diff --git a/catalog-rest-service/src/main/resources/ui/src/components/common/LoadMorePagination/LoadMorePagination.tsx b/catalog-rest-service/src/main/resources/ui/src/components/common/LoadMorePagination/LoadMorePagination.tsx new file mode 100644 index 00000000000..d72b2040037 --- /dev/null +++ b/catalog-rest-service/src/main/resources/ui/src/components/common/LoadMorePagination/LoadMorePagination.tsx @@ -0,0 +1,57 @@ +import { LoadingState } from 'Models'; +import React from 'react'; +import { Button } from '../../buttons/Button/Button'; +import Loader from '../../Loader/Loader'; + +type LoadMorePaginationProps = { + isLoading: boolean; + showLoadingText?: boolean; + status: LoadingState; + buttonText: string; + handleClick: () => void; +}; + +const LoadMorePagination = ({ + isLoading, + status, + buttonText, + showLoadingText, + handleClick, +}: LoadMorePaginationProps) => { + return ( + <> + {isLoading ? ( + + + {showLoadingText && Loading} + + ) : status === 'success' ? ( + + + + ) : ( + + {buttonText} + + )} + > + ); +}; + +export default LoadMorePagination; diff --git a/catalog-rest-service/src/main/resources/ui/src/interface/types.d.ts b/catalog-rest-service/src/main/resources/ui/src/interface/types.d.ts index 906d6ee6975..f3bc78a3e7e 100644 --- a/catalog-rest-service/src/main/resources/ui/src/interface/types.d.ts +++ b/catalog-rest-service/src/main/resources/ui/src/interface/types.d.ts @@ -118,8 +118,11 @@ declare module 'Models' { export type Paging = { after: string; before: string; + total?: number; }; + export type LoadingState = 'initial' | 'waiting' | 'success'; + export type TableDetail = { description: string; name: string; diff --git a/catalog-rest-service/src/main/resources/ui/src/pages/services/index.tsx b/catalog-rest-service/src/main/resources/ui/src/pages/services/index.tsx index e9ef0e05b45..13a113e42f5 100644 --- a/catalog-rest-service/src/main/resources/ui/src/pages/services/index.tsx +++ b/catalog-rest-service/src/main/resources/ui/src/pages/services/index.tsx @@ -17,8 +17,14 @@ import { AxiosError, AxiosResponse } from 'axios'; import classNames from 'classnames'; -import { isNull, lowerCase } from 'lodash'; -import { ServiceCollection, ServiceData, ServiceTypes } from 'Models'; +import { isNil, isNull, lowerCase } from 'lodash'; +import { + LoadingState, + Paging, + ServiceCollection, + ServiceData, + ServiceTypes, +} from 'Models'; import React, { useEffect, useState } from 'react'; import { Link } from 'react-router-dom'; import { @@ -29,6 +35,7 @@ import { updateService, } from '../../axiosAPIs/serviceAPI'; import { Button } from '../../components/buttons/Button/Button'; +import LoadMorePagination from '../../components/common/LoadMorePagination/LoadMorePagination'; import NonAdminAction from '../../components/common/non-admin-action/NonAdminAction'; import RichTextEditorPreviewer from '../../components/common/rich-text-editor/RichTextEditorPreviewer'; import Searchbar from '../../components/common/searchbar/Searchbar'; @@ -43,6 +50,7 @@ import { import ConfirmationModal from '../../components/Modals/ConfirmationModal/ConfirmationModal'; import { getServiceDetailsPath, + pagingObject, TITLE_FOR_NON_ADMIN_ACTION, } from '../../constants/constants'; import { @@ -50,6 +58,7 @@ import { NoDataFoundPlaceHolder, servicesDisplayName, } from '../../constants/services.const'; +import { CursorType } from '../../enums/pagination.enum'; import { ServiceCategory } from '../../enums/service.enum'; import { DashboardService, @@ -71,6 +80,13 @@ type ServiceRecord = { pipelineServices: Array; }; +type ServicePagingRecord = { + databaseServices: Paging; + messagingServices: Paging; + dashboardServices: Paging; + pipelineServices: Paging; +}; + export type ApiData = { description: string; href: string; @@ -92,6 +108,12 @@ const ServicesPage = () => { }); const [serviceName, setServiceName] = useState('databaseServices'); + const [paging, setPaging] = useState({ + databaseServices: pagingObject, + messagingServices: pagingObject, + dashboardServices: pagingObject, + pipelineServices: pagingObject, + }); const [services, setServices] = useState({ databaseServices: [], messagingServices: [], @@ -102,6 +124,8 @@ const ServicesPage = () => { const [editData, setEditData] = useState(); const [isLoading, setIsLoading] = useState(false); const [searchText, setSearchText] = useState(''); + const [currentTabTotalCount, setCurrentTabTotalCount] = useState(0); + const [servicesCount, setServicesCount] = useState({ databaseServices: 0, messagingServices: 0, @@ -109,6 +133,9 @@ const ServicesPage = () => { pipelineServices: 0, }); + const [isLoadingMore, setIsLoadingMore] = useState(false); + const [status, setStatus] = useState('initial'); + const updateServiceList = ( allServiceCollectionArr: Array ) => { @@ -122,24 +149,34 @@ const ServicesPage = () => { (result: PromiseSettledResult[]) => { if (result.length) { let serviceArr = []; + let servicePagingArr = []; const serviceRecord = {} as ServiceRecord; + const servicePaging = {} as ServicePagingRecord; serviceArr = result.map((service) => service.status === 'fulfilled' ? service.value?.data?.data : [] ); + servicePagingArr = result.map((service) => + service.status === 'fulfilled' ? service.value?.data?.paging : {} + ); for (let i = 0; i < serviceArr.length; i++) { serviceRecord[allServiceCollectionArr[i].value as ServiceTypes] = serviceArr[i]; + servicePaging[allServiceCollectionArr[i].value as ServiceTypes] = + servicePagingArr[i]; } setServices(serviceRecord); + + setPaging(servicePaging); setServicesCount({ - databaseServices: serviceRecord.databaseServices.length, - messagingServices: serviceRecord.messagingServices.length, - dashboardServices: serviceRecord.dashboardServices.length, - pipelineServices: serviceRecord.pipelineServices.length, + databaseServices: servicePaging.databaseServices.total || 0, + messagingServices: servicePaging.messagingServices.total || 0, + dashboardServices: servicePaging.dashboardServices.total || 0, + pipelineServices: servicePaging.pipelineServices.total || 0, }); setServiceList( serviceRecord[serviceName] as unknown as Array ); + setCurrentTabTotalCount(servicePaging[serviceName].total || 0); } setIsLoading(false); } @@ -308,7 +345,7 @@ const ServicesPage = () => { setSearchText(''); setServicesCount({ ...servicesCount, - [serviceName]: services[serviceName].length, + [serviceName]: currentTabTotalCount, }); setServiceName(tabName); setServiceList(services[tabName] as unknown as Array); @@ -382,6 +419,35 @@ const ServicesPage = () => { } }; + const pagingHandler = (cursorType: string) => { + setIsLoadingMore(true); + setStatus('waiting'); + const currentServicePaging = paging[serviceName]; + const pagingString = `${serviceName}?${cursorType}=${ + currentServicePaging[cursorType as keyof Paging] + }`; + getServices(pagingString) + .then((result: AxiosResponse) => { + const currentServices = [...services[serviceName], ...result.data.data]; + setServiceList(currentServices); + + setServices({ + ...services, + [serviceName]: currentServices, + }); + + setPaging({ + ...paging, + [serviceName]: result.data.paging, + }); + setStatus('success'); + }) + .finally(() => { + setIsLoadingMore(false); + setStatus('initial'); + }); + }; + useEffect(() => { // fetch all service collection setIsLoading(true); @@ -406,6 +472,10 @@ const ServicesPage = () => { }); }, []); + useEffect(() => { + setCurrentTabTotalCount(servicesCount[serviceName]); + }, [serviceName]); + return ( <> {!isLoading ? ( @@ -458,7 +528,7 @@ const ServicesPage = () => { {serviceList.length ? ( {serviceList.map((service, index) => ( { )} + {!isNil(paging[serviceName].after) && ( + + pagingHandler(CursorType.AFTER)} + isLoading={isLoadingMore} + status={status} + /> + + )} + {isModalOpen && (