mirror of
				https://github.com/open-metadata/OpenMetadata.git
				synced 2025-10-31 10:39:30 +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
	 Aniket Katkar
						Aniket Katkar