mirror of
				https://github.com/open-metadata/OpenMetadata.git
				synced 2025-11-04 12:36:23 +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