diff --git a/static/src/js/components/ManageCollectionAssociation/ManageCollectionAssociation.jsx b/static/src/js/components/ManageCollectionAssociation/ManageCollectionAssociation.jsx
index 4c42042d0..23e4880fa 100644
--- a/static/src/js/components/ManageCollectionAssociation/ManageCollectionAssociation.jsx
+++ b/static/src/js/components/ManageCollectionAssociation/ManageCollectionAssociation.jsx
@@ -1,15 +1,20 @@
+import {
+ Alert,
+ Col,
+ Row
+} from 'react-bootstrap'
+import { camelCase } from 'lodash-es'
import { useMutation, useSuspenseQuery } from '@apollo/client'
-import React, { useCallback, useState } from 'react'
import { useParams } from 'react-router'
import { useSearchParams } from 'react-router-dom'
-import { Alert } from 'react-bootstrap'
-import { camelCase } from 'lodash-es'
+import React, { useCallback, useState } from 'react'
import pluralize from 'pluralize'
import Button from '@/js/components/Button/Button'
import CustomModal from '@/js/components/CustomModal/CustomModal'
import EllipsisText from '@/js/components/EllipsisText/EllipsisText'
+import Pagination from '@/js/components/Pagination/Pagination'
import Table from '@/js/components/Table/Table'
import conceptTypeQueries from '@/js/constants/conceptTypeQueries'
@@ -43,9 +48,17 @@ const ManageCollectionAssociation = () => {
const derivedConceptType = getConceptTypeByConceptId(conceptId)
+ const limit = 20
+ const activePage = parseInt(searchParams.get('page'), 10) || 1
+ const offset = (activePage - 1) * limit
+
let params = {
params: {
conceptId
+ },
+ collectionsParams: {
+ limit,
+ offset
}
}
@@ -55,6 +68,8 @@ const ManageCollectionAssociation = () => {
params = {
...params,
collectionsParams: {
+ limit,
+ offset,
sortKey
}
}
@@ -185,6 +200,14 @@ const ManageCollectionAssociation = () => {
}
]
+ const setPage = (nextPage) => {
+ setSearchParams((currentParams) => {
+ currentParams.set('page', nextPage)
+
+ return Object.fromEntries(currentParams)
+ })
+ }
+
const toggleShowDeleteModal = (nextState) => {
setShowDeleteModal(nextState)
}
@@ -208,52 +231,72 @@ const ManageCollectionAssociation = () => {
const { collections: associatedCollections } = concept
- const { items, count } = associatedCollections
+ const { items = [], count } = associatedCollections
+
+ const totalPages = Math.ceil(count / limit)
+
+ const currentPageIndex = Math.floor(offset / limit)
+ const firstResultIndex = currentPageIndex * limit
+ const isLastPage = totalPages === activePage
+ const lastResultIndex = firstResultIndex + (isLastPage ? count % limit : limit)
+
+ const paginationMessage = count > 0
+ ? `Showing ${totalPages > 1 ? `Collection Associations ${firstResultIndex + 1}-${lastResultIndex} of ${count}` : `${count} ${pluralize('Collection Association', count)}`}`
+ : 'No Collection Associations found'
return (
- <>
-
-
-
- {' '}
- Association operations may take some time. If you are not seeing what you expect below,
- please
- {' '}
-
+
+
+ {' '}
+ Association operations may take some time. If you are not seeing what you expect below,
+ please
+ {' '}
+
- refresh the page
-
-
-
-
-
- Showing
- {' '}
- {count}
- {' '}
- {pluralize('collection association', count)}
+ }
+ // eslint-disable-next-line react/jsx-props-no-spreading
+ {...refreshAccessibleEventProps}
+ >
+ refresh the page
-
+
+
+
+ {
+ (!!count) && (
+ {paginationMessage}
+ )
+ }
+
+ {
+ totalPages > 1 && (
+
+
+
+ )
+ }
+
`column_${dataKey}_${conceptIdCell}`}
generateRowKey={({ conceptId: conceptIdRow }) => `row_${conceptIdRow}`}
- noDataMessage="No collection associations found."
+ id="associated-collections"
limit={count}
+ noDataMessage="No collection associations found."
+ offset={offset}
/>
-
{
]
}
/>
- >
+
)
}
diff --git a/static/src/js/components/ManageCollectionAssociation/__tests__/ManageCollectionAssociation.test.jsx b/static/src/js/components/ManageCollectionAssociation/__tests__/ManageCollectionAssociation.test.jsx
index 7e08ed27b..679d91ff7 100644
--- a/static/src/js/components/ManageCollectionAssociation/__tests__/ManageCollectionAssociation.test.jsx
+++ b/static/src/js/components/ManageCollectionAssociation/__tests__/ManageCollectionAssociation.test.jsx
@@ -27,6 +27,8 @@ import {
deletedAssociationResponse,
toolRecordSearch,
toolRecordSearchError,
+ toolRecordSearchTestPage,
+ toolRecordSearchwithPages,
toolRecordSortSearch
} from './__mocks__/manageCollectionAssociationResults'
@@ -108,12 +110,26 @@ describe('ManageCollectionAssociation', () => {
test('renders the collection association page with the associated collections', async () => {
setup({})
- expect(await screen.findByText('Showing 2 collection associations')).toBeInTheDocument()
+ expect(await screen.findByText('Showing 2 Collection Associations')).toBeInTheDocument()
expect(screen.getByText('CIESIN_SEDAC_ESI_2000')).toBeInTheDocument()
expect(screen.getByText('CIESIN_SEDAC_ESI_2001')).toBeInTheDocument()
})
})
+ describe('when paging through the table', () => {
+ test('navigate to the next page', async () => {
+ const { user } = setup({
+ overrideMocks: [toolRecordSearchTestPage, toolRecordSearchwithPages]
+ })
+
+ expect(await screen.findByText('Showing Collection Associations 1-20 of 50'))
+ const paginationButton = screen.getByRole('button', { name: 'Goto Page 3' })
+ await user.click(paginationButton)
+
+ expect(await screen.findByText('Showing Collection Associations 41-50 of 50'))
+ })
+ })
+
describe.skip('when the request results in an error', () => {
test('should call errorLogger and renders an ErrorBanner', async () => {
setup({
@@ -163,7 +179,7 @@ describe('ManageCollectionAssociation', () => {
const noButton = screen.getByRole('button', { name: 'No' })
await user.click(noButton)
- expect(await screen.findByText('Showing 2 collection associations')).toBeInTheDocument()
+ expect(await screen.findByText('Showing 2 Collection Associations')).toBeInTheDocument()
expect(screen.getByText('CIESIN_SEDAC_ESI_2000')).toBeInTheDocument()
expect(screen.getByText('CIESIN_SEDAC_ESI_2001')).toBeInTheDocument()
})
@@ -300,7 +316,11 @@ describe('ManageCollectionAssociation', () => {
...toolRecordSortSearch.request,
variables: {
...toolRecordSortSearch.request.variables,
- collectionsParams: { sortKey: '-shortName' }
+ collectionsParams: {
+ limit: 20,
+ offset: 0,
+ sortKey: '-shortName'
+ }
}
},
result: toolRecordSortSearch.result
diff --git a/static/src/js/components/ManageCollectionAssociation/__tests__/__mocks__/manageCollectionAssociationResults.js b/static/src/js/components/ManageCollectionAssociation/__tests__/__mocks__/manageCollectionAssociationResults.js
index 0e4334a6f..866a6d683 100644
--- a/static/src/js/components/ManageCollectionAssociation/__tests__/__mocks__/manageCollectionAssociationResults.js
+++ b/static/src/js/components/ManageCollectionAssociation/__tests__/__mocks__/manageCollectionAssociationResults.js
@@ -7,6 +7,10 @@ export const toolRecordSearch = {
variables: {
params: {
conceptId: 'T1200000-TEST'
+ },
+ collectionsParams: {
+ limit: 20,
+ offset: 0
}
}
},
@@ -137,13 +141,297 @@ export const toolRecordSearch = {
}
}
}
+export const toolRecordSearchwithPages = {
+ request: {
+ query: GET_TOOL,
+ variables: {
+ params: {
+ conceptId: 'T1200000-TEST'
+ },
+ collectionsParams: {
+ limit: 20,
+ offset: 40
+ }
+ }
+ },
+ result: {
+ data: {
+ tool: {
+ __typename: 'Tool',
+ accessConstraints: null,
+ ancillaryKeywords: null,
+ associationDetails: {
+ collections: [{
+ conceptId: 'C120000001-TEST'
+ }, {
+ conceptId: 'C120000002-TEST'
+ }]
+ },
+ collections: {
+ count: 50,
+ items: [
+ {
+ title: 'Associated Collection 1',
+ conceptId: 'C120000001-TEST',
+ entryTitle: 'Associated Collection 1',
+ shortName: 'CIESIN_SEDAC_ESI_2000',
+ version: '2000.00',
+ provider: 'SEDAC',
+ __typename: 'Collection'
+ },
+ {
+ title: 'Associated Collection 2',
+ conceptId: 'C120000002-TEST',
+ entryTitle: 'Associated Collection 2',
+ shortName: 'CIESIN_SEDAC_ESI_2001',
+ version: '2001.00',
+ provider: 'SEDAC',
+ __typename: 'Collection'
+ }
+ ],
+ __typename: 'CollectionList'
+ },
+ conceptId: 'T1200000-TEST',
+ contactGroups: null,
+ contactPersons: null,
+ description: '312',
+ doi: null,
+ lastUpdatedDate: null,
+ longName: '123',
+ metadataSpecification: {
+ name: 'UMM-T',
+ url: 'https://cdn.earthdata.nasa.gov/umm/tool/v1.2.0',
+ version: '1.2.0'
+ },
+ name: 'Testing publish with routes',
+ nativeId: 'Test-123',
+ organizations: [{
+ longName: 'Woods Hole Science Center, Coastal and Marine Geology, U.S. Geological Survey, U.S. Department of the Interior',
+ roles: ['DEVELOPER'],
+ shortName: 'DOI/USGS/CMG/WHSC',
+ urlValue: 'http://woodshole.er.usgs.gov/'
+ }],
+ pageTitle: 'Testing publish with routes',
+ potentialAction: null,
+ providerId: 'MMT_2',
+ quality: null,
+ relatedUrls: null,
+ revisionDate: '2024-03-19T17:05:21.642Z',
+ revisionId: '1',
+ revisions: {
+ __typename: 'ToolRevisionList',
+ count: 1,
+ items: [{
+ __typename: 'Tool',
+ conceptId: 'T1200000-TEST',
+ revisionDate: '2024-04-25T17:11:57.611Z',
+ revisionId: '1',
+ userId: 'ECHO_SYS'
+ }]
+ },
+ searchAction: null,
+ supportedBrowsers: null,
+ supportedInputFormats: null,
+ supportedOperatingSystems: null,
+ supportedOutputFormats: null,
+ supportedSoftwareLanguages: null,
+ toolKeywords: [{
+ toolCategory: 'EARTH SCIENCE SERVICES',
+ toolTerm: 'CALIBRATION/VALIDATION',
+ toolTopic: 'DATA ANALYSIS AND VISUALIZATION'
+ }],
+ type: 'Model',
+ ummMetadata: {
+ Description: '312',
+ LongName: '123',
+ MetadataSpecification: {
+ Name: 'UMM-T',
+ URL: 'https://cdn.earthdata.nasa.gov/umm/tool/v1.2.0',
+ Version: '1.2.0'
+ },
+ Name: 'Testing publish with routes',
+ Organizations: [{
+ LongName: 'Woods Hole Science Center, Coastal and Marine Geology, U.S. Geological Survey, U.S. Department of the Interior',
+ Roles: ['DEVELOPER'],
+ ShortName: 'DOI/USGS/CMG/WHSC',
+ URLValue: 'http://woodshole.er.usgs.gov/'
+ }],
+ ToolKeywords: [{
+ ToolCategory: 'EARTH SCIENCE SERVICES',
+ ToolTerm: 'CALIBRATION/VALIDATION',
+ ToolTopic: 'DATA ANALYSIS AND VISUALIZATION'
+ }],
+ Type: 'Model',
+ URL: {
+ Type: 'DOWNLOAD SOFTWARE',
+ URLContentType: 'DistributionURL',
+ URLValue: '132'
+ },
+ Version: '123'
+ },
+ url: {
+ type: 'DOWNLOAD SOFTWARE',
+ urlContentType: 'DistributionURL',
+ urlValue: '132'
+ },
+ useConstraints: null,
+ version: '123',
+ versionDescription: null
+ }
+ }
+ }
+}
+export const toolRecordSearchTestPage = {
+ request: {
+ query: GET_TOOL,
+ variables: {
+ params: {
+ conceptId: 'T1200000-TEST'
+ },
+ collectionsParams: {
+ limit: 20,
+ offset: 0
+ }
+ }
+ },
+ result: {
+ data: {
+ tool: {
+ __typename: 'Tool',
+ accessConstraints: null,
+ ancillaryKeywords: null,
+ associationDetails: {
+ collections: [{
+ conceptId: 'C120000001-TEST'
+ }, {
+ conceptId: 'C120000002-TEST'
+ }]
+ },
+ collections: {
+ count: 50,
+ items: [
+ {
+ title: 'Associated Collection 1',
+ conceptId: 'C120000001-TEST',
+ entryTitle: 'Associated Collection 1',
+ shortName: 'CIESIN_SEDAC_ESI_2000',
+ version: '2000.00',
+ provider: 'SEDAC',
+ __typename: 'Collection'
+ },
+ {
+ title: 'Associated Collection 2',
+ conceptId: 'C120000002-TEST',
+ entryTitle: 'Associated Collection 2',
+ shortName: 'CIESIN_SEDAC_ESI_2001',
+ version: '2001.00',
+ provider: 'SEDAC',
+ __typename: 'Collection'
+ }
+ ],
+ __typename: 'CollectionList'
+ },
+ conceptId: 'T1200000-TEST',
+ contactGroups: null,
+ contactPersons: null,
+ description: '312',
+ doi: null,
+ lastUpdatedDate: null,
+ longName: '123',
+ metadataSpecification: {
+ name: 'UMM-T',
+ url: 'https://cdn.earthdata.nasa.gov/umm/tool/v1.2.0',
+ version: '1.2.0'
+ },
+ name: 'Testing publish with routes',
+ nativeId: 'Test-123',
+ organizations: [{
+ longName: 'Woods Hole Science Center, Coastal and Marine Geology, U.S. Geological Survey, U.S. Department of the Interior',
+ roles: ['DEVELOPER'],
+ shortName: 'DOI/USGS/CMG/WHSC',
+ urlValue: 'http://woodshole.er.usgs.gov/'
+ }],
+ pageTitle: 'Testing publish with routes',
+ potentialAction: null,
+ providerId: 'MMT_2',
+ quality: null,
+ relatedUrls: null,
+ revisionDate: '2024-03-19T17:05:21.642Z',
+ revisionId: '1',
+ revisions: {
+ __typename: 'ToolRevisionList',
+ count: 1,
+ items: [{
+ __typename: 'Tool',
+ conceptId: 'T1200000-TEST',
+ revisionDate: '2024-04-25T17:11:57.611Z',
+ revisionId: '1',
+ userId: 'ECHO_SYS'
+ }]
+ },
+ searchAction: null,
+ supportedBrowsers: null,
+ supportedInputFormats: null,
+ supportedOperatingSystems: null,
+ supportedOutputFormats: null,
+ supportedSoftwareLanguages: null,
+ toolKeywords: [{
+ toolCategory: 'EARTH SCIENCE SERVICES',
+ toolTerm: 'CALIBRATION/VALIDATION',
+ toolTopic: 'DATA ANALYSIS AND VISUALIZATION'
+ }],
+ type: 'Model',
+ ummMetadata: {
+ Description: '312',
+ LongName: '123',
+ MetadataSpecification: {
+ Name: 'UMM-T',
+ URL: 'https://cdn.earthdata.nasa.gov/umm/tool/v1.2.0',
+ Version: '1.2.0'
+ },
+ Name: 'Testing publish with routes',
+ Organizations: [{
+ LongName: 'Woods Hole Science Center, Coastal and Marine Geology, U.S. Geological Survey, U.S. Department of the Interior',
+ Roles: ['DEVELOPER'],
+ ShortName: 'DOI/USGS/CMG/WHSC',
+ URLValue: 'http://woodshole.er.usgs.gov/'
+ }],
+ ToolKeywords: [{
+ ToolCategory: 'EARTH SCIENCE SERVICES',
+ ToolTerm: 'CALIBRATION/VALIDATION',
+ ToolTopic: 'DATA ANALYSIS AND VISUALIZATION'
+ }],
+ Type: 'Model',
+ URL: {
+ Type: 'DOWNLOAD SOFTWARE',
+ URLContentType: 'DistributionURL',
+ URLValue: '132'
+ },
+ Version: '123'
+ },
+ url: {
+ type: 'DOWNLOAD SOFTWARE',
+ urlContentType: 'DistributionURL',
+ urlValue: '132'
+ },
+ useConstraints: null,
+ version: '123',
+ versionDescription: null
+ }
+ }
+ }
+}
export const toolRecordSortSearch = {
request: {
query: GET_TOOL,
variables: {
params: { conceptId: 'T1200000-TEST' },
- collectionsParams: { sortKey: '-provider' }
+ collectionsParams: {
+ limit: 20,
+ offset: 0,
+ sortKey: '-provider'
+ }
}
},
result: {
@@ -283,6 +571,7 @@ export const singleAssociationSearch = {
},
collectionsParams: {
limit: 20,
+ offset: 0,
sortKey: null
}
}
@@ -442,6 +731,10 @@ export const deletedAssociationResponse = {
variables: {
params: {
conceptId: 'T1200000-TEST'
+ },
+ collectionsParams: {
+ limit: 20,
+ offset: 0
}
}
},