mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-09-10 17:42:07 +00:00
fix(ui): all assets not showing on my data widget (#13703)
* changed the api call to fetch owned assets in my data widget * fixed unit tests
This commit is contained in:
parent
de544d2dca
commit
a72fcec57f
@ -17,15 +17,20 @@ import { observer } from 'mobx-react';
|
|||||||
import React, { useCallback, useEffect, useState } from 'react';
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import AppState from '../../../AppState';
|
import {
|
||||||
import { getUserPath, ROUTES } from '../../../constants/constants';
|
getUserPath,
|
||||||
import { AssetsType } from '../../../enums/entity.enum';
|
INITIAL_PAGING_VALUE,
|
||||||
import { EntityReference } from '../../../generated/entity/type';
|
PAGE_SIZE,
|
||||||
|
ROUTES,
|
||||||
|
} from '../../../constants/constants';
|
||||||
|
import { SearchIndex } from '../../../enums/search.enum';
|
||||||
import { WidgetCommonProps } from '../../../pages/CustomizablePage/CustomizablePage.interface';
|
import { WidgetCommonProps } from '../../../pages/CustomizablePage/CustomizablePage.interface';
|
||||||
import { getUserById } from '../../../rest/userAPI';
|
import { searchData } from '../../../rest/miscAPI';
|
||||||
import { Transi18next } from '../../../utils/CommonUtils';
|
import { Transi18next } from '../../../utils/CommonUtils';
|
||||||
import { getEntityName } from '../../../utils/EntityUtils';
|
import { getEntityName } from '../../../utils/EntityUtils';
|
||||||
import { getEntityIcon, getEntityLink } from '../../../utils/TableUtils';
|
import { getEntityIcon, getEntityLink } from '../../../utils/TableUtils';
|
||||||
|
import { useAuthContext } from '../../authentication/auth-provider/AuthProvider';
|
||||||
|
import { SourceType } from '../../searched-data/SearchedData.interface';
|
||||||
import EntityListSkeleton from '../../Skeleton/MyData/EntityListSkeleton/EntityListSkeleton.component';
|
import EntityListSkeleton from '../../Skeleton/MyData/EntityListSkeleton/EntityListSkeleton.component';
|
||||||
import './MyDataWidget.less';
|
import './MyDataWidget.less';
|
||||||
|
|
||||||
@ -35,34 +40,43 @@ const MyDataWidgetInternal = ({
|
|||||||
widgetKey,
|
widgetKey,
|
||||||
}: WidgetCommonProps) => {
|
}: WidgetCommonProps) => {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const currentUserDetails = AppState.getCurrentUserDetails();
|
const { currentUser } = useAuthContext();
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
const [data, setData] = useState<EntityReference[]>([]);
|
const [data, setData] = useState<SourceType[]>([]);
|
||||||
const [totalOwnedAssetsCount, setTotalOwnedAssetsCount] = useState<number>(0);
|
const [totalOwnedAssetsCount, setTotalOwnedAssetsCount] = useState<number>(0);
|
||||||
|
|
||||||
const fetchMyDataAssets = async () => {
|
const fetchMyDataAssets = async () => {
|
||||||
if (!currentUserDetails || !currentUserDetails.id) {
|
if (!isUndefined(currentUser)) {
|
||||||
return;
|
setIsLoading(true);
|
||||||
}
|
try {
|
||||||
setIsLoading(true);
|
const teamsIds = (currentUser.teams ?? []).map((team) => team.id);
|
||||||
try {
|
const mergedIds = [
|
||||||
const userData = await getUserById(currentUserDetails?.id, 'owns');
|
...teamsIds.map((id) => `owner.id:${id}`),
|
||||||
|
`owner.id:${currentUser.id}`,
|
||||||
|
].join(' OR ');
|
||||||
|
|
||||||
if (userData) {
|
const queryFilter = `(${mergedIds})`;
|
||||||
const includeData = Object.values(AssetsType);
|
const res = await searchData(
|
||||||
const owns: EntityReference[] = userData.owns ?? [];
|
'',
|
||||||
|
INITIAL_PAGING_VALUE,
|
||||||
const includedOwnsData = owns.filter((data) =>
|
PAGE_SIZE,
|
||||||
includeData.includes(data.type as AssetsType)
|
queryFilter,
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
SearchIndex.ALL
|
||||||
);
|
);
|
||||||
|
|
||||||
setData(includedOwnsData.slice(0, 8));
|
// Extract useful details from the Response
|
||||||
setTotalOwnedAssetsCount(includedOwnsData.length);
|
const totalOwnedAssets = res?.data?.hits?.total.value ?? 0;
|
||||||
|
const ownedAssets = res?.data?.hits?.hits;
|
||||||
|
|
||||||
|
setData(ownedAssets.map((hit) => hit._source).slice(0, 8));
|
||||||
|
setTotalOwnedAssetsCount(totalOwnedAssets);
|
||||||
|
} catch (err) {
|
||||||
|
setData([]);
|
||||||
|
} finally {
|
||||||
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
} catch (err) {
|
|
||||||
setData([]);
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -72,7 +86,7 @@ const MyDataWidgetInternal = ({
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
fetchMyDataAssets();
|
fetchMyDataAssets();
|
||||||
}, [currentUserDetails]);
|
}, [currentUser]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card className="my-data-widget-container card-widget" loading={isLoading}>
|
<Card className="my-data-widget-container card-widget" loading={isLoading}>
|
||||||
@ -86,7 +100,7 @@ const MyDataWidgetInternal = ({
|
|||||||
{data.length ? (
|
{data.length ? (
|
||||||
<Link
|
<Link
|
||||||
data-testid="view-all-link"
|
data-testid="view-all-link"
|
||||||
to={getUserPath(currentUserDetails?.name || '', 'mydata')}>
|
to={getUserPath(currentUser?.name ?? '', 'mydata')}>
|
||||||
<span className="text-grey-muted font-normal text-xs">
|
<span className="text-grey-muted font-normal text-xs">
|
||||||
{t('label.view-all')}{' '}
|
{t('label.view-all')}{' '}
|
||||||
<span data-testid="my-data-total-count">
|
<span data-testid="my-data-total-count">
|
||||||
@ -132,14 +146,14 @@ const MyDataWidgetInternal = ({
|
|||||||
<Link
|
<Link
|
||||||
className=""
|
className=""
|
||||||
to={getEntityLink(
|
to={getEntityLink(
|
||||||
item.type || '',
|
item.entityType ?? '',
|
||||||
item.fullyQualifiedName as string
|
item.fullyQualifiedName as string
|
||||||
)}>
|
)}>
|
||||||
<Button
|
<Button
|
||||||
className="entity-button flex-center p-0 m--ml-1"
|
className="entity-button flex-center p-0 m--ml-1"
|
||||||
icon={
|
icon={
|
||||||
<div className="entity-button-icon m-r-xs">
|
<div className="entity-button-icon m-r-xs">
|
||||||
{getEntityIcon(item.type || '')}
|
{getEntityIcon(item.entityType ?? '')}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
type="text">
|
type="text">
|
||||||
|
@ -13,15 +13,46 @@
|
|||||||
import { act, render, screen } from '@testing-library/react';
|
import { act, render, screen } from '@testing-library/react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { MemoryRouter } from 'react-router-dom';
|
import { MemoryRouter } from 'react-router-dom';
|
||||||
import { getUserById } from '../../../rest/userAPI';
|
import { User } from '../../../generated/entity/teams/user';
|
||||||
|
import { searchData } from '../../../rest/miscAPI';
|
||||||
import { MyDataWidget } from './MyDataWidget.component';
|
import { MyDataWidget } from './MyDataWidget.component';
|
||||||
|
|
||||||
const userDetails = {
|
const mockUserData: User = {
|
||||||
id: '123',
|
name: 'testUser1',
|
||||||
|
email: 'testUser1@email.com',
|
||||||
|
id: '113',
|
||||||
};
|
};
|
||||||
|
|
||||||
jest.mock('../../../rest/userAPI', () => ({
|
const mockSearchAPIResponse = {
|
||||||
getUserById: jest.fn().mockImplementation(() =>
|
data: {
|
||||||
|
hits: {
|
||||||
|
hits: [
|
||||||
|
{
|
||||||
|
_source: {
|
||||||
|
id: '1',
|
||||||
|
name: 'test 1',
|
||||||
|
fullyQualifiedName: 'test-1',
|
||||||
|
type: 'table',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_source: {
|
||||||
|
id: '2',
|
||||||
|
name: 'test 2',
|
||||||
|
fullyQualifiedName: 'test-2',
|
||||||
|
type: 'table',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
total: {
|
||||||
|
value: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
jest.mock('../../../rest/miscAPI', () => ({
|
||||||
|
searchData: jest.fn().mockImplementation(() =>
|
||||||
Promise.resolve({
|
Promise.resolve({
|
||||||
owns: [],
|
owns: [],
|
||||||
})
|
})
|
||||||
@ -37,10 +68,10 @@ jest.mock('../../../utils/TableUtils', () => ({
|
|||||||
getEntityIcon: jest.fn().mockImplementation((obj) => obj.name),
|
getEntityIcon: jest.fn().mockImplementation((obj) => obj.name),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.mock('./../../../AppState', () => ({
|
jest.mock('../../authentication/auth-provider/AuthProvider', () => ({
|
||||||
getCurrentUserDetails: jest.fn().mockImplementation(() => {
|
useAuthContext: jest.fn(() => ({
|
||||||
return userDetails;
|
currentUser: mockUserData,
|
||||||
}),
|
})),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
jest.mock(
|
jest.mock(
|
||||||
@ -56,7 +87,15 @@ describe('MyDataWidget component', () => {
|
|||||||
render(<MyDataWidget widgetKey="widgetKey" />, { wrapper: MemoryRouter });
|
render(<MyDataWidget widgetKey="widgetKey" />, { wrapper: MemoryRouter });
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(getUserById).toHaveBeenCalledWith('123', 'owns');
|
expect(searchData).toHaveBeenCalledWith(
|
||||||
|
'',
|
||||||
|
1,
|
||||||
|
10,
|
||||||
|
'(owner.id:113)',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'all'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it.skip('should render header', () => {
|
it.skip('should render header', () => {
|
||||||
@ -84,23 +123,8 @@ describe('MyDataWidget component', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should render view all for data present', async () => {
|
it('should render view all for data present', async () => {
|
||||||
(getUserById as jest.Mock).mockImplementationOnce(() =>
|
(searchData as jest.Mock).mockImplementationOnce(() =>
|
||||||
Promise.resolve({
|
Promise.resolve(mockSearchAPIResponse)
|
||||||
owns: [
|
|
||||||
{
|
|
||||||
id: '1',
|
|
||||||
name: 'test 1',
|
|
||||||
fullyQualifiedName: 'test-1',
|
|
||||||
type: 'table',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '2',
|
|
||||||
name: 'test 2',
|
|
||||||
fullyQualifiedName: 'test-2',
|
|
||||||
type: 'table',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
})
|
|
||||||
);
|
);
|
||||||
act(() => {
|
act(() => {
|
||||||
render(
|
render(
|
||||||
@ -114,22 +138,7 @@ describe('MyDataWidget component', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should render table names', async () => {
|
it('should render table names', async () => {
|
||||||
(getUserById as jest.Mock).mockResolvedValueOnce({
|
(searchData as jest.Mock).mockResolvedValueOnce(mockSearchAPIResponse);
|
||||||
owns: [
|
|
||||||
{
|
|
||||||
id: '1',
|
|
||||||
name: 'test 1',
|
|
||||||
fullyQualifiedName: 'test-1',
|
|
||||||
type: 'table',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: '2',
|
|
||||||
name: 'test 2',
|
|
||||||
fullyQualifiedName: 'test-2',
|
|
||||||
type: 'table',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
});
|
|
||||||
act(() => {
|
act(() => {
|
||||||
render(
|
render(
|
||||||
<MemoryRouter>
|
<MemoryRouter>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user