Skip to content

Commit 46ac4b9

Browse files
authored
MMT-4098: Added View Granules Option (#1421)
* MMT-4098: Added View Granules Option
1 parent c7a16c4 commit 46ac4b9

File tree

11 files changed

+629
-2
lines changed

11 files changed

+629
-2
lines changed

static/src/js/App.jsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { Navigate, createBrowserRouter } from 'react-router-dom'
55
import CollectionAssociationFormPage from '@/js/pages/CollectionAssociationFormPage/CollectionAssociationFormPage'
66
import DraftListPage from '@/js/pages/DraftListPage/DraftListPage'
77
import DraftPage from '@/js/pages/DraftPage/DraftPage'
8+
import GranulesListPage from '@/js/pages/GranulesListPage/GranulesListPage'
89
import GroupFormPage from '@/js/pages/GroupFormPage/GroupFormPage'
910
import GroupListPage from '@/js/pages/GroupListPage/GroupListPage'
1011
import GroupPage from '@/js/pages/GroupPage/GroupPage'
@@ -111,6 +112,10 @@ export const App = () => {
111112
path: '/:type/:conceptId/collection-association',
112113
element: <ManageCollectionAssociationPage />
113114
},
115+
{
116+
path: '/collections/:conceptId/granules',
117+
element: <GranulesListPage />
118+
},
114119
{
115120
path: '/collections/:conceptId/service-associations',
116121
element: <ManageServiceAssociationsPage />

static/src/js/__tests__/App.test.jsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,12 @@ vi.mock('@/js/pages/KeywordManagerPage/KeywordManagerPage', () => ({
8181
))
8282
}))
8383

84+
vi.mock('@/js/pages/GranulesListPage/GranulesListPage', () => ({
85+
default: vi.fn(() => (
86+
<div data-testid="mock-granules-list-page">Granules List Page</div>
87+
))
88+
}))
89+
8490
const setup = () => {
8591
render(
8692
<App />
@@ -229,4 +235,17 @@ describe('App component', () => {
229235
window.history.pushState({}, '', '/')
230236
})
231237
})
238+
239+
describe('when rendering the "/collections/:conceptId/granules" route', () => {
240+
test('renders the granules list page', async () => {
241+
const mockConceptId = 'C1234567-TEST'
242+
window.history.pushState({}, '', `/collections/${mockConceptId}/granules`)
243+
244+
setup()
245+
246+
expect(await screen.findByTestId('mock-granules-list-page')).toBeInTheDocument()
247+
248+
window.history.pushState({}, '', '/')
249+
})
250+
})
232251
})
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import React, { useState } from 'react'
2+
import { useSuspenseQuery } from '@apollo/client'
3+
import { useParams } from 'react-router'
4+
import moment from 'moment'
5+
import pluralize from 'pluralize'
6+
import Col from 'react-bootstrap/Col'
7+
import Row from 'react-bootstrap/Row'
8+
9+
import { GET_GRANULES } from '@/js/operations/queries/getGranules'
10+
import ControlledPaginatedContent from '@/js/components/ControlledPaginatedContent/ControlledPaginatedContent'
11+
import getConceptTypeByConceptId from '../../utils/getConceptTypeByConceptId'
12+
import { DATE_FORMAT } from '../../constants/dateFormat'
13+
import Table from '../Table/Table'
14+
15+
const GranulesList = () => {
16+
const { conceptId } = useParams()
17+
const [activePage, setActivePage] = useState(1)
18+
19+
const limit = 10
20+
const offset = (activePage - 1) * limit
21+
22+
const derivedConceptType = getConceptTypeByConceptId(conceptId)
23+
24+
const { data } = useSuspenseQuery(GET_GRANULES, {
25+
variables: {
26+
params: {
27+
conceptId
28+
},
29+
granulesParams: {
30+
limit,
31+
offset
32+
}
33+
}
34+
})
35+
36+
const { [derivedConceptType.toLowerCase()]: concept } = data
37+
const { granules } = concept
38+
const { count, items } = granules
39+
40+
const setPage = (nextPage) => {
41+
setActivePage(nextPage)
42+
}
43+
44+
const columns = [
45+
{
46+
dataKey: 'conceptId',
47+
title: 'Concept Id',
48+
className: 'col-auto'
49+
},
50+
{
51+
dataKey: 'title',
52+
title: 'Title',
53+
className: 'col-auto'
54+
},
55+
{
56+
dataKey: 'revisionDate',
57+
title: 'Revision Date (UTC)',
58+
className: 'col-auto',
59+
dataAccessorFn: (cellData) => {
60+
if (cellData === null || cellData === undefined) {
61+
return 'N/A'
62+
}
63+
64+
return moment.utc(cellData).format(DATE_FORMAT)
65+
}
66+
}
67+
]
68+
69+
return (
70+
<Row>
71+
<Col sm={12}>
72+
<ControlledPaginatedContent
73+
activePage={activePage}
74+
count={count}
75+
limit={limit}
76+
setPage={setPage}
77+
>
78+
{
79+
({
80+
totalPages,
81+
pagination,
82+
firstResultPosition,
83+
lastResultPosition
84+
}) => {
85+
const paginationMessage = count > 0
86+
? `Showing ${totalPages > 1 ? `${firstResultPosition}-${lastResultPosition} of` : ''} ${count} ${pluralize('granule', count)}`
87+
: 'No granules found'
88+
89+
return (
90+
<>
91+
<Row className="d-flex justify-content-between align-items-center mb-4">
92+
<Col className="mb-4 flex-grow-1" xs="auto">
93+
{
94+
(!!count) && (
95+
<span className="text-secondary fw-bolder">{paginationMessage}</span>
96+
)
97+
}
98+
</Col>
99+
<Col className="mb-4 flex-grow-1" xs="auto" />
100+
{
101+
totalPages > 1 && (
102+
<Col xs="auto">
103+
{pagination}
104+
</Col>
105+
)
106+
}
107+
</Row>
108+
<Table
109+
id="granule-results-table"
110+
columns={columns}
111+
data={items}
112+
generateCellKey={({ conceptId: granuleConceptId, revisionId }, dataKey) => `column_${dataKey}_${granuleConceptId}_${revisionId}`}
113+
generateRowKey={({ conceptId: granuleConceptId, revisionId }) => `row_${granuleConceptId}_${revisionId}`}
114+
noDataMessage="No granules found"
115+
count={count}
116+
setPage={setPage}
117+
limit={limit}
118+
offset={offset}
119+
/>
120+
{
121+
totalPages > 1 && (
122+
<Row>
123+
<Col xs="12" className="pt-4 d-flex align-items-center justify-content-center">
124+
<div>
125+
{pagination}
126+
</div>
127+
</Col>
128+
</Row>
129+
)
130+
}
131+
</>
132+
)
133+
}
134+
}
135+
</ControlledPaginatedContent>
136+
</Col>
137+
</Row>
138+
)
139+
}
140+
141+
export default GranulesList

0 commit comments

Comments
 (0)