Fix: loading and entity count bug fix for Landing page (#955)

* resolved infinite loading bug onClick of active tab for landing page

* fix count and loading issue for landing page

* move const value to MyData.const file

* move MyDataHeader component to its seprate folder and miner bug fix in MyDataPage component

* add error handler at page level
This commit is contained in:
Shailesh Parmar 2021-10-28 13:43:40 +05:30 committed by GitHub
parent 328e3da12d
commit e52dbacfd8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 120 additions and 107 deletions

View File

@ -16,16 +16,13 @@
*/
import { isEmpty } from 'lodash';
import { Bucket, FormatedTableData, Sterm } from 'Models';
import { FormatedTableData } from 'Models';
import React, { useEffect, useRef, useState } from 'react';
import { Ownership } from '../../enums/mydata.enum';
import { formatDataResponse } from '../../utils/APIUtils';
import { getCurrentUserId } from '../../utils/CommonUtils';
import { getEntityCountByService } from '../../utils/ServiceUtils';
import ErrorPlaceHolderES from '../common/error-with-placeholder/ErrorPlaceHolderES';
import PageContainer from '../containers/PageContainer';
import Loader from '../Loader/Loader';
import MyDataHeader from '../my-data/MyDataHeader';
import MyDataHeader from '../MyDataHeader/MyDataHeader.component';
import RecentlyViewed from '../recently-viewed/RecentlyViewed';
import SearchedData from '../searched-data/SearchedData';
import { MyDataProps } from './MyData.interface';
@ -35,21 +32,16 @@ const MyData: React.FC<MyDataProps> = ({
userDetails,
searchResult,
fetchData,
error,
entityCounts,
}: MyDataProps): React.ReactElement => {
const [data, setData] = useState<Array<FormatedTableData>>([]);
const [currentPage, setCurrentPage] = useState<number>(1);
const [totalNumberOfValue, setTotalNumberOfValues] = useState<number>(0);
const [isLoading, setIsLoading] = useState<boolean>(true);
const [isEntityLoading, setIsEntityLoading] = useState<boolean>(true);
const [currentTab, setCurrentTab] = useState<number>(1);
const [filter, setFilter] = useState<string>('');
const [aggregations, setAggregations] = useState<Record<string, Sterm>>();
const [searchIndex] = useState<string>(
'dashboard_search_index,topic_search_index,table_search_index,pipeline_search_index'
);
const isMounted = useRef<boolean>(false);
const setAssetCount = useRef<boolean>(true);
const isMounted = useRef(false);
const getActiveTabClass = (tab: number) => {
return tab === currentTab ? 'active' : '';
@ -68,21 +60,6 @@ const MyData: React.FC<MyDataProps> = ({
return `${filter}:${getCurrentUserId()}`;
};
const fetchTableData = () => {
if (!isEntityLoading) {
setIsLoading(true);
}
fetchData({
queryString: '',
from: currentPage,
filters: filter ? getFilters() : '',
sortField: '',
sortOrder: '',
searchIndex: searchIndex,
});
};
const handleTabChange = (tab: number, filter: string) => {
if (currentTab !== tab) {
setIsEntityLoading(true);
@ -127,8 +104,16 @@ const MyData: React.FC<MyDataProps> = ({
};
useEffect(() => {
setAssetCount.current = !isMounted.current;
fetchTableData();
if (isMounted.current) {
setIsEntityLoading(true);
fetchData({
queryString: '',
from: currentPage,
filters: filter ? getFilters() : '',
sortField: '',
sortOrder: '',
});
}
}, [currentPage, filter]);
useEffect(() => {
@ -137,22 +122,12 @@ const MyData: React.FC<MyDataProps> = ({
if (hits.length > 0) {
setTotalNumberOfValues(searchResult.data.hits.total.value);
setData(formatDataResponse(hits));
if (setAssetCount.current) {
setAggregations(searchResult.data.aggregations);
setAssetCount.current = false;
}
setIsLoading(false);
setIsEntityLoading(false);
} else {
setData([]);
setTotalNumberOfValues(0);
setIsLoading(false);
setIsEntityLoading(false);
}
} else {
setIsLoading(false);
setIsEntityLoading(false);
}
setIsEntityLoading(false);
}, [searchResult]);
useEffect(() => {
@ -160,41 +135,27 @@ const MyData: React.FC<MyDataProps> = ({
}, []);
return (
<>
{error ? (
<ErrorPlaceHolderES errorMessage={error} type="error" />
) : (
<>
{isLoading ? (
<Loader />
) : (
<PageContainer>
<div className="container-fluid" data-testid="fluid-container">
<MyDataHeader
countServices={countServices}
entityCounts={getEntityCountByService(
aggregations?.['sterms#Service']?.buckets as Bucket[]
)}
/>
{getTabs()}
<SearchedData
showOnboardingTemplate
currentPage={currentPage}
data={data}
isLoading={isEntityLoading}
paginate={paginate}
searchText="*"
showOnlyChildren={currentTab === 1}
showResultCount={filter && data.length > 0 ? true : false}
totalValue={totalNumberOfValue}>
{currentTab === 1 ? <RecentlyViewed /> : null}
</SearchedData>
</div>
</PageContainer>
)}
</>
)}
</>
<PageContainer>
<div className="container-fluid" data-testid="fluid-container">
<MyDataHeader
countServices={countServices}
entityCounts={entityCounts}
/>
{getTabs()}
<SearchedData
showOnboardingTemplate
currentPage={currentPage}
data={data}
isLoading={isEntityLoading}
paginate={paginate}
searchText="*"
showOnlyChildren={currentTab === 1}
showResultCount={filter && data.length > 0 ? true : false}
totalValue={totalNumberOfValue}>
{currentTab === 1 ? <RecentlyViewed /> : null}
</SearchedData>
</div>
</PageContainer>
);
};

View File

@ -1,10 +1,10 @@
import { SearchDataFunctionType, SearchResponse } from 'Models';
import { EntityCounts, SearchDataFunctionType, SearchResponse } from 'Models';
import { User } from '../../generated/entity/teams/user';
export interface MyDataProps {
countServices: number;
userDetails: User;
error: string;
searchResult: SearchResponse | undefined;
fetchData: (value: SearchDataFunctionType) => void;
entityCounts: EntityCounts;
}

View File

@ -237,7 +237,7 @@ jest.mock('../../components/recently-viewed/RecentlyViewed', () => {
return jest.fn().mockReturnValue(<p>RecentlyViewed</p>);
});
jest.mock('../../components/my-data/MyDataHeader', () => {
jest.mock('../MyDataHeader/MyDataHeader.component', () => {
return jest.fn().mockReturnValue(<p>MyDataHeader</p>);
});
@ -258,7 +258,12 @@ describe('Test MyData page', () => {
const { container } = render(
<MyDataPage
countServices={0}
error=""
entityCounts={{
tableCount: 10,
topicCount: 5,
dashboardCount: 8,
pipelineCount: 1,
}}
fetchData={fetchData}
searchResult={mockData as unknown as SearchResponse}
userDetails={mockUserDetails as unknown as User}

View File

@ -17,6 +17,7 @@
import classNames from 'classnames';
import { observer } from 'mobx-react';
import { EntityCounts } from 'Models';
import React, { FunctionComponent, useEffect, useState } from 'react';
import { Link } from 'react-router-dom';
import AppState from '../../AppState';
@ -24,12 +25,7 @@ import SVGIcons, { Icons } from '../../utils/SvgUtils';
type Props = {
countServices: number;
entityCounts: {
tableCount: number;
topicCount: number;
dashboardCount: number;
pipelineCount: number;
};
entityCounts: EntityCounts;
};
type Summary = {
icon: string;

View File

@ -18,7 +18,7 @@
import { getByTestId, getByText, render } from '@testing-library/react';
import React from 'react';
import { MemoryRouter } from 'react-router';
import MyDataHeader from './MyDataHeader';
import MyDataHeader from './MyDataHeader.component';
describe('Test MyDataHeader Component', () => {
it('Component should render', () => {

View File

@ -19,6 +19,16 @@ import { FilterObject } from 'Models';
import { getCurrentUserId } from '../utils/CommonUtils';
import { getFilterString } from '../utils/FilterUtils';
export const myDataSearchIndex =
'dashboard_search_index,topic_search_index,table_search_index,pipeline_search_index';
export const myDataEntityCounts = {
tableCount: 0,
topicCount: 0,
dashboardCount: 0,
pipelineCount: 0,
};
export const myDataFilterType = [
{ key: 'Owned', value: 'owner' },
{ key: 'Following', value: 'followers' },

View File

@ -331,7 +331,14 @@ declare module 'Models' {
filters: string;
sortField: string;
sortOrder: string;
searchIndex: string;
searchIndex?: string;
};
export type EntityCounts = {
tableCount: number;
topicCount: number;
dashboardCount: number;
pipelineCount: number;
};
// topic interface start

View File

@ -16,25 +16,35 @@
*/
import { AxiosError } from 'axios';
import { isUndefined } from 'lodash';
import { observer } from 'mobx-react';
import { SearchDataFunctionType, SearchResponse } from 'Models';
import { EntityCounts, SearchDataFunctionType, SearchResponse } from 'Models';
import React, { useEffect, useState } from 'react';
import AppState from '../../AppState';
import { searchData } from '../../axiosAPIs/miscAPI';
import ErrorPlaceHolderES from '../../components/common/error-with-placeholder/ErrorPlaceHolderES';
import Loader from '../../components/Loader/Loader';
import MyData from '../../components/MyData/MyData.component';
import { ERROR500, PAGE_SIZE } from '../../constants/constants';
import {
myDataEntityCounts,
myDataSearchIndex,
} from '../../constants/Mydata.constants';
import useToastContext from '../../hooks/useToastContext';
import { getAllServices } from '../../utils/ServiceUtils';
import {
getAllServices,
getEntityCountByService,
} from '../../utils/ServiceUtils';
const MyDataPage = () => {
const showToast = useToastContext();
const [error, setError] = useState<string>('');
const [countServices, setCountServices] = useState<number>(0);
const [countServices, setCountServices] = useState<number>();
const [isLoading, setIsLoading] = useState<boolean>(true);
const [searchResult, setSearchResult] = useState<SearchResponse>();
const [entityCounts, setEntityCounts] = useState<EntityCounts>();
const fetchData = (value: SearchDataFunctionType) => {
const fetchData = (value: SearchDataFunctionType, fetchService = false) => {
searchData(
value.queryString,
value.from,
@ -42,10 +52,17 @@ const MyDataPage = () => {
value.filters,
value.sortField,
value.sortOrder,
value.searchIndex
myDataSearchIndex
)
.then((res: SearchResponse) => {
setSearchResult(res);
if (isUndefined(entityCounts)) {
setEntityCounts(
getEntityCountByService(
res.data.aggregations?.['sterms#Service']?.buckets
)
);
}
})
.catch((err: AxiosError) => {
setError(err.response?.data?.responseMessage);
@ -53,28 +70,45 @@ const MyDataPage = () => {
variant: 'error',
body: err.response?.data?.responseMessage ?? ERROR500,
});
setEntityCounts(myDataEntityCounts);
});
if (fetchService) {
getAllServices()
.then((res) => setCountServices(res.length))
.catch(() => setCountServices(0));
}
setIsLoading(false);
};
useEffect(() => {
getAllServices()
.then((res) => setCountServices(res.length))
.catch(() => setCountServices(0));
setIsLoading(false);
fetchData(
{
queryString: '',
from: 1,
filters: '',
sortField: '',
sortOrder: '',
},
isUndefined(countServices)
);
}, []);
return (
<div data-testid="my-data-page-conatiner">
{isLoading ? (
<Loader />
{countServices && entityCounts && !isLoading ? (
error ? (
<ErrorPlaceHolderES errorMessage={error} type="error" />
) : (
<MyData
countServices={countServices}
entityCounts={entityCounts}
fetchData={fetchData}
searchResult={searchResult}
userDetails={AppState.userDetails}
/>
)
) : (
<MyData
countServices={countServices}
error={error}
fetchData={fetchData}
searchResult={searchResult}
userDetails={AppState.userDetails}
/>
<Loader />
)}
</div>
);

View File

@ -19,7 +19,7 @@ import { findByTestId, render } from '@testing-library/react';
import React from 'react';
import MyDataPageComponent from './MyDataPage.component';
jest.mock('../../components/LandingPage/MyData.component', () => {
jest.mock('../../components/MyData/MyData.component', () => {
return jest.fn().mockReturnValue(<p>Mydata component</p>);
});