mirror of
https://github.com/open-metadata/OpenMetadata.git
synced 2025-11-16 10:53:31 +00:00
Feat: Added Pagination for services page (#1334)
* change ui to support paging for services page * fix count issue on tab change * change pagine with load more btn with micro interaction * made seprate component for load more pagination button * make seprate type for loading status and miner fix * miner fix
This commit is contained in:
parent
499c9c546f
commit
f6dfc62a4b
@ -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 ? (
|
||||||
|
<Button
|
||||||
|
disabled
|
||||||
|
className="tw-h-10"
|
||||||
|
size="regular"
|
||||||
|
theme="primary"
|
||||||
|
variant="contained">
|
||||||
|
<Loader size="small" type="white" />
|
||||||
|
{showLoadingText && <span className="tw-pl-1.5">Loading</span>}
|
||||||
|
</Button>
|
||||||
|
) : status === 'success' ? (
|
||||||
|
<Button
|
||||||
|
disabled
|
||||||
|
className="tw-h-10 disabled:tw-opacity-100"
|
||||||
|
size="regular"
|
||||||
|
theme="primary"
|
||||||
|
variant="contained">
|
||||||
|
<i aria-hidden="true" className="fa fa-check" />
|
||||||
|
</Button>
|
||||||
|
) : (
|
||||||
|
<Button
|
||||||
|
className="tw-h-10"
|
||||||
|
data-testid="saveManageTab"
|
||||||
|
size="regular"
|
||||||
|
theme="primary"
|
||||||
|
variant="contained"
|
||||||
|
onClick={handleClick}>
|
||||||
|
<span>{buttonText}</span>
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default LoadMorePagination;
|
||||||
@ -118,8 +118,11 @@ declare module 'Models' {
|
|||||||
export type Paging = {
|
export type Paging = {
|
||||||
after: string;
|
after: string;
|
||||||
before: string;
|
before: string;
|
||||||
|
total?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type LoadingState = 'initial' | 'waiting' | 'success';
|
||||||
|
|
||||||
export type TableDetail = {
|
export type TableDetail = {
|
||||||
description: string;
|
description: string;
|
||||||
name: string;
|
name: string;
|
||||||
|
|||||||
@ -17,8 +17,14 @@
|
|||||||
|
|
||||||
import { AxiosError, AxiosResponse } from 'axios';
|
import { AxiosError, AxiosResponse } from 'axios';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { isNull, lowerCase } from 'lodash';
|
import { isNil, isNull, lowerCase } from 'lodash';
|
||||||
import { ServiceCollection, ServiceData, ServiceTypes } from 'Models';
|
import {
|
||||||
|
LoadingState,
|
||||||
|
Paging,
|
||||||
|
ServiceCollection,
|
||||||
|
ServiceData,
|
||||||
|
ServiceTypes,
|
||||||
|
} from 'Models';
|
||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
@ -29,6 +35,7 @@ import {
|
|||||||
updateService,
|
updateService,
|
||||||
} from '../../axiosAPIs/serviceAPI';
|
} from '../../axiosAPIs/serviceAPI';
|
||||||
import { Button } from '../../components/buttons/Button/Button';
|
import { Button } from '../../components/buttons/Button/Button';
|
||||||
|
import LoadMorePagination from '../../components/common/LoadMorePagination/LoadMorePagination';
|
||||||
import NonAdminAction from '../../components/common/non-admin-action/NonAdminAction';
|
import NonAdminAction from '../../components/common/non-admin-action/NonAdminAction';
|
||||||
import RichTextEditorPreviewer from '../../components/common/rich-text-editor/RichTextEditorPreviewer';
|
import RichTextEditorPreviewer from '../../components/common/rich-text-editor/RichTextEditorPreviewer';
|
||||||
import Searchbar from '../../components/common/searchbar/Searchbar';
|
import Searchbar from '../../components/common/searchbar/Searchbar';
|
||||||
@ -43,6 +50,7 @@ import {
|
|||||||
import ConfirmationModal from '../../components/Modals/ConfirmationModal/ConfirmationModal';
|
import ConfirmationModal from '../../components/Modals/ConfirmationModal/ConfirmationModal';
|
||||||
import {
|
import {
|
||||||
getServiceDetailsPath,
|
getServiceDetailsPath,
|
||||||
|
pagingObject,
|
||||||
TITLE_FOR_NON_ADMIN_ACTION,
|
TITLE_FOR_NON_ADMIN_ACTION,
|
||||||
} from '../../constants/constants';
|
} from '../../constants/constants';
|
||||||
import {
|
import {
|
||||||
@ -50,6 +58,7 @@ import {
|
|||||||
NoDataFoundPlaceHolder,
|
NoDataFoundPlaceHolder,
|
||||||
servicesDisplayName,
|
servicesDisplayName,
|
||||||
} from '../../constants/services.const';
|
} from '../../constants/services.const';
|
||||||
|
import { CursorType } from '../../enums/pagination.enum';
|
||||||
import { ServiceCategory } from '../../enums/service.enum';
|
import { ServiceCategory } from '../../enums/service.enum';
|
||||||
import {
|
import {
|
||||||
DashboardService,
|
DashboardService,
|
||||||
@ -71,6 +80,13 @@ type ServiceRecord = {
|
|||||||
pipelineServices: Array<PipelineService>;
|
pipelineServices: Array<PipelineService>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type ServicePagingRecord = {
|
||||||
|
databaseServices: Paging;
|
||||||
|
messagingServices: Paging;
|
||||||
|
dashboardServices: Paging;
|
||||||
|
pipelineServices: Paging;
|
||||||
|
};
|
||||||
|
|
||||||
export type ApiData = {
|
export type ApiData = {
|
||||||
description: string;
|
description: string;
|
||||||
href: string;
|
href: string;
|
||||||
@ -92,6 +108,12 @@ const ServicesPage = () => {
|
|||||||
});
|
});
|
||||||
const [serviceName, setServiceName] =
|
const [serviceName, setServiceName] =
|
||||||
useState<ServiceTypes>('databaseServices');
|
useState<ServiceTypes>('databaseServices');
|
||||||
|
const [paging, setPaging] = useState<ServicePagingRecord>({
|
||||||
|
databaseServices: pagingObject,
|
||||||
|
messagingServices: pagingObject,
|
||||||
|
dashboardServices: pagingObject,
|
||||||
|
pipelineServices: pagingObject,
|
||||||
|
});
|
||||||
const [services, setServices] = useState<ServiceRecord>({
|
const [services, setServices] = useState<ServiceRecord>({
|
||||||
databaseServices: [],
|
databaseServices: [],
|
||||||
messagingServices: [],
|
messagingServices: [],
|
||||||
@ -102,6 +124,8 @@ const ServicesPage = () => {
|
|||||||
const [editData, setEditData] = useState<ServiceDataObj>();
|
const [editData, setEditData] = useState<ServiceDataObj>();
|
||||||
const [isLoading, setIsLoading] = useState<boolean>(false);
|
const [isLoading, setIsLoading] = useState<boolean>(false);
|
||||||
const [searchText, setSearchText] = useState('');
|
const [searchText, setSearchText] = useState('');
|
||||||
|
const [currentTabTotalCount, setCurrentTabTotalCount] = useState(0);
|
||||||
|
|
||||||
const [servicesCount, setServicesCount] = useState({
|
const [servicesCount, setServicesCount] = useState({
|
||||||
databaseServices: 0,
|
databaseServices: 0,
|
||||||
messagingServices: 0,
|
messagingServices: 0,
|
||||||
@ -109,6 +133,9 @@ const ServicesPage = () => {
|
|||||||
pipelineServices: 0,
|
pipelineServices: 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const [isLoadingMore, setIsLoadingMore] = useState<boolean>(false);
|
||||||
|
const [status, setStatus] = useState<LoadingState>('initial');
|
||||||
|
|
||||||
const updateServiceList = (
|
const updateServiceList = (
|
||||||
allServiceCollectionArr: Array<ServiceCollection>
|
allServiceCollectionArr: Array<ServiceCollection>
|
||||||
) => {
|
) => {
|
||||||
@ -122,24 +149,34 @@ const ServicesPage = () => {
|
|||||||
(result: PromiseSettledResult<AxiosResponse>[]) => {
|
(result: PromiseSettledResult<AxiosResponse>[]) => {
|
||||||
if (result.length) {
|
if (result.length) {
|
||||||
let serviceArr = [];
|
let serviceArr = [];
|
||||||
|
let servicePagingArr = [];
|
||||||
const serviceRecord = {} as ServiceRecord;
|
const serviceRecord = {} as ServiceRecord;
|
||||||
|
const servicePaging = {} as ServicePagingRecord;
|
||||||
serviceArr = result.map((service) =>
|
serviceArr = result.map((service) =>
|
||||||
service.status === 'fulfilled' ? service.value?.data?.data : []
|
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++) {
|
for (let i = 0; i < serviceArr.length; i++) {
|
||||||
serviceRecord[allServiceCollectionArr[i].value as ServiceTypes] =
|
serviceRecord[allServiceCollectionArr[i].value as ServiceTypes] =
|
||||||
serviceArr[i];
|
serviceArr[i];
|
||||||
|
servicePaging[allServiceCollectionArr[i].value as ServiceTypes] =
|
||||||
|
servicePagingArr[i];
|
||||||
}
|
}
|
||||||
setServices(serviceRecord);
|
setServices(serviceRecord);
|
||||||
|
|
||||||
|
setPaging(servicePaging);
|
||||||
setServicesCount({
|
setServicesCount({
|
||||||
databaseServices: serviceRecord.databaseServices.length,
|
databaseServices: servicePaging.databaseServices.total || 0,
|
||||||
messagingServices: serviceRecord.messagingServices.length,
|
messagingServices: servicePaging.messagingServices.total || 0,
|
||||||
dashboardServices: serviceRecord.dashboardServices.length,
|
dashboardServices: servicePaging.dashboardServices.total || 0,
|
||||||
pipelineServices: serviceRecord.pipelineServices.length,
|
pipelineServices: servicePaging.pipelineServices.total || 0,
|
||||||
});
|
});
|
||||||
setServiceList(
|
setServiceList(
|
||||||
serviceRecord[serviceName] as unknown as Array<ServiceDataObj>
|
serviceRecord[serviceName] as unknown as Array<ServiceDataObj>
|
||||||
);
|
);
|
||||||
|
setCurrentTabTotalCount(servicePaging[serviceName].total || 0);
|
||||||
}
|
}
|
||||||
setIsLoading(false);
|
setIsLoading(false);
|
||||||
}
|
}
|
||||||
@ -308,7 +345,7 @@ const ServicesPage = () => {
|
|||||||
setSearchText('');
|
setSearchText('');
|
||||||
setServicesCount({
|
setServicesCount({
|
||||||
...servicesCount,
|
...servicesCount,
|
||||||
[serviceName]: services[serviceName].length,
|
[serviceName]: currentTabTotalCount,
|
||||||
});
|
});
|
||||||
setServiceName(tabName);
|
setServiceName(tabName);
|
||||||
setServiceList(services[tabName] as unknown as Array<ServiceDataObj>);
|
setServiceList(services[tabName] as unknown as Array<ServiceDataObj>);
|
||||||
@ -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(() => {
|
useEffect(() => {
|
||||||
// fetch all service collection
|
// fetch all service collection
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
@ -406,6 +472,10 @@ const ServicesPage = () => {
|
|||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setCurrentTabTotalCount(servicesCount[serviceName]);
|
||||||
|
}, [serviceName]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{!isLoading ? (
|
{!isLoading ? (
|
||||||
@ -458,7 +528,7 @@ const ServicesPage = () => {
|
|||||||
</div>
|
</div>
|
||||||
{serviceList.length ? (
|
{serviceList.length ? (
|
||||||
<div
|
<div
|
||||||
className="tw-grid tw-grid-cols-4 tw-gap-4"
|
className="tw-grid tw-grid-cols-4 tw-gap-4 tw-mb-4"
|
||||||
data-testid="data-container">
|
data-testid="data-container">
|
||||||
{serviceList.map((service, index) => (
|
{serviceList.map((service, index) => (
|
||||||
<div
|
<div
|
||||||
@ -589,6 +659,18 @@ const ServicesPage = () => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{!isNil(paging[serviceName].after) && (
|
||||||
|
<div className="tw-my-4 tw-flex tw-justify-center tw-items-center">
|
||||||
|
<LoadMorePagination
|
||||||
|
showLoadingText
|
||||||
|
buttonText="Load more"
|
||||||
|
handleClick={() => pagingHandler(CursorType.AFTER)}
|
||||||
|
isLoading={isLoadingMore}
|
||||||
|
status={status}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{isModalOpen && (
|
{isModalOpen && (
|
||||||
<AddServiceModal
|
<AddServiceModal
|
||||||
data={editData}
|
data={editData}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user