mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-09-27 09:55:36 +00:00
Data products explore tab (#13578)
* fix: add data products in explore tab * fix: add data products to explore * fix: update icon positioning * fix: make dataProducts as default tab on explore * fix: multiple api calls * fix: data product feedback * fix: filtering ui screen for data product * fix: sonar tests --------- Co-authored-by: Chirag Madlani <12962843+chirag-madlani@users.noreply.github.com>
This commit is contained in:
parent
c65518ac04
commit
10ef83779e
@ -0,0 +1,3 @@
|
|||||||
|
<svg viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path fill-rule="evenodd" clip-rule="evenodd" d="M2 4.66667C2 4.29848 2.29848 4 2.66667 4H13.3333C13.7015 4 14 4.29848 14 4.66667C14 5.03485 13.7015 5.33333 13.3333 5.33333H2.66667C2.29848 5.33333 2 5.03485 2 4.66667ZM4 8C4 7.6318 4.29848 7.33333 4.66667 7.33333H11.3333C11.7015 7.33333 12 7.6318 12 8C12 8.3682 11.7015 8.66667 11.3333 8.66667H4.66667C4.29848 8.66667 4 8.3682 4 8ZM6 11.3333C6 10.9651 6.29848 10.6667 6.66667 10.6667H9.33333C9.70153 10.6667 10 10.9651 10 11.3333C10 11.7015 9.70153 12 9.33333 12H6.66667C6.29848 12 6 11.7015 6 11.3333Z" fill="#292929"/>
|
||||||
|
</svg>
|
After Width: | Height: | Size: 651 B |
@ -240,6 +240,9 @@ const Appbar: React.FC = (): JSX.Element => {
|
|||||||
tab: defaultTab,
|
tab: defaultTab,
|
||||||
search: value,
|
search: value,
|
||||||
isPersistFilters: false,
|
isPersistFilters: false,
|
||||||
|
extraParameters: {
|
||||||
|
sort: '_score',
|
||||||
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,7 @@ export interface AssetSelectionModalProps {
|
|||||||
type?: AssetsOfEntity;
|
type?: AssetsOfEntity;
|
||||||
onCancel: () => void;
|
onCancel: () => void;
|
||||||
onSave?: () => void;
|
onSave?: () => void;
|
||||||
|
queryFilter?: Record<string, unknown>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AssetsUnion =
|
export type AssetsUnion =
|
||||||
|
@ -38,7 +38,6 @@ import {
|
|||||||
getAssetsSearchIndex,
|
getAssetsSearchIndex,
|
||||||
getEntityAPIfromSource,
|
getEntityAPIfromSource,
|
||||||
} from '../../../utils/Assets/AssetsUtils';
|
} from '../../../utils/Assets/AssetsUtils';
|
||||||
import { getQueryFilterToExcludeTerm } from '../../../utils/GlossaryUtils';
|
|
||||||
import Searchbar from '../../common/searchbar/Searchbar';
|
import Searchbar from '../../common/searchbar/Searchbar';
|
||||||
import TableDataCardV2 from '../../common/table-data-card-v2/TableDataCardV2';
|
import TableDataCardV2 from '../../common/table-data-card-v2/TableDataCardV2';
|
||||||
import { AssetsOfEntity } from '../../Glossary/GlossaryTerms/tabs/AssetsTabs.interface';
|
import { AssetsOfEntity } from '../../Glossary/GlossaryTerms/tabs/AssetsTabs.interface';
|
||||||
@ -53,6 +52,7 @@ export const AssetSelectionModal = ({
|
|||||||
onSave,
|
onSave,
|
||||||
open,
|
open,
|
||||||
type = AssetsOfEntity.GLOSSARY,
|
type = AssetsOfEntity.GLOSSARY,
|
||||||
|
queryFilter = {},
|
||||||
}: AssetSelectionModalProps) => {
|
}: AssetSelectionModalProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const [search, setSearch] = useState('');
|
const [search, setSearch] = useState('');
|
||||||
@ -67,14 +67,6 @@ export const AssetSelectionModal = ({
|
|||||||
const [pageNumber, setPageNumber] = useState(1);
|
const [pageNumber, setPageNumber] = useState(1);
|
||||||
const [totalCount, setTotalCount] = useState(0);
|
const [totalCount, setTotalCount] = useState(0);
|
||||||
|
|
||||||
const queryFilter = useMemo(() => {
|
|
||||||
if (type === AssetsOfEntity.GLOSSARY) {
|
|
||||||
return getQueryFilterToExcludeTerm(entityFqn);
|
|
||||||
} else {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
}, [entityFqn, type]);
|
|
||||||
|
|
||||||
const fetchEntities = useCallback(
|
const fetchEntities = useCallback(
|
||||||
async ({ searchText = '', page = 1, index = activeFilter }) => {
|
async ({ searchText = '', page = 1, index = activeFilter }) => {
|
||||||
try {
|
try {
|
||||||
@ -106,7 +98,7 @@ export const AssetSelectionModal = ({
|
|||||||
} else if (type === AssetsOfEntity.DATA_PRODUCT) {
|
} else if (type === AssetsOfEntity.DATA_PRODUCT) {
|
||||||
const data = await getDataProductByName(
|
const data = await getDataProductByName(
|
||||||
encodeURIComponent(entityFqn),
|
encodeURIComponent(entityFqn),
|
||||||
''
|
'domain'
|
||||||
);
|
);
|
||||||
setActiveEntity(data);
|
setActiveEntity(data);
|
||||||
}
|
}
|
||||||
|
@ -44,10 +44,7 @@ import { EntityDetailsObjectInterface } from '../../../components/Explore/explor
|
|||||||
import AssetsTabs, {
|
import AssetsTabs, {
|
||||||
AssetsTabRef,
|
AssetsTabRef,
|
||||||
} from '../../../components/Glossary/GlossaryTerms/tabs/AssetsTabs.component';
|
} from '../../../components/Glossary/GlossaryTerms/tabs/AssetsTabs.component';
|
||||||
import {
|
import { AssetsOfEntity } from '../../../components/Glossary/GlossaryTerms/tabs/AssetsTabs.interface';
|
||||||
AssetsOfEntity,
|
|
||||||
AssetsViewType,
|
|
||||||
} from '../../../components/Glossary/GlossaryTerms/tabs/AssetsTabs.interface';
|
|
||||||
import EntityDeleteModal from '../../../components/Modals/EntityDeleteModal/EntityDeleteModal';
|
import EntityDeleteModal from '../../../components/Modals/EntityDeleteModal/EntityDeleteModal';
|
||||||
import EntityNameModal from '../../../components/Modals/EntityNameModal/EntityNameModal.component';
|
import EntityNameModal from '../../../components/Modals/EntityNameModal/EntityNameModal.component';
|
||||||
import { usePermissionProvider } from '../../../components/PermissionProvider/PermissionProvider';
|
import { usePermissionProvider } from '../../../components/PermissionProvider/PermissionProvider';
|
||||||
@ -56,7 +53,6 @@ import {
|
|||||||
ResourceEntity,
|
ResourceEntity,
|
||||||
} from '../../../components/PermissionProvider/PermissionProvider.interface';
|
} from '../../../components/PermissionProvider/PermissionProvider.interface';
|
||||||
import TabsLabel from '../../../components/TabsLabel/TabsLabel.component';
|
import TabsLabel from '../../../components/TabsLabel/TabsLabel.component';
|
||||||
import { FQN_SEPARATOR_CHAR } from '../../../constants/char.constants';
|
|
||||||
import { DE_ACTIVE_COLOR } from '../../../constants/constants';
|
import { DE_ACTIVE_COLOR } from '../../../constants/constants';
|
||||||
import { EntityField } from '../../../constants/Feeds.constants';
|
import { EntityField } from '../../../constants/Feeds.constants';
|
||||||
import { myDataSearchIndex } from '../../../constants/Mydata.constants';
|
import { myDataSearchIndex } from '../../../constants/Mydata.constants';
|
||||||
@ -70,8 +66,9 @@ import { Operation } from '../../../generated/entity/policies/policy';
|
|||||||
import { Style } from '../../../generated/type/tagLabel';
|
import { Style } from '../../../generated/type/tagLabel';
|
||||||
import { searchData } from '../../../rest/miscAPI';
|
import { searchData } from '../../../rest/miscAPI';
|
||||||
import { getEntityDeleteMessage } from '../../../utils/CommonUtils';
|
import { getEntityDeleteMessage } from '../../../utils/CommonUtils';
|
||||||
|
import { getQueryFilterToIncludeDomain } from '../../../utils/DomainUtils';
|
||||||
|
import { getEntityName } from '../../../utils/EntityUtils';
|
||||||
import { getEntityVersionByField } from '../../../utils/EntityVersionUtils';
|
import { getEntityVersionByField } from '../../../utils/EntityVersionUtils';
|
||||||
import Fqn from '../../../utils/Fqn.js';
|
|
||||||
import {
|
import {
|
||||||
checkPermission,
|
checkPermission,
|
||||||
DEFAULT_ENTITY_PERMISSION,
|
DEFAULT_ENTITY_PERMISSION,
|
||||||
@ -117,25 +114,18 @@ const DataProductsDetailsPage = ({
|
|||||||
const [assetCount, setAssetCount] = useState<number>(0);
|
const [assetCount, setAssetCount] = useState<number>(0);
|
||||||
|
|
||||||
const breadcrumbs = useMemo(() => {
|
const breadcrumbs = useMemo(() => {
|
||||||
if (!dataProductFqn) {
|
if (!dataProduct.domain) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const arr = Fqn.split(dataProductFqn);
|
|
||||||
const dataFQN: Array<string> = [];
|
|
||||||
|
|
||||||
return [
|
return [
|
||||||
...arr.slice(0, -1).map((d) => {
|
{
|
||||||
dataFQN.push(d);
|
name: getEntityName(dataProduct.domain),
|
||||||
|
url: getDomainPath(dataProduct.domain.fullyQualifiedName),
|
||||||
return {
|
|
||||||
name: d,
|
|
||||||
url: getDomainPath(dataFQN.join(FQN_SEPARATOR_CHAR)),
|
|
||||||
activeTitle: false,
|
activeTitle: false,
|
||||||
};
|
},
|
||||||
}),
|
|
||||||
];
|
];
|
||||||
}, [dataProductFqn]);
|
}, [dataProduct.domain]);
|
||||||
|
|
||||||
const [name, displayName] = useMemo(() => {
|
const [name, displayName] = useMemo(() => {
|
||||||
const defaultName = dataProduct.name;
|
const defaultName = dataProduct.name;
|
||||||
@ -425,7 +415,6 @@ const DataProductsDetailsPage = ({
|
|||||||
permissions={dataProductPermission}
|
permissions={dataProductPermission}
|
||||||
ref={assetTabRef}
|
ref={assetTabRef}
|
||||||
type={AssetsOfEntity.DATA_PRODUCT}
|
type={AssetsOfEntity.DATA_PRODUCT}
|
||||||
viewType={AssetsViewType.TABS}
|
|
||||||
onAddAsset={() => setAssetModelVisible(true)}
|
onAddAsset={() => setAssetModelVisible(true)}
|
||||||
onAssetClick={handleAssetClick}
|
onAssetClick={handleAssetClick}
|
||||||
/>
|
/>
|
||||||
@ -575,6 +564,9 @@ const DataProductsDetailsPage = ({
|
|||||||
<AssetSelectionModal
|
<AssetSelectionModal
|
||||||
entityFqn={dataProductFqn}
|
entityFqn={dataProductFqn}
|
||||||
open={assetModalVisible}
|
open={assetModalVisible}
|
||||||
|
queryFilter={getQueryFilterToIncludeDomain(
|
||||||
|
dataProduct.domain?.fullyQualifiedName ?? ''
|
||||||
|
)}
|
||||||
type={AssetsOfEntity.DATA_PRODUCT}
|
type={AssetsOfEntity.DATA_PRODUCT}
|
||||||
onCancel={() => setAssetModelVisible(false)}
|
onCancel={() => setAssetModelVisible(false)}
|
||||||
onSave={handleAssetSave}
|
onSave={handleAssetSave}
|
||||||
|
@ -40,6 +40,5 @@
|
|||||||
}
|
}
|
||||||
.summary-panel-container {
|
.summary-panel-container {
|
||||||
height: @domain-page-height;
|
height: @domain-page-height;
|
||||||
border-left: 1px solid @border-color;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,7 +101,7 @@ const DataProductsPage = () => {
|
|||||||
try {
|
try {
|
||||||
const data = await getDataProductByName(
|
const data = await getDataProductByName(
|
||||||
encodeURIComponent(fqn),
|
encodeURIComponent(fqn),
|
||||||
'owner,experts'
|
'domain,owner,experts'
|
||||||
);
|
);
|
||||||
setDataProduct(data);
|
setDataProduct(data);
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { isNil, isString } from 'lodash';
|
import { cloneDeep, isNil, isString } from 'lodash';
|
||||||
import Qs from 'qs';
|
import Qs from 'qs';
|
||||||
import React, {
|
import React, {
|
||||||
useCallback,
|
useCallback,
|
||||||
@ -22,9 +22,11 @@ import React, {
|
|||||||
} from 'react';
|
} from 'react';
|
||||||
import {
|
import {
|
||||||
Config,
|
Config,
|
||||||
|
FieldGroup,
|
||||||
ImmutableTree,
|
ImmutableTree,
|
||||||
JsonTree,
|
JsonTree,
|
||||||
Utils as QbUtils,
|
Utils as QbUtils,
|
||||||
|
ValueSource,
|
||||||
} from 'react-awesome-query-builder';
|
} from 'react-awesome-query-builder';
|
||||||
import { useHistory, useLocation, useParams } from 'react-router-dom';
|
import { useHistory, useLocation, useParams } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
@ -33,7 +35,9 @@ import {
|
|||||||
} from '../../../constants/AdvancedSearch.constants';
|
} from '../../../constants/AdvancedSearch.constants';
|
||||||
import { tabsInfo } from '../../../constants/explore.constants';
|
import { tabsInfo } from '../../../constants/explore.constants';
|
||||||
import { SearchIndex } from '../../../enums/search.enum';
|
import { SearchIndex } from '../../../enums/search.enum';
|
||||||
|
import { getTypeByFQN } from '../../../rest/metadataTypeAPI';
|
||||||
import { elasticSearchFormat } from '../../../utils/QueryBuilderElasticsearchFormatUtils';
|
import { elasticSearchFormat } from '../../../utils/QueryBuilderElasticsearchFormatUtils';
|
||||||
|
import { getEntityTypeFromSearchIndex } from '../../../utils/SearchUtils';
|
||||||
import Loader from '../../Loader/Loader';
|
import Loader from '../../Loader/Loader';
|
||||||
import { AdvancedSearchModal } from '../AdvanceSearchModal.component';
|
import { AdvancedSearchModal } from '../AdvanceSearchModal.component';
|
||||||
import { ExploreSearchIndex, UrlParams } from '../explore.interface';
|
import { ExploreSearchIndex, UrlParams } from '../explore.interface';
|
||||||
@ -165,15 +169,55 @@ export const AdvanceSearchProvider = ({
|
|||||||
});
|
});
|
||||||
}, [history, location.pathname]);
|
}, [history, location.pathname]);
|
||||||
|
|
||||||
useEffect(() => {
|
async function getCustomAttributesSubfields() {
|
||||||
if (jsonTree) {
|
const updatedConfig = cloneDeep(config);
|
||||||
const tree = QbUtils.checkTree(QbUtils.loadTree(jsonTree), config);
|
try {
|
||||||
|
const entityType = getEntityTypeFromSearchIndex(searchIndex);
|
||||||
|
if (!entityType) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const res = await getTypeByFQN(entityType);
|
||||||
|
const customAttributes = res.customProperties;
|
||||||
|
|
||||||
|
const subfields: Record<
|
||||||
|
string,
|
||||||
|
{ type: string; valueSources: ValueSource[] }
|
||||||
|
> = {};
|
||||||
|
|
||||||
|
if (customAttributes) {
|
||||||
|
customAttributes.forEach((attr) => {
|
||||||
|
subfields[attr.name] = {
|
||||||
|
type: 'text',
|
||||||
|
valueSources: ['value'],
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
(updatedConfig.fields.extension as FieldGroup).subfields = subfields;
|
||||||
|
|
||||||
|
return updatedConfig;
|
||||||
|
} catch (error) {
|
||||||
|
// Error
|
||||||
|
return updatedConfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const loadTree = useCallback(
|
||||||
|
async (treeObj: JsonTree) => {
|
||||||
|
const updatedConfig = (await getCustomAttributesSubfields()) ?? config;
|
||||||
|
const tree = QbUtils.checkTree(QbUtils.loadTree(treeObj), updatedConfig);
|
||||||
setTreeInternal(tree);
|
setTreeInternal(tree);
|
||||||
const qFilter = {
|
const qFilter = {
|
||||||
query: elasticSearchFormat(tree, config),
|
query: elasticSearchFormat(tree, updatedConfig),
|
||||||
};
|
};
|
||||||
setQueryFilter(qFilter);
|
setQueryFilter(qFilter);
|
||||||
setSQLQuery(QbUtils.sqlFormat(tree, config) ?? '');
|
setSQLQuery(QbUtils.sqlFormat(tree, updatedConfig) ?? '');
|
||||||
|
},
|
||||||
|
[config]
|
||||||
|
);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (jsonTree) {
|
||||||
|
loadTree(jsonTree);
|
||||||
} else {
|
} else {
|
||||||
handleReset();
|
handleReset();
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ import { useTranslation } from 'react-i18next';
|
|||||||
import { DataProduct } from '../../../../generated/entity/domains/dataProduct';
|
import { DataProduct } from '../../../../generated/entity/domains/dataProduct';
|
||||||
import { getEntityName } from '../../../../utils/EntityUtils';
|
import { getEntityName } from '../../../../utils/EntityUtils';
|
||||||
import { OwnerLabel } from '../../../common/OwnerLabel/OwnerLabel.component';
|
import { OwnerLabel } from '../../../common/OwnerLabel/OwnerLabel.component';
|
||||||
|
import RichTextEditorPreviewer from '../../../common/rich-text-editor/RichTextEditorPreviewer';
|
||||||
import SummaryPanelSkeleton from '../../../Skeleton/SummaryPanelSkeleton/SummaryPanelSkeleton.component';
|
import SummaryPanelSkeleton from '../../../Skeleton/SummaryPanelSkeleton/SummaryPanelSkeleton.component';
|
||||||
|
|
||||||
interface DataProductSummaryProps {
|
interface DataProductSummaryProps {
|
||||||
@ -50,6 +51,32 @@ const DataProductSummary = ({
|
|||||||
</Row>
|
</Row>
|
||||||
<Divider className="m-y-xs" />
|
<Divider className="m-y-xs" />
|
||||||
|
|
||||||
|
<Row className="m-md" gutter={[0, 8]}>
|
||||||
|
<Col span={24}>
|
||||||
|
<Typography.Text
|
||||||
|
className="summary-panel-section-title"
|
||||||
|
data-testid="description-header">
|
||||||
|
{t('label.description')}
|
||||||
|
</Typography.Text>
|
||||||
|
</Col>
|
||||||
|
<Col span={24}>
|
||||||
|
<div>
|
||||||
|
{entityDetails.description?.trim() ? (
|
||||||
|
<RichTextEditorPreviewer
|
||||||
|
markdown={entityDetails.description}
|
||||||
|
maxLength={80}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Typography className="text-grey-body">
|
||||||
|
{t('label.no-data-found')}
|
||||||
|
</Typography>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
|
||||||
|
<Divider className="m-y-xs" />
|
||||||
|
|
||||||
<Row className="m-md m-t-0" gutter={[0, 8]}>
|
<Row className="m-md m-t-0" gutter={[0, 8]}>
|
||||||
<Col span={24}>
|
<Col span={24}>
|
||||||
<Typography.Text
|
<Typography.Text
|
||||||
|
@ -268,6 +268,11 @@ export const MOCK_EXPLORE_SEARCH_RESULTS: SearchResponse<ExploreSearchIndex> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const MOCK_EXPLORE_TAB_ITEMS = [
|
export const MOCK_EXPLORE_TAB_ITEMS = [
|
||||||
|
{
|
||||||
|
key: 'data_product_search_index',
|
||||||
|
label: 'data_product_search_index',
|
||||||
|
count: 0,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'table_search_index',
|
key: 'table_search_index',
|
||||||
label: 'table_search_index',
|
label: 'table_search_index',
|
||||||
|
@ -46,6 +46,7 @@ export type UrlParams = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export type ExploreSearchIndex =
|
export type ExploreSearchIndex =
|
||||||
|
| SearchIndex.DATA_PRODUCT
|
||||||
| SearchIndex.TABLE
|
| SearchIndex.TABLE
|
||||||
| SearchIndex.PIPELINE
|
| SearchIndex.PIPELINE
|
||||||
| SearchIndex.DASHBOARD
|
| SearchIndex.DASHBOARD
|
||||||
|
@ -101,7 +101,8 @@ const ExploreSearchCard: React.FC<ExploreSearchCardProps> = forwardRef<
|
|||||||
|
|
||||||
if (
|
if (
|
||||||
source.entityType !== EntityType.GLOSSARY_TERM &&
|
source.entityType !== EntityType.GLOSSARY_TERM &&
|
||||||
source.entityType !== EntityType.TAG
|
source.entityType !== EntityType.TAG &&
|
||||||
|
source.entityType !== EntityType.DATA_PRODUCT
|
||||||
) {
|
) {
|
||||||
_otherDetails.push({
|
_otherDetails.push({
|
||||||
key: 'Tier',
|
key: 'Tier',
|
||||||
|
@ -76,7 +76,6 @@ const ExploreV1: React.FC<ExploreProps> = ({
|
|||||||
quickFilters,
|
quickFilters,
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
// const { tab } = useParams<{ tab: string }>();
|
|
||||||
const [selectedQuickFilters, setSelectedQuickFilters] = useState<
|
const [selectedQuickFilters, setSelectedQuickFilters] = useState<
|
||||||
ExploreQuickFilterField[]
|
ExploreQuickFilterField[]
|
||||||
>([] as ExploreQuickFilterField[]);
|
>([] as ExploreQuickFilterField[]);
|
||||||
|
@ -67,6 +67,7 @@ const props = {
|
|||||||
tabItems: MOCK_EXPLORE_TAB_ITEMS,
|
tabItems: MOCK_EXPLORE_TAB_ITEMS,
|
||||||
activeTabKey: SearchIndex.TABLE,
|
activeTabKey: SearchIndex.TABLE,
|
||||||
tabCounts: {
|
tabCounts: {
|
||||||
|
data_product_search_index: 0,
|
||||||
table_search_index: 20,
|
table_search_index: 20,
|
||||||
topic_search_index: 10,
|
topic_search_index: 10,
|
||||||
dashboard_search_index: 14,
|
dashboard_search_index: 14,
|
||||||
|
@ -101,10 +101,15 @@ export const FeedEditor = forwardRef<editorRef, FeedEditorProp>(
|
|||||||
renderLoading: () => `${t('label.loading')}...`,
|
renderLoading: () => `${t('label.loading')}...`,
|
||||||
renderItem: (item: Record<string, any>) => {
|
renderItem: (item: Record<string, any>) => {
|
||||||
if (!item.type) {
|
if (!item.type) {
|
||||||
return `<div class="d-flex gap-2">
|
const userResult = `<div class="d-flex gap-2">
|
||||||
${item.avatarEle}
|
${item.avatarEle}
|
||||||
<span class="d-flex items-center truncate w-56">${item.name}</span>
|
<span class="d-flex items-center truncate w-56">${item.name}</span>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
|
const userWrapper = document.createElement('div');
|
||||||
|
userWrapper.innerHTML = userResult;
|
||||||
|
|
||||||
|
return userWrapper;
|
||||||
}
|
}
|
||||||
|
|
||||||
const breadcrumbsData = item.breadcrumbs
|
const breadcrumbsData = item.breadcrumbs
|
||||||
@ -127,7 +132,7 @@ export const FeedEditor = forwardRef<editorRef, FeedEditorProp>(
|
|||||||
? `<span class="text-grey-muted text-xs">${item.type}</span>`
|
? `<span class="text-grey-muted text-xs">${item.type}</span>`
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
return `<div class="d-flex items-center gap-2">
|
const result = `<div class="d-flex items-center gap-2">
|
||||||
<div class="flex-center mention-icon-image">${icon}</div>
|
<div class="flex-center mention-icon-image">${icon}</div>
|
||||||
<div>
|
<div>
|
||||||
${breadcrumbEle}
|
${breadcrumbEle}
|
||||||
@ -137,6 +142,11 @@ export const FeedEditor = forwardRef<editorRef, FeedEditorProp>(
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
|
const wrapper = document.createElement('div');
|
||||||
|
wrapper.innerHTML = result;
|
||||||
|
|
||||||
|
return wrapper;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
markdownOptions: {},
|
markdownOptions: {},
|
||||||
|
@ -25,6 +25,7 @@ import { ChangeDescription } from '../../../generated/entity/type';
|
|||||||
import { searchData } from '../../../rest/miscAPI';
|
import { searchData } from '../../../rest/miscAPI';
|
||||||
import { getCountBadge, getFeedCounts } from '../../../utils/CommonUtils';
|
import { getCountBadge, getFeedCounts } from '../../../utils/CommonUtils';
|
||||||
import { getEntityVersionByField } from '../../../utils/EntityVersionUtils';
|
import { getEntityVersionByField } from '../../../utils/EntityVersionUtils';
|
||||||
|
import { getQueryFilterToExcludeTerm } from '../../../utils/GlossaryUtils';
|
||||||
import { getGlossaryTermsVersionsPath } from '../../../utils/RouterUtils';
|
import { getGlossaryTermsVersionsPath } from '../../../utils/RouterUtils';
|
||||||
import { getEncodedFqn } from '../../../utils/StringsUtils';
|
import { getEncodedFqn } from '../../../utils/StringsUtils';
|
||||||
import { ActivityFeedTab } from '../../ActivityFeed/ActivityFeedTab/ActivityFeedTab.component';
|
import { ActivityFeedTab } from '../../ActivityFeed/ActivityFeedTab/ActivityFeedTab.component';
|
||||||
@ -321,6 +322,9 @@ const GlossaryTermsV1 = ({
|
|||||||
<AssetSelectionModal
|
<AssetSelectionModal
|
||||||
entityFqn={glossaryTerm.fullyQualifiedName}
|
entityFqn={glossaryTerm.fullyQualifiedName}
|
||||||
open={assetModalVisible}
|
open={assetModalVisible}
|
||||||
|
queryFilter={getQueryFilterToExcludeTerm(
|
||||||
|
glossaryTerm.fullyQualifiedName
|
||||||
|
)}
|
||||||
type={AssetsOfEntity.GLOSSARY}
|
type={AssetsOfEntity.GLOSSARY}
|
||||||
onCancel={() => setAssetModelVisible(false)}
|
onCancel={() => setAssetModelVisible(false)}
|
||||||
onSave={handleAssetSave}
|
onSave={handleAssetSave}
|
||||||
|
@ -12,8 +12,6 @@
|
|||||||
*/
|
*/
|
||||||
import { render, screen } from '@testing-library/react';
|
import { render, screen } from '@testing-library/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import AppState from '../../AppState';
|
|
||||||
import { User } from '../../generated/entity/teams/user';
|
|
||||||
import {
|
import {
|
||||||
getEntityPermissionByFqn,
|
getEntityPermissionByFqn,
|
||||||
getEntityPermissionById,
|
getEntityPermissionById,
|
||||||
@ -37,13 +35,25 @@ jest.mock('../../rest/permissionAPI', () => ({
|
|||||||
.mockImplementation(() => Promise.resolve({})),
|
.mockImplementation(() => Promise.resolve({})),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
jest.mock('react-router-dom', () => ({
|
||||||
|
useHistory: jest.fn().mockReturnValue({ push: jest.fn(), listen: jest.fn() }),
|
||||||
|
}));
|
||||||
|
|
||||||
|
let currentUser: { id: string; name: string } | null = {
|
||||||
|
id: '123',
|
||||||
|
name: 'Test User',
|
||||||
|
};
|
||||||
|
|
||||||
|
jest.mock('../authentication/auth-provider/AuthProvider', () => {
|
||||||
|
return {
|
||||||
|
useAuthContext: jest.fn().mockImplementation(() => ({
|
||||||
|
currentUser,
|
||||||
|
})),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
describe('PermissionProvider', () => {
|
describe('PermissionProvider', () => {
|
||||||
it('Should render children and call apis when current user is present', async () => {
|
it('Should render children and call apis when current user is present', async () => {
|
||||||
const currentUser = { id: '123', name: 'Test User' };
|
|
||||||
const getUserDetailsSpy = jest
|
|
||||||
.spyOn(AppState, 'getCurrentUserDetails')
|
|
||||||
.mockReturnValue(currentUser as User);
|
|
||||||
|
|
||||||
render(
|
render(
|
||||||
<PermissionProvider>
|
<PermissionProvider>
|
||||||
<div data-testid="children">Children</div>
|
<div data-testid="children">Children</div>
|
||||||
@ -57,15 +67,10 @@ describe('PermissionProvider', () => {
|
|||||||
expect(getResourcePermission).not.toHaveBeenCalled();
|
expect(getResourcePermission).not.toHaveBeenCalled();
|
||||||
|
|
||||||
expect(await screen.findByTestId('children')).toBeInTheDocument();
|
expect(await screen.findByTestId('children')).toBeInTheDocument();
|
||||||
|
|
||||||
getUserDetailsSpy.mockRestore();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should not call apis when current user is undefined', async () => {
|
it('Should not call apis when current user is undefined', async () => {
|
||||||
const getUserDetailsSpy = jest
|
currentUser = null;
|
||||||
.spyOn(AppState, 'getCurrentUserDetails')
|
|
||||||
.mockReturnValue(undefined);
|
|
||||||
|
|
||||||
render(
|
render(
|
||||||
<PermissionProvider>
|
<PermissionProvider>
|
||||||
<div data-testid="children">Children</div>
|
<div data-testid="children">Children</div>
|
||||||
@ -77,7 +82,5 @@ describe('PermissionProvider', () => {
|
|||||||
expect(getEntityPermissionById).not.toHaveBeenCalled();
|
expect(getEntityPermissionById).not.toHaveBeenCalled();
|
||||||
expect(getEntityPermissionByFqn).not.toHaveBeenCalled();
|
expect(getEntityPermissionByFqn).not.toHaveBeenCalled();
|
||||||
expect(getResourcePermission).not.toHaveBeenCalled();
|
expect(getResourcePermission).not.toHaveBeenCalled();
|
||||||
|
|
||||||
getUserDetailsSpy.mockRestore();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -24,7 +24,6 @@ import React, {
|
|||||||
useState,
|
useState,
|
||||||
} from 'react';
|
} from 'react';
|
||||||
import { useHistory } from 'react-router-dom';
|
import { useHistory } from 'react-router-dom';
|
||||||
import AppState from '../../AppState';
|
|
||||||
import Loader from '../../components/Loader/Loader';
|
import Loader from '../../components/Loader/Loader';
|
||||||
import { REDIRECT_PATHNAME } from '../../constants/constants';
|
import { REDIRECT_PATHNAME } from '../../constants/constants';
|
||||||
import {
|
import {
|
||||||
@ -41,6 +40,7 @@ import {
|
|||||||
getOperationPermissions,
|
getOperationPermissions,
|
||||||
getUIPermission,
|
getUIPermission,
|
||||||
} from '../../utils/PermissionsUtils';
|
} from '../../utils/PermissionsUtils';
|
||||||
|
import { useAuthContext } from '../authentication/auth-provider/AuthProvider';
|
||||||
import {
|
import {
|
||||||
EntityPermissionMap,
|
EntityPermissionMap,
|
||||||
PermissionContextType,
|
PermissionContextType,
|
||||||
@ -67,6 +67,7 @@ const PermissionProvider: FC<PermissionProviderProps> = ({ children }) => {
|
|||||||
const [permissions, setPermissions] = useState<UIPermission>(
|
const [permissions, setPermissions] = useState<UIPermission>(
|
||||||
{} as UIPermission
|
{} as UIPermission
|
||||||
);
|
);
|
||||||
|
const { currentUser } = useAuthContext();
|
||||||
const cookieStorage = new CookieStorage();
|
const cookieStorage = new CookieStorage();
|
||||||
const history = useHistory();
|
const history = useHistory();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
@ -78,11 +79,6 @@ const PermissionProvider: FC<PermissionProviderProps> = ({ children }) => {
|
|||||||
{} as UIPermission
|
{} as UIPermission
|
||||||
);
|
);
|
||||||
|
|
||||||
// Update current user details of AppState change
|
|
||||||
const currentUser = useMemo(() => {
|
|
||||||
return AppState.getCurrentUserDetails();
|
|
||||||
}, [AppState.userDetails, AppState.nonSecureUserDetails]);
|
|
||||||
|
|
||||||
const redirectToStoredPath = useCallback(() => {
|
const redirectToStoredPath = useCallback(() => {
|
||||||
const urlPathname = cookieStorage.getItem(REDIRECT_PATHNAME);
|
const urlPathname = cookieStorage.getItem(REDIRECT_PATHNAME);
|
||||||
if (urlPathname) {
|
if (urlPathname) {
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
}
|
}
|
||||||
.ant-tabs-nav {
|
.ant-tabs-nav {
|
||||||
padding: 8px 16px 0 28px;
|
padding: 8px 16px 0 28px;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.widget-manage-dropdown .ant-dropdown-trigger {
|
.widget-manage-dropdown .ant-dropdown-trigger {
|
||||||
|
@ -84,14 +84,8 @@ const EntitySummaryDetails = ({
|
|||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
const {
|
const { isEntityDetails, userDetails, isTier, isOwner, isTeamOwner } =
|
||||||
isEntityDetails,
|
useMemo(() => {
|
||||||
userDetails,
|
|
||||||
isTier,
|
|
||||||
isOwner,
|
|
||||||
|
|
||||||
isTeamOwner,
|
|
||||||
} = useMemo(() => {
|
|
||||||
const userDetails = getTeamsUser(data);
|
const userDetails = getTeamsUser(data);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@ -100,7 +94,9 @@ const EntitySummaryDetails = ({
|
|||||||
userDetails,
|
userDetails,
|
||||||
isTier: data.key === 'Tier',
|
isTier: data.key === 'Tier',
|
||||||
isOwner: data.key === 'Owner',
|
isOwner: data.key === 'Owner',
|
||||||
isTeamOwner: isString(data.value) ? data.value.includes('teams/') : false,
|
isTeamOwner: isString(data.value)
|
||||||
|
? data.value.includes('teams/')
|
||||||
|
: false,
|
||||||
};
|
};
|
||||||
}, [data]);
|
}, [data]);
|
||||||
|
|
||||||
@ -129,7 +125,11 @@ const EntitySummaryDetails = ({
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{isTeamOwner ? (
|
{isTeamOwner ? (
|
||||||
<IconTeamsGrey height={18} width={18} />
|
<IconTeamsGrey
|
||||||
|
className="align-middle"
|
||||||
|
height={18}
|
||||||
|
width={18}
|
||||||
|
/>
|
||||||
) : (
|
) : (
|
||||||
<ProfilePicture
|
<ProfilePicture
|
||||||
displayName={displayVal}
|
displayName={displayVal}
|
||||||
|
@ -10,11 +10,11 @@
|
|||||||
* 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 { FilterOutlined } from '@ant-design/icons';
|
|
||||||
import { Button, Checkbox, List, Popover, Space, Typography } from 'antd';
|
import { Button, Checkbox, List, Popover, Space, Typography } from 'antd';
|
||||||
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import AppState from '../../../AppState';
|
import AppState from '../../../AppState';
|
||||||
|
import { ReactComponent as FilterIcon } from '../../../assets/svg/ic-feeds-filter.svg';
|
||||||
import { FeedFilter } from '../../../enums/mydata.enum';
|
import { FeedFilter } from '../../../enums/mydata.enum';
|
||||||
import './feeds-filter-popover.less';
|
import './feeds-filter-popover.less';
|
||||||
import { FeedsFilterPopoverProps } from './FeedsFilterPopover.interface';
|
import { FeedsFilterPopoverProps } from './FeedsFilterPopover.interface';
|
||||||
@ -126,7 +126,7 @@ const FeedsFilterPopover = ({
|
|||||||
showArrow={false}
|
showArrow={false}
|
||||||
trigger="click"
|
trigger="click"
|
||||||
onOpenChange={setPopupVisible}>
|
onOpenChange={setPopupVisible}>
|
||||||
<Button icon={<FilterOutlined />}>{t('label.filter-plural')}</Button>
|
<Button className="flex-center" icon={<FilterIcon height={16} />} />
|
||||||
</Popover>
|
</Popover>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -162,6 +162,17 @@ export const TAG_DROPDOWN_ITEMS = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const DATA_PRODUCT_DROPDOWN_ITEMS = [
|
||||||
|
{
|
||||||
|
label: t('label.domain'),
|
||||||
|
key: 'domain.displayName.keyword',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: t('label.owner'),
|
||||||
|
key: 'owner.displayName.keyword',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
export const ALL_DROPDOWN_ITEMS = [
|
export const ALL_DROPDOWN_ITEMS = [
|
||||||
...COMMON_DROPDOWN_ITEMS,
|
...COMMON_DROPDOWN_ITEMS,
|
||||||
...TABLE_DROPDOWN_ITEMS,
|
...TABLE_DROPDOWN_ITEMS,
|
||||||
|
@ -26,7 +26,7 @@ export const SIDEBAR_LIST = [
|
|||||||
{
|
{
|
||||||
key: ROUTES.EXPLORE,
|
key: ROUTES.EXPLORE,
|
||||||
label: i18next.t('label.explore'),
|
label: i18next.t('label.explore'),
|
||||||
redirect_url: '/explore/tables',
|
redirect_url: '/explore/dataProducts',
|
||||||
icon: ExploreIcon,
|
icon: ExploreIcon,
|
||||||
dataTestId: 'app-bar-item-explore',
|
dataTestId: 'app-bar-item-explore',
|
||||||
},
|
},
|
||||||
|
@ -56,6 +56,12 @@ export interface ExploreTabInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const tabsInfo: { [K in ExploreSearchIndex]: ExploreTabInfo } = {
|
export const tabsInfo: { [K in ExploreSearchIndex]: ExploreTabInfo } = {
|
||||||
|
[SearchIndex.DATA_PRODUCT]: {
|
||||||
|
label: i18n.t('label.data-product-plural'),
|
||||||
|
sortingFields: tableSortingFields,
|
||||||
|
sortField: INITIAL_SORT_FIELD,
|
||||||
|
path: 'dataProducts',
|
||||||
|
},
|
||||||
[SearchIndex.TABLE]: {
|
[SearchIndex.TABLE]: {
|
||||||
label: i18n.t('label.table-plural'),
|
label: i18n.t('label.table-plural'),
|
||||||
sortingFields: tableSortingFields,
|
sortingFields: tableSortingFields,
|
||||||
|
@ -1917,6 +1917,7 @@ export const mockSearchData = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const MOCK_EXPLORE_PAGE_COUNT = {
|
export const MOCK_EXPLORE_PAGE_COUNT = {
|
||||||
|
[SearchIndex.DATA_PRODUCT]: 0,
|
||||||
[SearchIndex.TABLE]: mockSearchData.hits.total.value,
|
[SearchIndex.TABLE]: mockSearchData.hits.total.value,
|
||||||
[SearchIndex.TOPIC]: 0,
|
[SearchIndex.TOPIC]: 0,
|
||||||
[SearchIndex.DASHBOARD]: 0,
|
[SearchIndex.DASHBOARD]: 0,
|
||||||
|
@ -77,8 +77,6 @@ const ExplorePageV1: FunctionComponent = () => {
|
|||||||
const [advancesSearchQuickFilters, setAdvancedSearchQuickFilters] =
|
const [advancesSearchQuickFilters, setAdvancedSearchQuickFilters] =
|
||||||
useState<QueryFilterInterface>();
|
useState<QueryFilterInterface>();
|
||||||
|
|
||||||
const [sortValue, setSortValue] = useState<string>(INITIAL_SORT_FIELD);
|
|
||||||
|
|
||||||
const [sortOrder, setSortOrder] = useState<SORT_ORDER>(SORT_ORDER.DESC);
|
const [sortOrder, setSortOrder] = useState<SORT_ORDER>(SORT_ORDER.DESC);
|
||||||
|
|
||||||
const [searchHitCounts, setSearchHitCounts] = useState<SearchHitCounts>();
|
const [searchHitCounts, setSearchHitCounts] = useState<SearchHitCounts>();
|
||||||
@ -87,20 +85,23 @@ const ExplorePageV1: FunctionComponent = () => {
|
|||||||
|
|
||||||
const { queryFilter } = useAdvanceSearch();
|
const { queryFilter } = useAdvanceSearch();
|
||||||
|
|
||||||
const parsedSearch = useMemo(
|
const [parsedSearch, searchQueryParam, sortValue] = useMemo(() => {
|
||||||
() =>
|
const parsedSearch = Qs.parse(
|
||||||
Qs.parse(
|
|
||||||
location.search.startsWith('?')
|
location.search.startsWith('?')
|
||||||
? location.search.substring(1)
|
? location.search.substring(1)
|
||||||
: location.search
|
: location.search
|
||||||
),
|
|
||||||
[location.search]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const searchQueryParam = useMemo(
|
const searchQueryParam = isString(parsedSearch.search)
|
||||||
() => (isString(parsedSearch.search) ? parsedSearch.search : ''),
|
? parsedSearch.search
|
||||||
[location.search]
|
: '';
|
||||||
);
|
|
||||||
|
const sortValue = isString(parsedSearch.sort)
|
||||||
|
? parsedSearch.sort
|
||||||
|
: INITIAL_SORT_FIELD;
|
||||||
|
|
||||||
|
return [parsedSearch, searchQueryParam, sortValue];
|
||||||
|
}, [location.search]);
|
||||||
|
|
||||||
const handlePageChange: ExploreProps['onChangePage'] = (page, size) => {
|
const handlePageChange: ExploreProps['onChangePage'] = (page, size) => {
|
||||||
history.push({
|
history.push({
|
||||||
@ -108,6 +109,17 @@ const ExplorePageV1: FunctionComponent = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleSortValueChange = (page: number, sortVal: string) => {
|
||||||
|
history.push({
|
||||||
|
search: Qs.stringify({
|
||||||
|
...parsedSearch,
|
||||||
|
page,
|
||||||
|
size: size ?? PAGE_SIZE,
|
||||||
|
sort: sortVal,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Filters that can be common for all the Entities Ex. Tables, Topics, etc.
|
// Filters that can be common for all the Entities Ex. Tables, Topics, etc.
|
||||||
const commonQuickFilters = useMemo(() => {
|
const commonQuickFilters = useMemo(() => {
|
||||||
const mustField: QueryFieldInterface[] = get(
|
const mustField: QueryFieldInterface[] = get(
|
||||||
@ -152,6 +164,7 @@ const ExplorePageV1: FunctionComponent = () => {
|
|||||||
getExplorePath({
|
getExplorePath({
|
||||||
tab: tabsInfo[nSearchIndex].path,
|
tab: tabsInfo[nSearchIndex].path,
|
||||||
extraParameters: {
|
extraParameters: {
|
||||||
|
sort: searchQueryParam ? '_score' : INITIAL_SORT_FIELD,
|
||||||
page: '1',
|
page: '1',
|
||||||
quickFilter: commonQuickFilters
|
quickFilter: commonQuickFilters
|
||||||
? JSON.stringify(commonQuickFilters)
|
? JSON.stringify(commonQuickFilters)
|
||||||
@ -161,7 +174,7 @@ const ExplorePageV1: FunctionComponent = () => {
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
[commonQuickFilters]
|
[commonQuickFilters, searchQueryParam]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleQuickFilterChange = useCallback(
|
const handleQuickFilterChange = useCallback(
|
||||||
@ -193,13 +206,13 @@ const ExplorePageV1: FunctionComponent = () => {
|
|||||||
if (isNil(tabInfo)) {
|
if (isNil(tabInfo)) {
|
||||||
const activeKey = findActiveSearchIndex(searchHitCounts);
|
const activeKey = findActiveSearchIndex(searchHitCounts);
|
||||||
|
|
||||||
return activeKey ? activeKey : SearchIndex.TABLE;
|
return activeKey ? activeKey : SearchIndex.DATA_PRODUCT;
|
||||||
}
|
}
|
||||||
|
|
||||||
return tabInfo[0] as ExploreSearchIndex;
|
return tabInfo[0] as ExploreSearchIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
return SearchIndex.TABLE;
|
return SearchIndex.DATA_PRODUCT;
|
||||||
}, [tab, searchHitCounts]);
|
}, [tab, searchHitCounts]);
|
||||||
|
|
||||||
const tabItems = useMemo(() => {
|
const tabItems = useMemo(() => {
|
||||||
@ -297,19 +310,13 @@ const ExplorePageV1: FunctionComponent = () => {
|
|||||||
queryFilter as unknown as QueryFilterInterface
|
queryFilter as unknown as QueryFilterInterface
|
||||||
);
|
);
|
||||||
|
|
||||||
let newSortValue = sortValue;
|
|
||||||
if (searchQueryParam !== '') {
|
|
||||||
newSortValue = '_score';
|
|
||||||
setSortValue(newSortValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
Promise.all([
|
Promise.all([
|
||||||
searchQuery({
|
searchQuery({
|
||||||
query: escapeESReservedCharacters(searchQueryParam),
|
query: escapeESReservedCharacters(searchQueryParam),
|
||||||
searchIndex,
|
searchIndex,
|
||||||
queryFilter: combinedQueryFilter,
|
queryFilter: combinedQueryFilter,
|
||||||
sortField: newSortValue,
|
sortField: sortValue,
|
||||||
sortOrder,
|
sortOrder,
|
||||||
pageNumber: page,
|
pageNumber: page,
|
||||||
pageSize: size,
|
pageSize: size,
|
||||||
@ -322,6 +329,7 @@ const ExplorePageV1: FunctionComponent = () => {
|
|||||||
}),
|
}),
|
||||||
Promise.all(
|
Promise.all(
|
||||||
[
|
[
|
||||||
|
SearchIndex.DATA_PRODUCT,
|
||||||
SearchIndex.TABLE,
|
SearchIndex.TABLE,
|
||||||
SearchIndex.TOPIC,
|
SearchIndex.TOPIC,
|
||||||
SearchIndex.DASHBOARD,
|
SearchIndex.DASHBOARD,
|
||||||
@ -348,6 +356,7 @@ const ExplorePageV1: FunctionComponent = () => {
|
|||||||
)
|
)
|
||||||
).then(
|
).then(
|
||||||
([
|
([
|
||||||
|
dataProductResponse,
|
||||||
tableResponse,
|
tableResponse,
|
||||||
topicResponse,
|
topicResponse,
|
||||||
dashboardResponse,
|
dashboardResponse,
|
||||||
@ -361,6 +370,7 @@ const ExplorePageV1: FunctionComponent = () => {
|
|||||||
searchIndexResponse,
|
searchIndexResponse,
|
||||||
]) => {
|
]) => {
|
||||||
setSearchHitCounts({
|
setSearchHitCounts({
|
||||||
|
[SearchIndex.DATA_PRODUCT]: dataProductResponse.hits.total.value,
|
||||||
[SearchIndex.TABLE]: tableResponse.hits.total.value,
|
[SearchIndex.TABLE]: tableResponse.hits.total.value,
|
||||||
[SearchIndex.TOPIC]: topicResponse.hits.total.value,
|
[SearchIndex.TOPIC]: topicResponse.hits.total.value,
|
||||||
[SearchIndex.DASHBOARD]: dashboardResponse.hits.total.value,
|
[SearchIndex.DASHBOARD]: dashboardResponse.hits.total.value,
|
||||||
@ -440,9 +450,8 @@ const ExplorePageV1: FunctionComponent = () => {
|
|||||||
handlePageChange(1);
|
handlePageChange(1);
|
||||||
setSortOrder(sort);
|
setSortOrder(sort);
|
||||||
}}
|
}}
|
||||||
onChangeSortValue={(sort) => {
|
onChangeSortValue={(sortVal) => {
|
||||||
handlePageChange(1);
|
handleSortValueChange(1, sortVal);
|
||||||
setSortValue(sort);
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -23,6 +23,7 @@ import { User } from '../generated/entity/teams/user';
|
|||||||
import { SearchResponse } from '../interface/search.interface';
|
import { SearchResponse } from '../interface/search.interface';
|
||||||
|
|
||||||
export type SearchEntityHits = SearchResponse<
|
export type SearchEntityHits = SearchResponse<
|
||||||
|
| SearchIndex.DATA_PRODUCT
|
||||||
| SearchIndex.PIPELINE
|
| SearchIndex.PIPELINE
|
||||||
| SearchIndex.DASHBOARD
|
| SearchIndex.DASHBOARD
|
||||||
| SearchIndex.TABLE
|
| SearchIndex.TABLE
|
||||||
@ -56,7 +57,7 @@ export const formatDataResponse = (
|
|||||||
newData.owner = get(hit, '_source.owner');
|
newData.owner = get(hit, '_source.owner');
|
||||||
newData.highlight = hit.highlight;
|
newData.highlight = hit.highlight;
|
||||||
newData.entityType = hit._source.entityType;
|
newData.entityType = hit._source.entityType;
|
||||||
newData.deleted = hit._source.deleted;
|
newData.deleted = get(hit, '_source.deleted');
|
||||||
|
|
||||||
if ('tableType' in source) {
|
if ('tableType' in source) {
|
||||||
newData.tableType = source.tableType ?? '';
|
newData.tableType = source.tableType ?? '';
|
||||||
|
@ -24,6 +24,7 @@ import {
|
|||||||
CONTAINER_DROPDOWN_ITEMS,
|
CONTAINER_DROPDOWN_ITEMS,
|
||||||
DASHBOARD_DATA_MODEL_TYPE,
|
DASHBOARD_DATA_MODEL_TYPE,
|
||||||
DASHBOARD_DROPDOWN_ITEMS,
|
DASHBOARD_DROPDOWN_ITEMS,
|
||||||
|
DATA_PRODUCT_DROPDOWN_ITEMS,
|
||||||
GLOSSARY_DROPDOWN_ITEMS,
|
GLOSSARY_DROPDOWN_ITEMS,
|
||||||
PIPELINE_DROPDOWN_ITEMS,
|
PIPELINE_DROPDOWN_ITEMS,
|
||||||
SEARCH_INDEX_DROPDOWN_ITEMS,
|
SEARCH_INDEX_DROPDOWN_ITEMS,
|
||||||
@ -79,6 +80,8 @@ export const getDropDownItems = (index: string) => {
|
|||||||
return [...GLOSSARY_DROPDOWN_ITEMS];
|
return [...GLOSSARY_DROPDOWN_ITEMS];
|
||||||
case SearchIndex.TAG:
|
case SearchIndex.TAG:
|
||||||
return [...TAG_DROPDOWN_ITEMS];
|
return [...TAG_DROPDOWN_ITEMS];
|
||||||
|
case SearchIndex.DATA_PRODUCT:
|
||||||
|
return [...DATA_PRODUCT_DROPDOWN_ITEMS];
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return [];
|
return [];
|
||||||
|
@ -109,3 +109,23 @@ export const getUserNames = (
|
|||||||
|
|
||||||
return getOwner(hasPermission, getEntityName(entity.owner), entity.owner);
|
return getOwner(hasPermission, getEntityName(entity.owner), entity.owner);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getQueryFilterToIncludeDomain = (fqn: string) => ({
|
||||||
|
query: {
|
||||||
|
bool: {
|
||||||
|
must: [
|
||||||
|
{
|
||||||
|
bool: {
|
||||||
|
must: [
|
||||||
|
{
|
||||||
|
term: {
|
||||||
|
'domain.fullyQualifiedName': fqn,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user