mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-08-31 20:51:26 +00:00
feat(ui): new pagination with page number and page size (#10921)
* feat(ui): new pagination with page number and page size * fix unit tests * fix unit tests * fix pagination issue --------- Co-authored-by: Shailesh Parmar <shailesh.parmar.webdev@gmail.com>
This commit is contained in:
parent
6b8b9a179b
commit
fa93a37fcd
@ -27,7 +27,6 @@ import unique from 'fork-ts-checker-webpack-plugin/lib/utils/array/unique';
|
|||||||
import {
|
import {
|
||||||
isEmpty,
|
isEmpty,
|
||||||
isNil,
|
isNil,
|
||||||
isNumber,
|
|
||||||
isString,
|
isString,
|
||||||
isUndefined,
|
isUndefined,
|
||||||
lowerCase,
|
lowerCase,
|
||||||
@ -81,7 +80,6 @@ const Explore: React.FC<ExploreProps> = ({
|
|||||||
onChangeSortValue,
|
onChangeSortValue,
|
||||||
onChangeShowDeleted,
|
onChangeShowDeleted,
|
||||||
showDeleted,
|
showDeleted,
|
||||||
page = 1,
|
|
||||||
onChangePage = noop,
|
onChangePage = noop,
|
||||||
loading,
|
loading,
|
||||||
quickFilters,
|
quickFilters,
|
||||||
@ -400,19 +398,12 @@ const Explore: React.FC<ExploreProps> = ({
|
|||||||
<SearchedData
|
<SearchedData
|
||||||
isFilterSelected
|
isFilterSelected
|
||||||
showResultCount
|
showResultCount
|
||||||
currentPage={page}
|
|
||||||
data={searchResults?.hits.hits ?? []}
|
data={searchResults?.hits.hits ?? []}
|
||||||
handleSummaryPanelDisplay={handleSummaryPanelDisplay}
|
handleSummaryPanelDisplay={handleSummaryPanelDisplay}
|
||||||
isSummaryPanelVisible={showSummaryPanel}
|
isSummaryPanelVisible={showSummaryPanel}
|
||||||
paginate={(value) => {
|
|
||||||
if (isNumber(value)) {
|
|
||||||
onChangePage(value);
|
|
||||||
} else if (!isNaN(Number.parseInt(value))) {
|
|
||||||
onChangePage(Number.parseInt(value));
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
selectedEntityId={entityDetails?.id || ''}
|
selectedEntityId={entityDetails?.id || ''}
|
||||||
totalValue={searchResults?.hits.total.value ?? 0}
|
totalValue={searchResults?.hits.total.value ?? 0}
|
||||||
|
onPaginationChange={onChangePage}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Loader />
|
<Loader />
|
||||||
|
@ -82,8 +82,7 @@ export interface ExploreProps {
|
|||||||
showDeleted: boolean;
|
showDeleted: boolean;
|
||||||
onChangeShowDeleted: (showDeleted: boolean) => void;
|
onChangeShowDeleted: (showDeleted: boolean) => void;
|
||||||
|
|
||||||
page?: number;
|
onChangePage?: (page: number, size?: number) => void;
|
||||||
onChangePage?: (page: number) => void;
|
|
||||||
|
|
||||||
loading?: boolean;
|
loading?: boolean;
|
||||||
|
|
||||||
|
@ -73,9 +73,8 @@ export interface SearchedDataProps {
|
|||||||
children?: ReactNode;
|
children?: ReactNode;
|
||||||
selectedEntityId: string;
|
selectedEntityId: string;
|
||||||
data: SearchHitBody<ExploreSearchIndex, SourceType>[];
|
data: SearchHitBody<ExploreSearchIndex, SourceType>[];
|
||||||
currentPage: number;
|
|
||||||
isLoading?: boolean;
|
isLoading?: boolean;
|
||||||
paginate: (value: string | number) => void;
|
onPaginationChange: (value: number, pageSize?: number) => void;
|
||||||
totalValue: number;
|
totalValue: number;
|
||||||
fetchLeftPanel?: () => ReactNode;
|
fetchLeftPanel?: () => ReactNode;
|
||||||
isSummaryPanelVisible: boolean;
|
isSummaryPanelVisible: boolean;
|
||||||
|
@ -106,7 +106,7 @@ const MOCK_PROPS = {
|
|||||||
currentPage: 0,
|
currentPage: 0,
|
||||||
data: mockData,
|
data: mockData,
|
||||||
handleSummaryPanelDisplay: mockHandleSummaryPanelDisplay,
|
handleSummaryPanelDisplay: mockHandleSummaryPanelDisplay,
|
||||||
paginate: mockPaginate,
|
onPaginationChange: mockPaginate,
|
||||||
selectedEntityId: 'name1',
|
selectedEntityId: 'name1',
|
||||||
totalValue: 10,
|
totalValue: 10,
|
||||||
};
|
};
|
||||||
@ -145,19 +145,6 @@ describe('Test SearchedData Component', () => {
|
|||||||
expect(getByText(container, /hello world/i)).toBeInTheDocument();
|
expect(getByText(container, /hello world/i)).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Pagination Should be there if data is more than 10 count', () => {
|
|
||||||
const { container } = render(
|
|
||||||
<SearchedData {...MOCK_PROPS} totalValue={11}>
|
|
||||||
<p>hello world</p>
|
|
||||||
</SearchedData>,
|
|
||||||
{
|
|
||||||
wrapper: MemoryRouter,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(getByText(container, /Pagination/i)).toBeInTheDocument();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Onboarding component should display if there is showOnboardingTemplate is true', () => {
|
it('Onboarding component should display if there is showOnboardingTemplate is true', () => {
|
||||||
const { container } = render(
|
const { container } = render(
|
||||||
<SearchedData
|
<SearchedData
|
||||||
|
@ -11,18 +11,17 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { Pagination } from 'antd';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { ELASTICSEARCH_ERROR_PLACEHOLDER_TYPE } from 'enums/common.enum';
|
import { ELASTICSEARCH_ERROR_PLACEHOLDER_TYPE } from 'enums/common.enum';
|
||||||
import { isUndefined } from 'lodash';
|
import { isNumber, isUndefined } from 'lodash';
|
||||||
import PropTypes from 'prop-types';
|
import Qs from 'qs';
|
||||||
import React from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { getEntityName } from 'utils/EntityUtils';
|
import { getEntityName } from 'utils/EntityUtils';
|
||||||
import { PAGE_SIZE } from '../../constants/constants';
|
import { PAGE_SIZE } from '../../constants/constants';
|
||||||
import { MAX_RESULT_HITS } from '../../constants/explore.constants';
|
import { MAX_RESULT_HITS } from '../../constants/explore.constants';
|
||||||
import { Paging } from '../../generated/type/paging';
|
|
||||||
import { pluralize } from '../../utils/CommonUtils';
|
import { pluralize } from '../../utils/CommonUtils';
|
||||||
import ErrorPlaceHolderES from '../common/error-with-placeholder/ErrorPlaceHolderES';
|
import ErrorPlaceHolderES from '../common/error-with-placeholder/ErrorPlaceHolderES';
|
||||||
import NextPrevious from '../common/next-previous/NextPrevious';
|
|
||||||
import TableDataCardV2 from '../common/table-data-card-v2/TableDataCardV2';
|
import TableDataCardV2 from '../common/table-data-card-v2/TableDataCardV2';
|
||||||
import Loader from '../Loader/Loader';
|
import Loader from '../Loader/Loader';
|
||||||
import Onboarding from '../onboarding/Onboarding';
|
import Onboarding from '../onboarding/Onboarding';
|
||||||
@ -38,9 +37,8 @@ const ASSETS_NAME = [
|
|||||||
const SearchedData: React.FC<SearchedDataProps> = ({
|
const SearchedData: React.FC<SearchedDataProps> = ({
|
||||||
children,
|
children,
|
||||||
data,
|
data,
|
||||||
currentPage,
|
|
||||||
isLoading = false,
|
isLoading = false,
|
||||||
paginate,
|
onPaginationChange,
|
||||||
showResultCount = false,
|
showResultCount = false,
|
||||||
showOnboardingTemplate = false,
|
showOnboardingTemplate = false,
|
||||||
showOnlyChildren = false,
|
showOnlyChildren = false,
|
||||||
@ -51,7 +49,7 @@ const SearchedData: React.FC<SearchedDataProps> = ({
|
|||||||
selectedEntityId,
|
selectedEntityId,
|
||||||
handleSummaryPanelDisplay,
|
handleSummaryPanelDisplay,
|
||||||
}) => {
|
}) => {
|
||||||
const highlightSearchResult = () => {
|
const searchResultCards = useMemo(() => {
|
||||||
return data.map(({ _source: table, highlight }, index) => {
|
return data.map(({ _source: table, highlight }, index) => {
|
||||||
let tDesc = table.description ?? '';
|
let tDesc = table.description ?? '';
|
||||||
const highLightedTexts = highlight?.description || [];
|
const highLightedTexts = highlight?.description || [];
|
||||||
@ -108,7 +106,12 @@ const SearchedData: React.FC<SearchedDataProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
};
|
}, [
|
||||||
|
data,
|
||||||
|
isSummaryPanelVisible,
|
||||||
|
handleSummaryPanelDisplay,
|
||||||
|
selectedEntityId,
|
||||||
|
]);
|
||||||
|
|
||||||
const ResultCount = () => {
|
const ResultCount = () => {
|
||||||
if (showResultCount && (isFilterSelected || searchText)) {
|
if (showResultCount && (isFilterSelected || searchText)) {
|
||||||
@ -122,6 +125,16 @@ const SearchedData: React.FC<SearchedDataProps> = ({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const { page, size } = useMemo(
|
||||||
|
() =>
|
||||||
|
Qs.parse(
|
||||||
|
location.search.startsWith('?')
|
||||||
|
? location.search.substr(1)
|
||||||
|
: location.search
|
||||||
|
),
|
||||||
|
[location.search]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
@ -138,17 +151,20 @@ const SearchedData: React.FC<SearchedDataProps> = ({
|
|||||||
<div
|
<div
|
||||||
className="tw-grid tw-grid-rows-1 tw-grid-cols-1"
|
className="tw-grid tw-grid-rows-1 tw-grid-cols-1"
|
||||||
data-testid="search-results">
|
data-testid="search-results">
|
||||||
{highlightSearchResult()}
|
{searchResultCards}
|
||||||
{totalValue > PAGE_SIZE && data.length > 0 && (
|
<Pagination
|
||||||
<NextPrevious
|
hideOnSinglePage
|
||||||
isNumberBased
|
className="text-center"
|
||||||
currentPage={currentPage}
|
current={isNumber(Number(page)) ? Number(page) : 1}
|
||||||
pageSize={PAGE_SIZE}
|
pageSize={
|
||||||
paging={{} as Paging}
|
size && isNumber(Number(size))
|
||||||
pagingHandler={paginate}
|
? Number(size)
|
||||||
totalCount={totalValue}
|
: PAGE_SIZE
|
||||||
/>
|
}
|
||||||
)}
|
pageSizeOptions={[10, 25, 50]}
|
||||||
|
total={totalValue}
|
||||||
|
onChange={onPaginationChange}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<Onboarding />
|
<Onboarding />
|
||||||
@ -171,16 +187,4 @@ const SearchedData: React.FC<SearchedDataProps> = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
SearchedData.propTypes = {
|
|
||||||
children: PropTypes.element,
|
|
||||||
data: PropTypes.array.isRequired,
|
|
||||||
currentPage: PropTypes.number.isRequired,
|
|
||||||
isLoading: PropTypes.bool,
|
|
||||||
paginate: PropTypes.func.isRequired,
|
|
||||||
showResultCount: PropTypes.bool,
|
|
||||||
showOnboardingTemplate: PropTypes.bool,
|
|
||||||
totalValue: PropTypes.number.isRequired,
|
|
||||||
fetchLeftPanel: PropTypes.func,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SearchedData;
|
export default SearchedData;
|
||||||
|
@ -119,8 +119,10 @@ const ExplorePage: FunctionComponent = () => {
|
|||||||
[facetFilters]
|
[facetFilters]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handlePageChange: ExploreProps['onChangePage'] = (page) => {
|
const handlePageChange: ExploreProps['onChangePage'] = (page, size) => {
|
||||||
history.push({ search: Qs.stringify({ ...parsedSearch, page }) });
|
history.push({
|
||||||
|
search: Qs.stringify({ ...parsedSearch, page, size: size ?? PAGE_SIZE }),
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Filters that can be common for all the Entities Ex. Tables, Topics, etc.
|
// Filters that can be common for all the Entities Ex. Tables, Topics, etc.
|
||||||
@ -234,9 +236,18 @@ const ExplorePage: FunctionComponent = () => {
|
|||||||
return Number.parseInt(pageParam);
|
return Number.parseInt(pageParam);
|
||||||
}, [parsedSearch.page]);
|
}, [parsedSearch.page]);
|
||||||
|
|
||||||
|
const size = useMemo(() => {
|
||||||
|
const sizeParam = parsedSearch.size;
|
||||||
|
if (!isString(sizeParam) || isNaN(Number.parseInt(sizeParam))) {
|
||||||
|
return PAGE_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Number.parseInt(sizeParam);
|
||||||
|
}, [parsedSearch.size]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
handlePageChange(page);
|
handlePageChange(page, size);
|
||||||
}, [page]);
|
}, [page, size]);
|
||||||
|
|
||||||
const showDeleted = useMemo(() => {
|
const showDeleted = useMemo(() => {
|
||||||
const showDeletedParam = parsedSearch.showDeleted;
|
const showDeletedParam = parsedSearch.showDeleted;
|
||||||
@ -305,7 +316,7 @@ const ExplorePage: FunctionComponent = () => {
|
|||||||
sortField: sortValue,
|
sortField: sortValue,
|
||||||
sortOrder,
|
sortOrder,
|
||||||
pageNumber: page,
|
pageNumber: page,
|
||||||
pageSize: PAGE_SIZE,
|
pageSize: size,
|
||||||
includeDeleted: showDeleted,
|
includeDeleted: showDeleted,
|
||||||
})
|
})
|
||||||
.then((res) => res)
|
.then((res) => res)
|
||||||
@ -373,6 +384,7 @@ const ExplorePage: FunctionComponent = () => {
|
|||||||
elasticsearchQueryFilter,
|
elasticsearchQueryFilter,
|
||||||
searchIndex,
|
searchIndex,
|
||||||
page,
|
page,
|
||||||
|
size,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const handleAdvanceSearchQuickFiltersChange = useCallback(
|
const handleAdvanceSearchQuickFiltersChange = useCallback(
|
||||||
@ -422,7 +434,6 @@ const ExplorePage: FunctionComponent = () => {
|
|||||||
aggregations={updatedAggregations}
|
aggregations={updatedAggregations}
|
||||||
facetFilters={facetFilters}
|
facetFilters={facetFilters}
|
||||||
loading={isLoading}
|
loading={isLoading}
|
||||||
page={page}
|
|
||||||
quickFilters={advancesSearchQuickFilters}
|
quickFilters={advancesSearchQuickFilters}
|
||||||
searchIndex={searchIndex}
|
searchIndex={searchIndex}
|
||||||
searchResults={searchResults}
|
searchResults={searchResults}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user