+ const userResult = `
${item.avatarEle}
${item.name}
`;
+
+ const userWrapper = document.createElement('div');
+ userWrapper.innerHTML = userResult;
+
+ return userWrapper;
}
const breadcrumbsData = item.breadcrumbs
@@ -127,7 +132,7 @@ export const FeedEditor = forwardRef
(
? `${item.type}`
: '';
- return `
+ const result = `
${icon}
${breadcrumbEle}
@@ -137,6 +142,11 @@ export const FeedEditor = forwardRef(
`;
+
+ const wrapper = document.createElement('div');
+ wrapper.innerHTML = result;
+
+ return wrapper;
},
},
markdownOptions: {},
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTerms/GlossaryTermsV1.component.tsx b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTerms/GlossaryTermsV1.component.tsx
index e400ec84ed7..cb6c838b344 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTerms/GlossaryTermsV1.component.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/Glossary/GlossaryTerms/GlossaryTermsV1.component.tsx
@@ -25,6 +25,7 @@ import { ChangeDescription } from '../../../generated/entity/type';
import { searchData } from '../../../rest/miscAPI';
import { getCountBadge, getFeedCounts } from '../../../utils/CommonUtils';
import { getEntityVersionByField } from '../../../utils/EntityVersionUtils';
+import { getQueryFilterToExcludeTerm } from '../../../utils/GlossaryUtils';
import { getGlossaryTermsVersionsPath } from '../../../utils/RouterUtils';
import { getEncodedFqn } from '../../../utils/StringsUtils';
import { ActivityFeedTab } from '../../ActivityFeed/ActivityFeedTab/ActivityFeedTab.component';
@@ -321,6 +322,9 @@ const GlossaryTermsV1 = ({
setAssetModelVisible(false)}
onSave={handleAssetSave}
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/PermissionProvider/PermissionProvider.test.tsx b/openmetadata-ui/src/main/resources/ui/src/components/PermissionProvider/PermissionProvider.test.tsx
index 177a71ba628..18731075055 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/PermissionProvider/PermissionProvider.test.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/PermissionProvider/PermissionProvider.test.tsx
@@ -12,8 +12,6 @@
*/
import { render, screen } from '@testing-library/react';
import React from 'react';
-import AppState from '../../AppState';
-import { User } from '../../generated/entity/teams/user';
import {
getEntityPermissionByFqn,
getEntityPermissionById,
@@ -37,13 +35,25 @@ jest.mock('../../rest/permissionAPI', () => ({
.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', () => {
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(
Children
@@ -57,15 +67,10 @@ describe('PermissionProvider', () => {
expect(getResourcePermission).not.toHaveBeenCalled();
expect(await screen.findByTestId('children')).toBeInTheDocument();
-
- getUserDetailsSpy.mockRestore();
});
it('Should not call apis when current user is undefined', async () => {
- const getUserDetailsSpy = jest
- .spyOn(AppState, 'getCurrentUserDetails')
- .mockReturnValue(undefined);
-
+ currentUser = null;
render(
Children
@@ -77,7 +82,5 @@ describe('PermissionProvider', () => {
expect(getEntityPermissionById).not.toHaveBeenCalled();
expect(getEntityPermissionByFqn).not.toHaveBeenCalled();
expect(getResourcePermission).not.toHaveBeenCalled();
-
- getUserDetailsSpy.mockRestore();
});
});
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/PermissionProvider/PermissionProvider.tsx b/openmetadata-ui/src/main/resources/ui/src/components/PermissionProvider/PermissionProvider.tsx
index 7d7e4bfa029..4e73a80b8d4 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/PermissionProvider/PermissionProvider.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/PermissionProvider/PermissionProvider.tsx
@@ -24,7 +24,6 @@ import React, {
useState,
} from 'react';
import { useHistory } from 'react-router-dom';
-import AppState from '../../AppState';
import Loader from '../../components/Loader/Loader';
import { REDIRECT_PATHNAME } from '../../constants/constants';
import {
@@ -41,6 +40,7 @@ import {
getOperationPermissions,
getUIPermission,
} from '../../utils/PermissionsUtils';
+import { useAuthContext } from '../authentication/auth-provider/AuthProvider';
import {
EntityPermissionMap,
PermissionContextType,
@@ -67,6 +67,7 @@ const PermissionProvider: FC = ({ children }) => {
const [permissions, setPermissions] = useState(
{} as UIPermission
);
+ const { currentUser } = useAuthContext();
const cookieStorage = new CookieStorage();
const history = useHistory();
const [loading, setLoading] = useState(false);
@@ -78,11 +79,6 @@ const PermissionProvider: FC = ({ children }) => {
{} as UIPermission
);
- // Update current user details of AppState change
- const currentUser = useMemo(() => {
- return AppState.getCurrentUserDetails();
- }, [AppState.userDetails, AppState.nonSecureUserDetails]);
-
const redirectToStoredPath = useCallback(() => {
const urlPathname = cookieStorage.getItem(REDIRECT_PATHNAME);
if (urlPathname) {
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/Widgets/FeedsWidget/feeds-widget.less b/openmetadata-ui/src/main/resources/ui/src/components/Widgets/FeedsWidget/feeds-widget.less
index c5da7d52d40..f12fb49899a 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/Widgets/FeedsWidget/feeds-widget.less
+++ b/openmetadata-ui/src/main/resources/ui/src/components/Widgets/FeedsWidget/feeds-widget.less
@@ -29,7 +29,7 @@
}
.ant-tabs-nav {
padding: 8px 16px 0 28px;
- margin-bottom: 0;
+ margin-bottom: 0 !important;
}
.widget-manage-dropdown .ant-dropdown-trigger {
diff --git a/openmetadata-ui/src/main/resources/ui/src/components/common/EntitySummaryDetails/EntitySummaryDetails.tsx b/openmetadata-ui/src/main/resources/ui/src/components/common/EntitySummaryDetails/EntitySummaryDetails.tsx
index 511fae173e5..ce516d6d565 100644
--- a/openmetadata-ui/src/main/resources/ui/src/components/common/EntitySummaryDetails/EntitySummaryDetails.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/components/common/EntitySummaryDetails/EntitySummaryDetails.tsx
@@ -84,25 +84,21 @@ const EntitySummaryDetails = ({
/>
);
- const {
- isEntityDetails,
- userDetails,
- isTier,
- isOwner,
+ const { isEntityDetails, userDetails, isTier, isOwner, isTeamOwner } =
+ useMemo(() => {
+ const userDetails = getTeamsUser(data);
- isTeamOwner,
- } = useMemo(() => {
- const userDetails = getTeamsUser(data);
-
- return {
- isEntityCard: data?.isEntityCard,
- isEntityDetails: data?.isEntityDetails,
- userDetails,
- isTier: data.key === 'Tier',
- isOwner: data.key === 'Owner',
- isTeamOwner: isString(data.value) ? data.value.includes('teams/') : false,
- };
- }, [data]);
+ return {
+ isEntityCard: data?.isEntityCard,
+ isEntityDetails: data?.isEntityDetails,
+ userDetails,
+ isTier: data.key === 'Tier',
+ isOwner: data.key === 'Owner',
+ isTeamOwner: isString(data.value)
+ ? data.value.includes('teams/')
+ : false,
+ };
+ }, [data]);
switch (data.key) {
case 'Owner':
@@ -129,7 +125,11 @@ const EntitySummaryDetails = ({
>
)}
{isTeamOwner ? (
-
+
) : (
- }>{t('label.filter-plural')}
+ } />
);
};
diff --git a/openmetadata-ui/src/main/resources/ui/src/constants/AdvancedSearch.constants.ts b/openmetadata-ui/src/main/resources/ui/src/constants/AdvancedSearch.constants.ts
index 9b6caded1b7..622cd795e80 100644
--- a/openmetadata-ui/src/main/resources/ui/src/constants/AdvancedSearch.constants.ts
+++ b/openmetadata-ui/src/main/resources/ui/src/constants/AdvancedSearch.constants.ts
@@ -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 = [
...COMMON_DROPDOWN_ITEMS,
...TABLE_DROPDOWN_ITEMS,
diff --git a/openmetadata-ui/src/main/resources/ui/src/constants/LeftSidebar.constants.ts b/openmetadata-ui/src/main/resources/ui/src/constants/LeftSidebar.constants.ts
index 29a02c1a8f5..368f9bc31e6 100644
--- a/openmetadata-ui/src/main/resources/ui/src/constants/LeftSidebar.constants.ts
+++ b/openmetadata-ui/src/main/resources/ui/src/constants/LeftSidebar.constants.ts
@@ -26,7 +26,7 @@ export const SIDEBAR_LIST = [
{
key: ROUTES.EXPLORE,
label: i18next.t('label.explore'),
- redirect_url: '/explore/tables',
+ redirect_url: '/explore/dataProducts',
icon: ExploreIcon,
dataTestId: 'app-bar-item-explore',
},
diff --git a/openmetadata-ui/src/main/resources/ui/src/constants/explore.constants.ts b/openmetadata-ui/src/main/resources/ui/src/constants/explore.constants.ts
index 61b96e11202..6e817f1e3e9 100644
--- a/openmetadata-ui/src/main/resources/ui/src/constants/explore.constants.ts
+++ b/openmetadata-ui/src/main/resources/ui/src/constants/explore.constants.ts
@@ -56,6 +56,12 @@ export interface 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]: {
label: i18n.t('label.table-plural'),
sortingFields: tableSortingFields,
diff --git a/openmetadata-ui/src/main/resources/ui/src/constants/mockTourData.constants.ts b/openmetadata-ui/src/main/resources/ui/src/constants/mockTourData.constants.ts
index 2ec6244cc46..465bdfd8f57 100644
--- a/openmetadata-ui/src/main/resources/ui/src/constants/mockTourData.constants.ts
+++ b/openmetadata-ui/src/main/resources/ui/src/constants/mockTourData.constants.ts
@@ -1917,6 +1917,7 @@ export const mockSearchData = {
};
export const MOCK_EXPLORE_PAGE_COUNT = {
+ [SearchIndex.DATA_PRODUCT]: 0,
[SearchIndex.TABLE]: mockSearchData.hits.total.value,
[SearchIndex.TOPIC]: 0,
[SearchIndex.DASHBOARD]: 0,
diff --git a/openmetadata-ui/src/main/resources/ui/src/pages/explore/ExplorePageV1.component.tsx b/openmetadata-ui/src/main/resources/ui/src/pages/explore/ExplorePageV1.component.tsx
index 8f7f731362e..0a3c81a5829 100644
--- a/openmetadata-ui/src/main/resources/ui/src/pages/explore/ExplorePageV1.component.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/pages/explore/ExplorePageV1.component.tsx
@@ -77,8 +77,6 @@ const ExplorePageV1: FunctionComponent = () => {
const [advancesSearchQuickFilters, setAdvancedSearchQuickFilters] =
useState();
- const [sortValue, setSortValue] = useState(INITIAL_SORT_FIELD);
-
const [sortOrder, setSortOrder] = useState(SORT_ORDER.DESC);
const [searchHitCounts, setSearchHitCounts] = useState();
@@ -87,20 +85,23 @@ const ExplorePageV1: FunctionComponent = () => {
const { queryFilter } = useAdvanceSearch();
- const parsedSearch = useMemo(
- () =>
- Qs.parse(
- location.search.startsWith('?')
- ? location.search.substring(1)
- : location.search
- ),
- [location.search]
- );
+ const [parsedSearch, searchQueryParam, sortValue] = useMemo(() => {
+ const parsedSearch = Qs.parse(
+ location.search.startsWith('?')
+ ? location.search.substring(1)
+ : location.search
+ );
- const searchQueryParam = useMemo(
- () => (isString(parsedSearch.search) ? parsedSearch.search : ''),
- [location.search]
- );
+ const searchQueryParam = isString(parsedSearch.search)
+ ? parsedSearch.search
+ : '';
+
+ const sortValue = isString(parsedSearch.sort)
+ ? parsedSearch.sort
+ : INITIAL_SORT_FIELD;
+
+ return [parsedSearch, searchQueryParam, sortValue];
+ }, [location.search]);
const handlePageChange: ExploreProps['onChangePage'] = (page, size) => {
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.
const commonQuickFilters = useMemo(() => {
const mustField: QueryFieldInterface[] = get(
@@ -152,6 +164,7 @@ const ExplorePageV1: FunctionComponent = () => {
getExplorePath({
tab: tabsInfo[nSearchIndex].path,
extraParameters: {
+ sort: searchQueryParam ? '_score' : INITIAL_SORT_FIELD,
page: '1',
quickFilter: commonQuickFilters
? JSON.stringify(commonQuickFilters)
@@ -161,7 +174,7 @@ const ExplorePageV1: FunctionComponent = () => {
})
);
},
- [commonQuickFilters]
+ [commonQuickFilters, searchQueryParam]
);
const handleQuickFilterChange = useCallback(
@@ -193,13 +206,13 @@ const ExplorePageV1: FunctionComponent = () => {
if (isNil(tabInfo)) {
const activeKey = findActiveSearchIndex(searchHitCounts);
- return activeKey ? activeKey : SearchIndex.TABLE;
+ return activeKey ? activeKey : SearchIndex.DATA_PRODUCT;
}
return tabInfo[0] as ExploreSearchIndex;
}
- return SearchIndex.TABLE;
+ return SearchIndex.DATA_PRODUCT;
}, [tab, searchHitCounts]);
const tabItems = useMemo(() => {
@@ -297,19 +310,13 @@ const ExplorePageV1: FunctionComponent = () => {
queryFilter as unknown as QueryFilterInterface
);
- let newSortValue = sortValue;
- if (searchQueryParam !== '') {
- newSortValue = '_score';
- setSortValue(newSortValue);
- }
-
setIsLoading(true);
Promise.all([
searchQuery({
query: escapeESReservedCharacters(searchQueryParam),
searchIndex,
queryFilter: combinedQueryFilter,
- sortField: newSortValue,
+ sortField: sortValue,
sortOrder,
pageNumber: page,
pageSize: size,
@@ -322,6 +329,7 @@ const ExplorePageV1: FunctionComponent = () => {
}),
Promise.all(
[
+ SearchIndex.DATA_PRODUCT,
SearchIndex.TABLE,
SearchIndex.TOPIC,
SearchIndex.DASHBOARD,
@@ -348,6 +356,7 @@ const ExplorePageV1: FunctionComponent = () => {
)
).then(
([
+ dataProductResponse,
tableResponse,
topicResponse,
dashboardResponse,
@@ -361,6 +370,7 @@ const ExplorePageV1: FunctionComponent = () => {
searchIndexResponse,
]) => {
setSearchHitCounts({
+ [SearchIndex.DATA_PRODUCT]: dataProductResponse.hits.total.value,
[SearchIndex.TABLE]: tableResponse.hits.total.value,
[SearchIndex.TOPIC]: topicResponse.hits.total.value,
[SearchIndex.DASHBOARD]: dashboardResponse.hits.total.value,
@@ -440,9 +450,8 @@ const ExplorePageV1: FunctionComponent = () => {
handlePageChange(1);
setSortOrder(sort);
}}
- onChangeSortValue={(sort) => {
- handlePageChange(1);
- setSortValue(sort);
+ onChangeSortValue={(sortVal) => {
+ handleSortValueChange(1, sortVal);
}}
/>
);
diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/APIUtils.ts b/openmetadata-ui/src/main/resources/ui/src/utils/APIUtils.ts
index 216c65874b0..88093d1f110 100644
--- a/openmetadata-ui/src/main/resources/ui/src/utils/APIUtils.ts
+++ b/openmetadata-ui/src/main/resources/ui/src/utils/APIUtils.ts
@@ -23,6 +23,7 @@ import { User } from '../generated/entity/teams/user';
import { SearchResponse } from '../interface/search.interface';
export type SearchEntityHits = SearchResponse<
+ | SearchIndex.DATA_PRODUCT
| SearchIndex.PIPELINE
| SearchIndex.DASHBOARD
| SearchIndex.TABLE
@@ -56,7 +57,7 @@ export const formatDataResponse = (
newData.owner = get(hit, '_source.owner');
newData.highlight = hit.highlight;
newData.entityType = hit._source.entityType;
- newData.deleted = hit._source.deleted;
+ newData.deleted = get(hit, '_source.deleted');
if ('tableType' in source) {
newData.tableType = source.tableType ?? '';
diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/AdvancedSearchUtils.tsx b/openmetadata-ui/src/main/resources/ui/src/utils/AdvancedSearchUtils.tsx
index 2f272294c85..ecfe9666581 100644
--- a/openmetadata-ui/src/main/resources/ui/src/utils/AdvancedSearchUtils.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/utils/AdvancedSearchUtils.tsx
@@ -24,6 +24,7 @@ import {
CONTAINER_DROPDOWN_ITEMS,
DASHBOARD_DATA_MODEL_TYPE,
DASHBOARD_DROPDOWN_ITEMS,
+ DATA_PRODUCT_DROPDOWN_ITEMS,
GLOSSARY_DROPDOWN_ITEMS,
PIPELINE_DROPDOWN_ITEMS,
SEARCH_INDEX_DROPDOWN_ITEMS,
@@ -79,6 +80,8 @@ export const getDropDownItems = (index: string) => {
return [...GLOSSARY_DROPDOWN_ITEMS];
case SearchIndex.TAG:
return [...TAG_DROPDOWN_ITEMS];
+ case SearchIndex.DATA_PRODUCT:
+ return [...DATA_PRODUCT_DROPDOWN_ITEMS];
default:
return [];
diff --git a/openmetadata-ui/src/main/resources/ui/src/utils/DomainUtils.tsx b/openmetadata-ui/src/main/resources/ui/src/utils/DomainUtils.tsx
index 2b0acb5df6b..74425bd8c4b 100644
--- a/openmetadata-ui/src/main/resources/ui/src/utils/DomainUtils.tsx
+++ b/openmetadata-ui/src/main/resources/ui/src/utils/DomainUtils.tsx
@@ -109,3 +109,23 @@ export const getUserNames = (
return getOwner(hasPermission, getEntityName(entity.owner), entity.owner);
};
+
+export const getQueryFilterToIncludeDomain = (fqn: string) => ({
+ query: {
+ bool: {
+ must: [
+ {
+ bool: {
+ must: [
+ {
+ term: {
+ 'domain.fullyQualifiedName': fqn,
+ },
+ },
+ ],
+ },
+ },
+ ],
+ },
+ },
+});