mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-08-28 19:05:53 +00:00
chore(ui): fix advance search modal getting stuck (#10494)
* chore(ui): fix advance search modal getting stuck * update URL and make request to get data * remove unwanted code * listen location search change and update data
This commit is contained in:
parent
b982d3fe2b
commit
baab56a4be
@ -1,74 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2022 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 React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
||||||
import {
|
|
||||||
Builder,
|
|
||||||
Config,
|
|
||||||
Query,
|
|
||||||
Utils as QbUtils,
|
|
||||||
} from 'react-awesome-query-builder';
|
|
||||||
import {
|
|
||||||
emptyJsonTree,
|
|
||||||
getQbConfigs,
|
|
||||||
} from '../../constants/AdvancedSearch.constants';
|
|
||||||
import { elasticSearchFormat } from '../../utils/QueryBuilderElasticsearchFormatUtils';
|
|
||||||
import { AdvancedSearchProps } from './AdvancedSearch.interface';
|
|
||||||
|
|
||||||
const AdvancedSearch: React.FC<AdvancedSearchProps> = ({
|
|
||||||
jsonTree = emptyJsonTree,
|
|
||||||
onChangeJsonTree,
|
|
||||||
onChangeQueryFilter,
|
|
||||||
searchIndex,
|
|
||||||
}) => {
|
|
||||||
const [config, setConfig] = useState<Config>(getQbConfigs(searchIndex));
|
|
||||||
|
|
||||||
const immutableTree = useMemo(
|
|
||||||
() => QbUtils.checkTree(QbUtils.loadTree(jsonTree), config),
|
|
||||||
[jsonTree]
|
|
||||||
);
|
|
||||||
|
|
||||||
useEffect(() => setConfig(getQbConfigs(searchIndex)), [searchIndex]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
onChangeQueryFilter(
|
|
||||||
{
|
|
||||||
query: elasticSearchFormat(immutableTree, config),
|
|
||||||
},
|
|
||||||
QbUtils.sqlFormat(immutableTree, config) ?? ''
|
|
||||||
);
|
|
||||||
}, [immutableTree, config]);
|
|
||||||
|
|
||||||
const handleChange = useCallback(
|
|
||||||
(nTree, nConfig) => {
|
|
||||||
setConfig(nConfig);
|
|
||||||
onChangeJsonTree(QbUtils.getTree(nTree));
|
|
||||||
},
|
|
||||||
[setConfig, onChangeJsonTree]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Query
|
|
||||||
{...config}
|
|
||||||
renderBuilder={(props) => (
|
|
||||||
<div className="query-builder-container query-builder qb-lite">
|
|
||||||
<Builder {...props} />
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
value={immutableTree}
|
|
||||||
onChange={handleChange}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default AdvancedSearch;
|
|
@ -12,102 +12,24 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Button, Modal, Space, Typography } from 'antd';
|
import { Button, Modal, Space, Typography } from 'antd';
|
||||||
import { debounce, delay, isString } from 'lodash';
|
import React, { FunctionComponent } from 'react';
|
||||||
import Qs from 'qs';
|
import { Builder, Query } from 'react-awesome-query-builder';
|
||||||
import React, {
|
|
||||||
FunctionComponent,
|
|
||||||
useCallback,
|
|
||||||
useMemo,
|
|
||||||
useState,
|
|
||||||
} from 'react';
|
|
||||||
import { JsonTree, Utils } from 'react-awesome-query-builder';
|
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useHistory, useLocation } from 'react-router-dom';
|
import { useAdvanceSearch } from './AdvanceSearchProvider/AdvanceSearchProvider.component';
|
||||||
import { SearchIndex } from '../../enums/search.enum';
|
|
||||||
import AdvancedSearch from '../AdvancedSearch/AdvancedSearch.component';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
onSubmit: (
|
onSubmit: () => void;
|
||||||
filter: Record<string, unknown> | undefined,
|
|
||||||
sqlFilter: string
|
|
||||||
) => void;
|
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
searchIndex: SearchIndex;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const AdvancedSearchModal: FunctionComponent<Props> = ({
|
export const AdvancedSearchModal: FunctionComponent<Props> = ({
|
||||||
visible,
|
visible,
|
||||||
onSubmit,
|
onSubmit,
|
||||||
onCancel,
|
onCancel,
|
||||||
searchIndex,
|
|
||||||
}: Props) => {
|
}: Props) => {
|
||||||
const [queryFilter, setQueryFilter] = useState<
|
|
||||||
Record<string, unknown> | undefined
|
|
||||||
>();
|
|
||||||
const [sqlFilter, setSQLFilter] = useState<string>('');
|
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const history = useHistory();
|
const { config, treeInternal, onTreeUpdate, onReset } = useAdvanceSearch();
|
||||||
const location = useLocation();
|
|
||||||
|
|
||||||
const parsedSearch = useMemo(
|
|
||||||
() =>
|
|
||||||
Qs.parse(
|
|
||||||
location.search.startsWith('?')
|
|
||||||
? location.search.substr(1)
|
|
||||||
: location.search
|
|
||||||
),
|
|
||||||
[location.search]
|
|
||||||
);
|
|
||||||
|
|
||||||
const jsonTree = useMemo(() => {
|
|
||||||
if (!isString(parsedSearch.queryFilter)) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const queryFilter = JSON.parse(parsedSearch.queryFilter);
|
|
||||||
const immutableTree = Utils.loadTree(queryFilter as JsonTree);
|
|
||||||
if (Utils.isValidTree(immutableTree)) {
|
|
||||||
return queryFilter as JsonTree;
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
}, [location.search]);
|
|
||||||
|
|
||||||
const [treeInternal, setTreeInternal] = useState<JsonTree | undefined>(
|
|
||||||
jsonTree
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleTreeUpdate = useCallback(
|
|
||||||
(tree?: JsonTree) => {
|
|
||||||
history.push({
|
|
||||||
pathname: history.location.pathname,
|
|
||||||
search: Qs.stringify({
|
|
||||||
...parsedSearch,
|
|
||||||
queryFilter: tree ? JSON.stringify(tree) : undefined,
|
|
||||||
page: 1,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
setTreeInternal(undefined);
|
|
||||||
},
|
|
||||||
[history, parsedSearch]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleAdvanceSearchReset = () => {
|
|
||||||
delay(handleTreeUpdate, 100);
|
|
||||||
};
|
|
||||||
const handleQueryFilterUpdate = useCallback(
|
|
||||||
(queryFilter: Record<string, unknown> | undefined, sqlFilter: string) => {
|
|
||||||
setQueryFilter(queryFilter);
|
|
||||||
setSQLFilter(sqlFilter);
|
|
||||||
},
|
|
||||||
[setQueryFilter, setSQLFilter]
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
@ -116,21 +38,12 @@ export const AdvancedSearchModal: FunctionComponent<Props> = ({
|
|||||||
closeIcon={null}
|
closeIcon={null}
|
||||||
footer={
|
footer={
|
||||||
<Space className="justify-between w-full">
|
<Space className="justify-between w-full">
|
||||||
<Button
|
<Button className="float-right" size="small" onClick={onReset}>
|
||||||
className="float-right"
|
|
||||||
size="small"
|
|
||||||
onClick={handleAdvanceSearchReset}>
|
|
||||||
{t('label.reset')}
|
{t('label.reset')}
|
||||||
</Button>
|
</Button>
|
||||||
<div>
|
<div>
|
||||||
<Button onClick={onCancel}>{t('label.cancel')}</Button>
|
<Button onClick={onCancel}>{t('label.cancel')}</Button>
|
||||||
<Button
|
<Button type="primary" onClick={onSubmit}>
|
||||||
type="primary"
|
|
||||||
onClick={() => {
|
|
||||||
handleTreeUpdate(treeInternal);
|
|
||||||
onSubmit(queryFilter, sqlFilter);
|
|
||||||
onCancel();
|
|
||||||
}}>
|
|
||||||
{t('label.apply')}
|
{t('label.apply')}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
@ -146,11 +59,15 @@ export const AdvancedSearchModal: FunctionComponent<Props> = ({
|
|||||||
<Typography.Text data-testid="advanced-search-message">
|
<Typography.Text data-testid="advanced-search-message">
|
||||||
{t('message.advanced-search-message')}
|
{t('message.advanced-search-message')}
|
||||||
</Typography.Text>
|
</Typography.Text>
|
||||||
<AdvancedSearch
|
<Query
|
||||||
jsonTree={treeInternal}
|
{...config}
|
||||||
searchIndex={searchIndex}
|
renderBuilder={(props) => (
|
||||||
onChangeJsonTree={debounce(setTreeInternal, 1)}
|
<div className="query-builder-container query-builder qb-lite">
|
||||||
onChangeQueryFilter={handleQueryFilterUpdate}
|
<Builder {...props} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
value={treeInternal}
|
||||||
|
onChange={onTreeUpdate}
|
||||||
/>
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
@ -0,0 +1,196 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 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 Loader from 'components/Loader/Loader';
|
||||||
|
import {
|
||||||
|
emptyJsonTree,
|
||||||
|
getQbConfigs,
|
||||||
|
} from 'constants/AdvancedSearch.constants';
|
||||||
|
import { tabsInfo } from 'constants/explore.constants';
|
||||||
|
import { SearchIndex } from 'enums/search.enum';
|
||||||
|
import { isNil, isString } from 'lodash';
|
||||||
|
import Qs from 'qs';
|
||||||
|
import React, {
|
||||||
|
useCallback,
|
||||||
|
useContext,
|
||||||
|
useEffect,
|
||||||
|
useMemo,
|
||||||
|
useState,
|
||||||
|
} from 'react';
|
||||||
|
import {
|
||||||
|
Config,
|
||||||
|
ImmutableTree,
|
||||||
|
JsonTree,
|
||||||
|
Utils as QbUtils,
|
||||||
|
} from 'react-awesome-query-builder';
|
||||||
|
import { useHistory, useLocation, useParams } from 'react-router-dom';
|
||||||
|
import { elasticSearchFormat } from '../../../utils/QueryBuilderElasticsearchFormatUtils';
|
||||||
|
import { AdvancedSearchModal } from '../AdvanceSearchModal.component';
|
||||||
|
import { ExploreSearchIndex, UrlParams } from '../explore.interface';
|
||||||
|
import {
|
||||||
|
AdvanceSearchContext,
|
||||||
|
AdvanceSearchProviderProps,
|
||||||
|
} from './AdvanceSearchProvider.interface';
|
||||||
|
|
||||||
|
const AdvancedSearchContext = React.createContext<AdvanceSearchContext>(
|
||||||
|
{} as AdvanceSearchContext
|
||||||
|
);
|
||||||
|
|
||||||
|
export const AdvanceSearchProvider = ({
|
||||||
|
children,
|
||||||
|
}: AdvanceSearchProviderProps) => {
|
||||||
|
const location = useLocation();
|
||||||
|
const history = useHistory();
|
||||||
|
const { tab } = useParams<UrlParams>();
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const searchIndex = useMemo(() => {
|
||||||
|
const tabInfo = Object.entries(tabsInfo).find(
|
||||||
|
([, tabInfo]) => tabInfo.path === tab
|
||||||
|
);
|
||||||
|
if (isNil(tabInfo)) {
|
||||||
|
return SearchIndex.TABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tabInfo[0] as ExploreSearchIndex;
|
||||||
|
}, [tab]);
|
||||||
|
const [config, setConfig] = useState<Config>(getQbConfigs(searchIndex));
|
||||||
|
|
||||||
|
const defaultTree = useMemo(
|
||||||
|
() => QbUtils.checkTree(QbUtils.loadTree(emptyJsonTree), config),
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
|
const parsedSearch = useMemo(
|
||||||
|
() =>
|
||||||
|
Qs.parse(
|
||||||
|
location.search.startsWith('?')
|
||||||
|
? location.search.substr(1)
|
||||||
|
: location.search
|
||||||
|
),
|
||||||
|
[location.search]
|
||||||
|
);
|
||||||
|
|
||||||
|
const jsonTree = useMemo(() => {
|
||||||
|
if (!isString(parsedSearch.queryFilter)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const filter = JSON.parse(parsedSearch.queryFilter);
|
||||||
|
const immutableTree = QbUtils.loadTree(filter as JsonTree);
|
||||||
|
if (QbUtils.isValidTree(immutableTree)) {
|
||||||
|
return filter as JsonTree;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}, [parsedSearch]);
|
||||||
|
|
||||||
|
const [showModal, setShowModal] = useState(false);
|
||||||
|
const [treeInternal, setTreeInternal] = useState<ImmutableTree>(() =>
|
||||||
|
jsonTree
|
||||||
|
? QbUtils.checkTree(QbUtils.loadTree(jsonTree), config)
|
||||||
|
: defaultTree
|
||||||
|
);
|
||||||
|
const [queryFilter, setQueryFilter] = useState<
|
||||||
|
Record<string, unknown> | undefined
|
||||||
|
>();
|
||||||
|
const [sqlQuery, setSQLQuery] = useState(
|
||||||
|
treeInternal ? QbUtils.sqlFormat(treeInternal, config) ?? '' : ''
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => setConfig(getQbConfigs(searchIndex)), [searchIndex]);
|
||||||
|
|
||||||
|
const handleChange = useCallback(
|
||||||
|
(nTree, nConfig) => {
|
||||||
|
setConfig(nConfig);
|
||||||
|
setTreeInternal(nTree);
|
||||||
|
},
|
||||||
|
[setConfig, setTreeInternal]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleTreeUpdate = useCallback(
|
||||||
|
(tree?: ImmutableTree) => {
|
||||||
|
history.push({
|
||||||
|
pathname: location.pathname,
|
||||||
|
search: Qs.stringify({
|
||||||
|
...parsedSearch,
|
||||||
|
queryFilter: tree ? JSON.stringify(tree) : undefined,
|
||||||
|
page: 1,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[history, parsedSearch, location.pathname]
|
||||||
|
);
|
||||||
|
|
||||||
|
const toggleModal = (show: boolean) => {
|
||||||
|
setShowModal(show);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleReset = useCallback(() => {
|
||||||
|
setTreeInternal(QbUtils.checkTree(QbUtils.loadTree(emptyJsonTree), config));
|
||||||
|
setQueryFilter(undefined);
|
||||||
|
setSQLQuery('');
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (jsonTree) {
|
||||||
|
const tree = QbUtils.checkTree(QbUtils.loadTree(jsonTree), config);
|
||||||
|
setTreeInternal(tree);
|
||||||
|
const qFilter = {
|
||||||
|
query: elasticSearchFormat(tree, config),
|
||||||
|
};
|
||||||
|
setQueryFilter(qFilter);
|
||||||
|
setSQLQuery(QbUtils.sqlFormat(tree, config) ?? '');
|
||||||
|
} else {
|
||||||
|
handleReset();
|
||||||
|
}
|
||||||
|
|
||||||
|
setLoading(false);
|
||||||
|
}, [jsonTree]);
|
||||||
|
|
||||||
|
const handleSubmit = useCallback(() => {
|
||||||
|
const qFilter = {
|
||||||
|
query: elasticSearchFormat(treeInternal, config),
|
||||||
|
};
|
||||||
|
setQueryFilter(qFilter);
|
||||||
|
setSQLQuery(
|
||||||
|
treeInternal ? QbUtils.sqlFormat(treeInternal, config) ?? '' : ''
|
||||||
|
);
|
||||||
|
handleTreeUpdate(treeInternal);
|
||||||
|
setShowModal(false);
|
||||||
|
}, [treeInternal, config, handleTreeUpdate]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AdvancedSearchContext.Provider
|
||||||
|
value={{
|
||||||
|
queryFilter,
|
||||||
|
sqlQuery,
|
||||||
|
onTreeUpdate: handleChange,
|
||||||
|
toggleModal,
|
||||||
|
treeInternal,
|
||||||
|
config,
|
||||||
|
onReset: handleReset,
|
||||||
|
}}>
|
||||||
|
{loading ? <Loader /> : children}
|
||||||
|
<AdvancedSearchModal
|
||||||
|
visible={showModal}
|
||||||
|
onCancel={() => setShowModal(false)}
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
/>
|
||||||
|
</AdvancedSearchContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const useAdvanceSearch = () => useContext(AdvancedSearchContext);
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2022 Collate.
|
* Copyright 2023 Collate.
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
@ -10,18 +10,21 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
import { ReactNode } from 'react';
|
||||||
|
import { Config, ImmutableTree } from 'react-awesome-query-builder';
|
||||||
|
|
||||||
import { JsonTree } from 'react-awesome-query-builder';
|
export interface AdvanceSearchProviderProps {
|
||||||
import { SearchIndex } from '../../enums/search.enum';
|
children: ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
export interface AdvancedSearchProps {
|
export interface AdvanceSearchContext {
|
||||||
jsonTree: JsonTree | undefined;
|
queryFilter?: Record<string, unknown>;
|
||||||
searchIndex: SearchIndex;
|
sqlQuery: string;
|
||||||
onChangeJsonTree: (tree: JsonTree) => void;
|
onTreeUpdate: (nTree: ImmutableTree, nConfig: Config) => void;
|
||||||
onChangeQueryFilter: (
|
toggleModal: (show: boolean) => void;
|
||||||
queryFilter: Record<string, unknown> | undefined,
|
treeInternal: ImmutableTree;
|
||||||
sqlFilter: string
|
config: Config;
|
||||||
) => void;
|
onReset: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type FilterObject = Record<string, string[]>;
|
export type FilterObject = Record<string, string[]>;
|
@ -42,7 +42,7 @@ import { FacetFilterProps } from '../common/facetfilter/facetFilter.interface';
|
|||||||
import PageLayoutV1 from '../containers/PageLayoutV1';
|
import PageLayoutV1 from '../containers/PageLayoutV1';
|
||||||
import Loader from '../Loader/Loader';
|
import Loader from '../Loader/Loader';
|
||||||
import ExploreSkeleton from '../Skeleton/Explore/ExploreLeftPanelSkeleton.component';
|
import ExploreSkeleton from '../Skeleton/Explore/ExploreLeftPanelSkeleton.component';
|
||||||
import { AdvancedSearchModal } from './AdvanceSearchModal.component';
|
import { useAdvanceSearch } from './AdvanceSearchProvider/AdvanceSearchProvider.component';
|
||||||
import AppliedFilterText from './AppliedFilterText/AppliedFilterText';
|
import AppliedFilterText from './AppliedFilterText/AppliedFilterText';
|
||||||
import EntitySummaryPanel from './EntitySummaryPanel/EntitySummaryPanel.component';
|
import EntitySummaryPanel from './EntitySummaryPanel/EntitySummaryPanel.component';
|
||||||
import {
|
import {
|
||||||
@ -77,7 +77,6 @@ const Explore: React.FC<ExploreProps> = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const { tab } = useParams<{ tab: string }>();
|
const { tab } = useParams<{ tab: string }>();
|
||||||
const [showAdvanceSearchModal, setShowAdvanceSearchModal] = useState(false);
|
|
||||||
|
|
||||||
const [selectedQuickFilters, setSelectedQuickFilters] = useState<
|
const [selectedQuickFilters, setSelectedQuickFilters] = useState<
|
||||||
ExploreQuickFilterField[]
|
ExploreQuickFilterField[]
|
||||||
@ -86,8 +85,7 @@ const Explore: React.FC<ExploreProps> = ({
|
|||||||
const [entityDetails, setEntityDetails] =
|
const [entityDetails, setEntityDetails] =
|
||||||
useState<{ details: EntityDetailsType; entityType: string }>();
|
useState<{ details: EntityDetailsType; entityType: string }>();
|
||||||
|
|
||||||
const [appliedFilterSQLFormat, setAppliedFilterSQLFormat] =
|
const { toggleModal, sqlQuery } = useAdvanceSearch();
|
||||||
useState<string>('');
|
|
||||||
|
|
||||||
const handleClosePanel = () => {
|
const handleClosePanel = () => {
|
||||||
setShowSummaryPanel(false);
|
setShowSummaryPanel(false);
|
||||||
@ -242,11 +240,6 @@ const Explore: React.FC<ExploreProps> = ({
|
|||||||
}
|
}
|
||||||
}, [tab, searchResults]);
|
}, [tab, searchResults]);
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
// reset Applied Filter SQL Format on tab change
|
|
||||||
setAppliedFilterSQLFormat('');
|
|
||||||
}, [tab]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageLayoutV1
|
<PageLayoutV1
|
||||||
className="explore-page-container"
|
className="explore-page-container"
|
||||||
@ -308,15 +301,15 @@ const Explore: React.FC<ExploreProps> = ({
|
|||||||
<ExploreQuickFilters
|
<ExploreQuickFilters
|
||||||
fields={selectedQuickFilters}
|
fields={selectedQuickFilters}
|
||||||
index={searchIndex}
|
index={searchIndex}
|
||||||
onAdvanceSearch={() => setShowAdvanceSearchModal(true)}
|
onAdvanceSearch={() => toggleModal(true)}
|
||||||
onFieldValueSelect={handleAdvanceFieldValueSelect}
|
onFieldValueSelect={handleAdvanceFieldValueSelect}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
{appliedFilterSQLFormat && (
|
{sqlQuery && (
|
||||||
<Col span={24}>
|
<Col span={24}>
|
||||||
<AppliedFilterText
|
<AppliedFilterText
|
||||||
filterText={appliedFilterSQLFormat}
|
filterText={sqlQuery}
|
||||||
onEdit={() => setShowAdvanceSearchModal(true)}
|
onEdit={() => toggleModal(true)}
|
||||||
/>
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
)}
|
)}
|
||||||
@ -357,15 +350,6 @@ const Explore: React.FC<ExploreProps> = ({
|
|||||||
</Col>
|
</Col>
|
||||||
)}
|
)}
|
||||||
</Row>
|
</Row>
|
||||||
<AdvancedSearchModal
|
|
||||||
searchIndex={searchIndex}
|
|
||||||
visible={showAdvanceSearchModal}
|
|
||||||
onCancel={() => setShowAdvanceSearchModal(false)}
|
|
||||||
onSubmit={(query, sqlFilter) => {
|
|
||||||
onChangeAdvancedSearchQueryFilter(query);
|
|
||||||
setAppliedFilterSQLFormat(sqlFilter);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</PageLayoutV1>
|
</PageLayoutV1>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -20,8 +20,8 @@ import { Pipeline } from '../../generated/entity/data/pipeline';
|
|||||||
import { Table } from '../../generated/entity/data/table';
|
import { Table } from '../../generated/entity/data/table';
|
||||||
import { Topic } from '../../generated/entity/data/topic';
|
import { Topic } from '../../generated/entity/data/topic';
|
||||||
import { SearchResponse } from '../../interface/search.interface';
|
import { SearchResponse } from '../../interface/search.interface';
|
||||||
import { FilterObject } from '../AdvancedSearch/AdvancedSearch.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;
|
||||||
|
@ -11,8 +11,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { FilterObject } from 'components/Explore/AdvanceSearchProvider/AdvanceSearchProvider.interface';
|
||||||
import { Aggregations } from '../../../interface/search.interface';
|
import { Aggregations } from '../../../interface/search.interface';
|
||||||
import { FilterObject } from '../../AdvancedSearch/AdvancedSearch.interface';
|
|
||||||
|
|
||||||
export interface FacetFilterProps {
|
export interface FacetFilterProps {
|
||||||
aggregations?: Aggregations;
|
aggregations?: Aggregations;
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 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 { AdvanceSearchProvider } from 'components/Explore/AdvanceSearchProvider/AdvanceSearchProvider.component';
|
||||||
|
import React, { FC } from 'react';
|
||||||
|
|
||||||
|
export const withAdvanceSearch = (Component: FC) => (props: any) => {
|
||||||
|
return (
|
||||||
|
<AdvanceSearchProvider>
|
||||||
|
<Component {...props} />
|
||||||
|
</AdvanceSearchProvider>
|
||||||
|
);
|
||||||
|
};
|
@ -12,6 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import PageContainerV1 from 'components/containers/PageContainerV1';
|
import PageContainerV1 from 'components/containers/PageContainerV1';
|
||||||
|
import { useAdvanceSearch } from 'components/Explore/AdvanceSearchProvider/AdvanceSearchProvider.component';
|
||||||
import Explore from 'components/Explore/Explore.component';
|
import Explore from 'components/Explore/Explore.component';
|
||||||
import {
|
import {
|
||||||
ExploreProps,
|
ExploreProps,
|
||||||
@ -19,6 +20,7 @@ import {
|
|||||||
SearchHitCounts,
|
SearchHitCounts,
|
||||||
UrlParams,
|
UrlParams,
|
||||||
} from 'components/Explore/explore.interface';
|
} from 'components/Explore/explore.interface';
|
||||||
|
import { withAdvanceSearch } from 'components/router/withAdvanceSearch';
|
||||||
import { SORT_ORDER } from 'enums/common.enum';
|
import { SORT_ORDER } from 'enums/common.enum';
|
||||||
import { isNil, isString } from 'lodash';
|
import { isNil, isString } from 'lodash';
|
||||||
import Qs from 'qs';
|
import Qs from 'qs';
|
||||||
@ -29,7 +31,6 @@ import React, {
|
|||||||
useMemo,
|
useMemo,
|
||||||
useState,
|
useState,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { JsonTree, Utils as QbUtils } from 'react-awesome-query-builder';
|
|
||||||
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 useDeepCompareEffect from 'use-deep-compare-effect';
|
||||||
@ -69,6 +70,8 @@ const ExplorePage: FunctionComponent = () => {
|
|||||||
|
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
|
||||||
|
const { queryFilter } = useAdvanceSearch();
|
||||||
|
|
||||||
const parsedSearch = useMemo(
|
const parsedSearch = useMemo(
|
||||||
() =>
|
() =>
|
||||||
Qs.parse(
|
Qs.parse(
|
||||||
@ -114,19 +117,6 @@ const ExplorePage: FunctionComponent = () => {
|
|||||||
setAdvancedSearchQueryFilter(undefined);
|
setAdvancedSearchQueryFilter(undefined);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleQueryFilterChange = useCallback(
|
|
||||||
(queryFilter) => {
|
|
||||||
history.push({
|
|
||||||
search: Qs.stringify({
|
|
||||||
...parsedSearch,
|
|
||||||
queryFilter: queryFilter ? JSON.stringify(queryFilter) : undefined,
|
|
||||||
page: 1,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
},
|
|
||||||
[history, parsedSearch]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handlePostFilterChange: ExploreProps['onChangePostFilter'] = (
|
const handlePostFilterChange: ExploreProps['onChangePostFilter'] = (
|
||||||
postFilter
|
postFilter
|
||||||
) => {
|
) => {
|
||||||
@ -143,28 +133,6 @@ const ExplorePage: FunctionComponent = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const queryFilter = useMemo(() => {
|
|
||||||
if (!isString(parsedSearch.queryFilter)) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
const queryFilter = JSON.parse(parsedSearch.queryFilter);
|
|
||||||
const immutableTree = QbUtils.loadTree(queryFilter as JsonTree);
|
|
||||||
if (QbUtils.isValidTree(immutableTree)) {
|
|
||||||
return queryFilter as JsonTree;
|
|
||||||
}
|
|
||||||
} catch {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return undefined;
|
|
||||||
}, [location.search]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
handleQueryFilterChange(queryFilter);
|
|
||||||
}, [queryFilter]);
|
|
||||||
|
|
||||||
const searchIndex = useMemo(() => {
|
const searchIndex = useMemo(() => {
|
||||||
const tabInfo = Object.entries(tabsInfo).find(
|
const tabInfo = Object.entries(tabsInfo).find(
|
||||||
([, tabInfo]) => tabInfo.path === tab
|
([, tabInfo]) => tabInfo.path === tab
|
||||||
@ -206,9 +174,10 @@ const ExplorePage: FunctionComponent = () => {
|
|||||||
// That is why I first did typecast it into QueryFilterInterface type to access the properties.
|
// That is why I first did typecast it into QueryFilterInterface type to access the properties.
|
||||||
getCombinedQueryFilterObject(
|
getCombinedQueryFilterObject(
|
||||||
elasticsearchQueryFilter as unknown as QueryFilterInterface,
|
elasticsearchQueryFilter as unknown as QueryFilterInterface,
|
||||||
advancesSearchQueryFilter as unknown as QueryFilterInterface
|
(advancesSearchQueryFilter as unknown as QueryFilterInterface) ??
|
||||||
|
queryFilter
|
||||||
),
|
),
|
||||||
[elasticsearchQueryFilter, advancesSearchQueryFilter]
|
[elasticsearchQueryFilter, advancesSearchQueryFilter, queryFilter]
|
||||||
);
|
);
|
||||||
|
|
||||||
useDeepCompareEffect(() => {
|
useDeepCompareEffect(() => {
|
||||||
@ -275,6 +244,7 @@ const ExplorePage: FunctionComponent = () => {
|
|||||||
showDeleted,
|
showDeleted,
|
||||||
advancesSearchQueryFilter,
|
advancesSearchQueryFilter,
|
||||||
elasticsearchQueryFilter,
|
elasticsearchQueryFilter,
|
||||||
|
queryFilter,
|
||||||
page,
|
page,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -320,4 +290,4 @@ const ExplorePage: FunctionComponent = () => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ExplorePage;
|
export default withAdvanceSearch(ExplorePage);
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { FilterObject } from 'components/AdvancedSearch/AdvancedSearch.interface';
|
import { FilterObject } from 'components/Explore/AdvanceSearchProvider/AdvanceSearchProvider.interface';
|
||||||
import { isArray, isNil, isObject, isString } from 'lodash';
|
import { isArray, isNil, isObject, isString } from 'lodash';
|
||||||
|
|
||||||
export function isFilterObject(obj: unknown): obj is FilterObject {
|
export function isFilterObject(obj: unknown): obj is FilterObject {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user