From 3726f5441c797f180d4015c36f9a9c7cff3b158d Mon Sep 17 00:00:00 2001 From: gaurav2733 Date: Tue, 16 Apr 2024 17:28:01 +0530 Subject: [PATCH] feat(ui/tasks): add pagination on tasks listing page --- .../app/entity/dataFlow/DataFlowEntity.tsx | 63 ++++++------ .../containers/profile/EntityProfile.tsx | 4 +- .../profile/useGetDataForProfile.ts | 17 +++- .../shared/tabs/Entity/DataFlowJobsTab.tsx | 16 +++- .../tabs/Entity/components/EntityList.tsx | 95 +++++++++++++++++-- .../components/TaskPaginationContext.tsx | 30 ++++++ .../src/graphql/dataFlow.graphql | 4 +- 7 files changed, 183 insertions(+), 46 deletions(-) create mode 100644 datahub-web-react/src/app/entity/shared/tabs/Entity/components/TaskPaginationContext.tsx diff --git a/datahub-web-react/src/app/entity/dataFlow/DataFlowEntity.tsx b/datahub-web-react/src/app/entity/dataFlow/DataFlowEntity.tsx index 25c1af09e7e5c8..3f3c996647d604 100644 --- a/datahub-web-react/src/app/entity/dataFlow/DataFlowEntity.tsx +++ b/datahub-web-react/src/app/entity/dataFlow/DataFlowEntity.tsx @@ -19,6 +19,7 @@ import { capitalizeFirstLetterOnly } from '../../shared/textUtil'; import DataProductSection from '../shared/containers/profile/sidebar/DataProduct/DataProductSection'; import { getDataProduct } from '../shared/utils'; import { IncidentTab } from '../shared/tabs/Incident/IncidentTab'; +import { TaskPaginationProvider } from '../shared/tabs/Entity/components/TaskPaginationContext'; /** * Definition of the DataHub DataFlow entity. @@ -62,37 +63,39 @@ export class DataFlowEntity implements Entity { useEntityQuery = useGetDataFlowQuery; renderProfile = (urn: string) => ( - { - const activeIncidentCount = dataFlow?.dataFlow?.activeIncidents.total; - return `Incidents${(activeIncidentCount && ` (${activeIncidentCount})`) || ''}`; + + + { + name: 'Properties', + component: PropertiesTab, + }, + { + name: 'Tasks', + component: DataFlowJobsTab, + }, + { + name: 'Incidents', + component: IncidentTab, + getDynamicName: (_, dataFlow) => { + const activeIncidentCount = dataFlow?.dataFlow?.activeIncidents.total; + return `Incidents${(activeIncidentCount && ` (${activeIncidentCount})`) || ''}`; + }, + }, + ]} + sidebarSections={this.getSidebarSections()} + /> + ); getSidebarSections = () => [ diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/EntityProfile.tsx b/datahub-web-react/src/app/entity/shared/containers/profile/EntityProfile.tsx index a9737c9698f7b2..acadfcc87c84b4 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/EntityProfile.tsx +++ b/datahub-web-react/src/app/entity/shared/containers/profile/EntityProfile.tsx @@ -46,6 +46,7 @@ import { useAppConfig } from '../../../../useAppConfig'; import { useUpdateDomainEntityDataOnChange } from '../../../../domain/utils'; import ProfileSidebar from './sidebar/ProfileSidebar'; import SidebarFormInfoWrapper from './sidebar/FormInfo/SidebarFormInfoWrapper'; +import { useTaskPagination } from '../../tabs/Entity/components/TaskPaginationContext'; type Props = { urn: string; @@ -164,6 +165,7 @@ export const EntityProfile = ({ const entityRegistry = useEntityRegistry(); const history = useHistory(); const appConfig = useAppConfig(); + const { count, start } = useTaskPagination(); const isCompact = React.useContext(CompactContext); const tabsWithDefaults = tabs.map((tab) => ({ ...tab, display: { ...defaultTabDisplayConfig, ...tab.display } })); @@ -214,7 +216,7 @@ export const EntityProfile = ({ ); const { entityData, dataPossiblyCombinedWithSiblings, dataNotCombinedWithSiblings, loading, error, refetch } = - useGetDataForProfile({ urn, entityType, useEntityQuery, getOverrideProperties }); + useGetDataForProfile({ urn, entityType, count ,start , useEntityQuery, getOverrideProperties }); useUpdateGlossaryEntityDataOnChange(entityData, entityType); useUpdateDomainEntityDataOnChange(entityData, entityType); diff --git a/datahub-web-react/src/app/entity/shared/containers/profile/useGetDataForProfile.ts b/datahub-web-react/src/app/entity/shared/containers/profile/useGetDataForProfile.ts index ae87eeb1a84507..9b321ff2b63e6f 100644 --- a/datahub-web-react/src/app/entity/shared/containers/profile/useGetDataForProfile.ts +++ b/datahub-web-react/src/app/entity/shared/containers/profile/useGetDataForProfile.ts @@ -6,24 +6,37 @@ import { EntityType, Exact } from '../../../../../types.generated'; interface Props { urn: string; + count?: number; + start?: number; entityType: EntityType; useEntityQuery: ( baseOptions: QueryHookOptions< T, Exact<{ urn: string; + count?: number; + start?: number; }> >, ) => QueryResult< T, Exact<{ urn: string; + count?: number; + start?: number; }> >; getOverrideProperties: (T) => GenericEntityProperties; } -export default function useGetDataForProfile({ urn, entityType, useEntityQuery, getOverrideProperties }: Props) { +export default function useGetDataForProfile({ + urn, + count, + start, + entityType, + useEntityQuery, + getOverrideProperties, +}: Props) { const isHideSiblingMode = useIsSeparateSiblingsMode(); const { loading, @@ -31,7 +44,7 @@ export default function useGetDataForProfile({ urn, entityType, useEntityQuer data: dataNotCombinedWithSiblings, refetch, } = useEntityQuery({ - variables: { urn }, + variables: { urn, count, start }, fetchPolicy: 'cache-first', }); diff --git a/datahub-web-react/src/app/entity/shared/tabs/Entity/DataFlowJobsTab.tsx b/datahub-web-react/src/app/entity/shared/tabs/Entity/DataFlowJobsTab.tsx index fe43ee7dc518a9..fd86c867c1a117 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Entity/DataFlowJobsTab.tsx +++ b/datahub-web-react/src/app/entity/shared/tabs/Entity/DataFlowJobsTab.tsx @@ -10,10 +10,24 @@ export const DataFlowJobsTab = () => { const dataJobs = dataFlow?.childJobs?.relationships.map((relationship) => relationship.entity); const entityRegistry = useEntityRegistry(); const totalJobs = dataFlow?.childJobs?.total || 0; + const pageSize = dataFlow?.childJobs?.count || 0; + const pageStart = dataFlow?.childJobs?.start || 0; + const lastResultIndex = pageStart + pageSize > totalJobs ? totalJobs : pageStart + pageSize; + const title = `Contains ${totalJobs} ${ totalJobs === 1 ? entityRegistry.getEntityName(EntityType.DataJob) : entityRegistry.getCollectionName(EntityType.DataJob) }`; - return ; + return ( + + ); }; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Entity/components/EntityList.tsx b/datahub-web-react/src/app/entity/shared/tabs/Entity/components/EntityList.tsx index 3a9061fd97d6e7..d7e1dea6d7f181 100644 --- a/datahub-web-react/src/app/entity/shared/tabs/Entity/components/EntityList.tsx +++ b/datahub-web-react/src/app/entity/shared/tabs/Entity/components/EntityList.tsx @@ -1,9 +1,16 @@ -import React from 'react'; -import { List } from 'antd'; +import React, { useEffect, useState } from 'react'; +import { List, Pagination, Typography } from 'antd'; import styled from 'styled-components'; import { useEntityRegistry } from '../../../../../useEntityRegistry'; import { PreviewType } from '../../../../Entity'; import { EntityType } from '../../../../../../types.generated'; +import { SearchCfg } from '../../../../../../conf'; +import { useTaskPagination } from './TaskPaginationContext'; + +const ScrollWrapper = styled.div` + overflow: auto; + max-height: 100%; +`; const StyledList = styled(List)` padding-left: 40px; @@ -28,22 +35,90 @@ const StyledListItem = styled(List.Item)` padding-top: 20px; `; +const PaginationInfoContainer = styled.span` + padding: 8px; + padding-left: 16px; + border-top: 1px solid; + border-color: ${(props) => props.theme.styles['border-color-base']}; + display: flex; + justify-content: space-between; + align-items: center; +`; + +const StyledPagination = styled(Pagination)` + margin: 0px; + padding: 0px; +`; + +const PaginationInfo = styled(Typography.Text)` + padding: 0px; +`; + type EntityListProps = { type: EntityType; entities: Array; title?: string; + totalJobs?: number | null; + pageSize?: any; + lastResultIndex?: any; + showTaskPagination?: boolean; }; -export const EntityList = ({ type, entities, title }: EntityListProps) => { +export const EntityList = ({ + type, + entities, + title, + totalJobs, + pageSize, + lastResultIndex, + showTaskPagination = false, +}: EntityListProps) => { const entityRegistry = useEntityRegistry(); + const { updateData } = useTaskPagination(); + + const [page, setPage] = useState(1); + const [numResultsPerPage, setNumResultsPerPage] = useState(SearchCfg.RESULTS_PER_PAGE); + + const onChangePage = (newPage: number) => { + setPage(newPage); + }; + + useEffect(() => { + updateData(numResultsPerPage, (page - 1) * numResultsPerPage); + }, [page, numResultsPerPage, updateData]); + return ( - ( - {entityRegistry.renderPreview(type, PreviewType.PREVIEW, item)} + <> + + ( + {entityRegistry.renderPreview(type, PreviewType.PREVIEW, item)} + )} + /> + + {showTaskPagination && ( + + + + {lastResultIndex > 0 ? (page - 1) * pageSize + 1 : 0} - {lastResultIndex} + {' '} + of {totalJobs} + + SearchCfg.RESULTS_PER_PAGE} + onShowSizeChange={(_currNum, newNum) => setNumResultsPerPage(newNum)} + pageSizeOptions={['10', '20', '50', '100']} + /> + )} - /> + ); }; diff --git a/datahub-web-react/src/app/entity/shared/tabs/Entity/components/TaskPaginationContext.tsx b/datahub-web-react/src/app/entity/shared/tabs/Entity/components/TaskPaginationContext.tsx new file mode 100644 index 00000000000000..54733c26b02521 --- /dev/null +++ b/datahub-web-react/src/app/entity/shared/tabs/Entity/components/TaskPaginationContext.tsx @@ -0,0 +1,30 @@ +import React, { createContext, useContext, useState } from 'react'; +import { SearchCfg } from '../../../../../../conf'; + +type PaginationUpdateFunction = (newCount: number, newStart: number) => void; + +const TaskPaginationContext = createContext({ + count: SearchCfg.RESULTS_PER_PAGE, + start: 1, + updateData: (() => {}) as PaginationUpdateFunction, +}); + +export const useTaskPagination = () => useContext(TaskPaginationContext); + +export const TaskPaginationProvider = ({ children }: { children: React.ReactNode }) => { + const [count, setCount] = useState(SearchCfg.RESULTS_PER_PAGE); + const [start, setStart] = useState(1); + + const updateData: PaginationUpdateFunction = (newCount, newStart) => { + setCount(newCount); + setStart(newStart); + }; + + const contextValue = { + count, + start, + updateData, + }; + + return {children}; +}; diff --git a/datahub-web-react/src/graphql/dataFlow.graphql b/datahub-web-react/src/graphql/dataFlow.graphql index e4284225e55b9a..5408747b67f7ea 100644 --- a/datahub-web-react/src/graphql/dataFlow.graphql +++ b/datahub-web-react/src/graphql/dataFlow.graphql @@ -61,7 +61,7 @@ fragment dataFlowFields on DataFlow { } } -query getDataFlow($urn: String!) { +query getDataFlow($urn: String!, $start: Int, $count: Int) { dataFlow(urn: $urn) { ...dataFlowFields upstream: lineage(input: { direction: UPSTREAM, start: 0, count: 100 }) { @@ -70,7 +70,7 @@ query getDataFlow($urn: String!) { downstream: lineage(input: { direction: DOWNSTREAM, start: 0, count: 100 }) { ...partialLineageResults } - childJobs: relationships(input: { types: ["IsPartOf"], direction: INCOMING, start: 0, count: 100 }) { + childJobs: relationships(input: { types: ["IsPartOf"], direction: INCOMING, start: $start, count: $count }) { start count total