From 86b5bf0f7a8614db151928aad8aad2750d6458a1 Mon Sep 17 00:00:00 2001 From: Mandy Parson <135638667+mandyparson@users.noreply.github.com> Date: Fri, 27 Sep 2024 15:32:12 -0600 Subject: [PATCH] MMT-3908: Adding pagination to ACL (#1304) --- .../ManageCollectionAssociation.jsx | 1 - .../PermissionCollectionTable.jsx | 54 +++++- .../PermissionCollectionTable.test.jsx | 133 +++++-------- .../permissionCollectionTableResults.js | 179 ++++++++++++++++++ 4 files changed, 276 insertions(+), 91 deletions(-) create mode 100644 static/src/js/components/PermissionCollectionTable/__tests__/__mocks__/permissionCollectionTableResults.js diff --git a/static/src/js/components/ManageCollectionAssociation/ManageCollectionAssociation.jsx b/static/src/js/components/ManageCollectionAssociation/ManageCollectionAssociation.jsx index 23e4880fa..7ea0d39c0 100644 --- a/static/src/js/components/ManageCollectionAssociation/ManageCollectionAssociation.jsx +++ b/static/src/js/components/ManageCollectionAssociation/ManageCollectionAssociation.jsx @@ -41,7 +41,6 @@ const ManageCollectionAssociation = () => { const { addNotification } = useNotificationsContext() - // Const [error, setError] = useState() const [searchParams, setSearchParams] = useSearchParams() const [collectionConceptIds, setCollectionConceptIds] = useState([]) const [showDeleteModal, setShowDeleteModal] = useState(false) diff --git a/static/src/js/components/PermissionCollectionTable/PermissionCollectionTable.jsx b/static/src/js/components/PermissionCollectionTable/PermissionCollectionTable.jsx index 523297741..6adcacdc7 100644 --- a/static/src/js/components/PermissionCollectionTable/PermissionCollectionTable.jsx +++ b/static/src/js/components/PermissionCollectionTable/PermissionCollectionTable.jsx @@ -1,4 +1,5 @@ import React, { useCallback } from 'react' +import pluralize from 'pluralize' import { useSuspenseQuery } from '@apollo/client' import { useParams } from 'react-router' import { useSearchParams } from 'react-router-dom' @@ -11,13 +12,23 @@ import Table from '@/js/components/Table/Table' import { GET_COLLECTION_PERMISSION } from '@/js/operations/queries/getCollectionPermission' +import Pagination from '../Pagination/Pagination' + const PermissionCollectionTable = () => { const { conceptId } = useParams() const [searchParams, setSearchParams] = useSearchParams() + const limit = 20 + const activePage = parseInt(searchParams.get('page'), 10) || 1 + const offset = (activePage - 1) * limit + let params = { - conceptId + conceptId, + collectionParams: { + limit, + offset + } } const sortKey = searchParams.get('sortKey') @@ -26,6 +37,8 @@ const PermissionCollectionTable = () => { params = { ...params, collectionParams: { + limit, + offset, sortKey } } @@ -38,7 +51,7 @@ const PermissionCollectionTable = () => { const { acl } = data const { collections } = acl - const { items, count } = collections || {} + const { items, count } = collections const sortFn = useCallback((key, order) => { let nextSortKey @@ -59,6 +72,14 @@ const PermissionCollectionTable = () => { }) }, []) + const setPage = (nextPage) => { + setSearchParams((currentParams) => { + currentParams.set('page', nextPage) + + return Object.fromEntries(currentParams) + }) + } + const buildEllipsisLinkCell = useCallback((cellData, rowData) => { const { conceptId: collectionConceptId } = rowData @@ -91,8 +112,35 @@ const PermissionCollectionTable = () => { } ] + 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 = `Showing ${totalPages > 1 ? `Collection Associations ${firstResultIndex + 1}-${lastResultIndex} of ${count}` : `${count} ${pluralize('Collection Association', count)}`}` + return ( - + + + { + (!!count) && ( + {paginationMessage} + ) + } + + { + totalPages > 1 && ( + + + + ) + } { items && ( diff --git a/static/src/js/components/PermissionCollectionTable/__tests__/PermissionCollectionTable.test.jsx b/static/src/js/components/PermissionCollectionTable/__tests__/PermissionCollectionTable.test.jsx index 8648a1892..2b4b9531d 100644 --- a/static/src/js/components/PermissionCollectionTable/__tests__/PermissionCollectionTable.test.jsx +++ b/static/src/js/components/PermissionCollectionTable/__tests__/PermissionCollectionTable.test.jsx @@ -17,98 +17,23 @@ import { GET_COLLECTION_PERMISSION } from '@/js/operations/queries/getCollection import { InMemoryCache, defaultDataIdFromObject } from '@apollo/client' import PermissionCollectionTable from '../PermissionCollectionTable' -const mockPermission = { - __typename: 'Acl', - conceptId: 'ACL00000-CMR', - collections: { - __typename: 'CollectionList', - count: 1, - items: [ - { - __typename: 'Collection', - conceptId: 'C1200450691-MMT_2', - shortName: 'Collection 1', - title: 'Mock Collection 1', - version: '1', - provider: 'MMT_2' - }, - { - __typename: 'Collection', - conceptId: 'C1200450692-MMT_2', - shortName: 'Collection 2', - title: 'Mock Collection 2', - version: '2', - provider: 'MMT_2' - } - ] - }, - identityType: 'Catalog Item', - location: 'https://cmr.sit.earthdata.nasa.gov:443/access-control/acls/ACL00000-CMR', - name: 'Mock Permission', - providerIdentity: null, - revisionId: 5, - systemIdentity: null, - catalogItemIdentity: { - __typename: 'CatalogItemIdentity', - collectionApplicable: true, - granuleApplicable: false, - granuleIdentifier: null, - name: 'Mock Permission', - providerId: 'MMT_2', - collectionIdentifier: { - __typename: 'CollectionIdentifier', - accessValue: null, - temporal: null - } - }, - groups: { - __typename: 'AclGroupList', - items: [ - { - __typename: 'GroupPermission', - permissions: [ - 'read' - ], - userType: 'guest', - group: null, - id: null, - name: null - }, - { - __typename: 'GroupPermission', - permissions: [ - 'read' - ], - userType: 'registered', - group: null, - id: null, - name: null - } - ] - } -} +import { + mockPermission, + mockCollectionPermissionSearch, + mockCollectionPermissionSearchWithPages +} from './__mocks__/permissionCollectionTableResults' + const setup = ({ - additionalMock = [] + additionalMock = [], + overrideMocks = false }) => { - const mocks = [{ - request: { - query: GET_COLLECTION_PERMISSION, - variables: { - conceptId: 'ACL00000-CMR' - } - }, - result: { - data: { - acl: mockPermission - } - } - }, ...additionalMock] + const mocks = [mockCollectionPermissionSearch, ...additionalMock] const user = userEvent.setup() render( { @@ -168,7 +93,11 @@ describe('PermissionCollectionTable', () => { query: GET_COLLECTION_PERMISSION, variables: { conceptId: 'ACL00000-CMR', - collectionParams: { sortKey: '-shortName' } + collectionParams: { + limit: 20, + offset: 0, + sortKey: '-shortName' + } } }, result: { @@ -197,7 +126,11 @@ describe('PermissionCollectionTable', () => { query: GET_COLLECTION_PERMISSION, variables: { conceptId: 'ACL00000-CMR', - collectionParams: { sortKey: 'entryTitle' } + collectionParams: { + limit: 20, + offset: 0, + sortKey: 'entryTitle' + } } }, result: { @@ -217,4 +150,30 @@ describe('PermissionCollectionTable', () => { expect(await within(row1).findByRole('button', { name: /Sort Short Name in descending order/ })).toHaveClass('table__sort-button--inactive') }) }) + + describe('when paging through the table', () => { + test('navigate to the next page', async () => { + const { user } = setup({ + overrideMocks: [mockCollectionPermissionSearchWithPages, { + request: { + ...mockCollectionPermissionSearchWithPages.request, + variables: { + conceptId: 'ACL00000-CMR', + collectionParams: { + limit: 20, + offset: 40 + } + } + }, + result: mockCollectionPermissionSearchWithPages.result + }] + }) + + expect(await screen.findByText('Showing Collection Associations 1-20 of 45')) + const paginationButton = screen.getByRole('button', { name: 'Goto Page 3' }) + await user.click(paginationButton) + + expect(await screen.findByText('Showing Collection Associations 41-45 of 45')) + }) + }) }) diff --git a/static/src/js/components/PermissionCollectionTable/__tests__/__mocks__/permissionCollectionTableResults.js b/static/src/js/components/PermissionCollectionTable/__tests__/__mocks__/permissionCollectionTableResults.js new file mode 100644 index 000000000..eb00dd3aa --- /dev/null +++ b/static/src/js/components/PermissionCollectionTable/__tests__/__mocks__/permissionCollectionTableResults.js @@ -0,0 +1,179 @@ +import { GET_COLLECTION_PERMISSION } from '@/js/operations/queries/getCollectionPermission' + +export const mockPermission = { + __typename: 'Acl', + conceptId: 'ACL00000-CMR', + collections: { + __typename: 'CollectionList', + count: 1, + items: [ + { + __typename: 'Collection', + conceptId: 'C1200450691-MMT_2', + shortName: 'Collection 1', + title: 'Mock Collection 1', + version: '1', + provider: 'MMT_2' + }, + { + __typename: 'Collection', + conceptId: 'C1200450692-MMT_2', + shortName: 'Collection 2', + title: 'Mock Collection 2', + version: '2', + provider: 'MMT_2' + } + ] + }, + identityType: 'Catalog Item', + location: 'https://cmr.sit.earthdata.nasa.gov:443/access-control/acls/ACL00000-CMR', + name: 'Mock Permission', + providerIdentity: null, + revisionId: 5, + systemIdentity: null, + catalogItemIdentity: { + __typename: 'CatalogItemIdentity', + collectionApplicable: true, + granuleApplicable: false, + granuleIdentifier: null, + name: 'Mock Permission', + providerId: 'MMT_2', + collectionIdentifier: { + __typename: 'CollectionIdentifier', + accessValue: null, + temporal: null + } + }, + groups: { + __typename: 'AclGroupList', + items: [ + { + __typename: 'GroupPermission', + permissions: [ + 'read' + ], + userType: 'guest', + group: null, + id: null, + name: null + }, + { + __typename: 'GroupPermission', + permissions: [ + 'read' + ], + userType: 'registered', + group: null, + id: null, + name: null + } + ] + } +} + +export const mockPermissions = { + __typename: 'Acl', + conceptId: 'ACL00000-CMR', + collections: { + __typename: 'CollectionList', + count: 45, + items: [ + { + __typename: 'Collection', + conceptId: 'C1200450691-MMT_2', + shortName: 'Collection 1', + title: 'Mock Collection 1', + version: '1', + provider: 'MMT_2' + }, + { + __typename: 'Collection', + conceptId: 'C1200450692-MMT_2', + shortName: 'Collection 2', + title: 'Mock Collection 2', + version: '2', + provider: 'MMT_2' + } + ] + }, + identityType: 'Catalog Item', + location: 'https://cmr.sit.earthdata.nasa.gov:443/access-control/acls/ACL00000-CMR', + name: 'Mock Permission', + providerIdentity: null, + revisionId: 5, + systemIdentity: null, + catalogItemIdentity: { + __typename: 'CatalogItemIdentity', + collectionApplicable: true, + granuleApplicable: false, + granuleIdentifier: null, + name: 'Mock Permission', + providerId: 'MMT_2', + collectionIdentifier: { + __typename: 'CollectionIdentifier', + accessValue: null, + temporal: null + } + }, + groups: { + __typename: 'AclGroupList', + items: [ + { + __typename: 'GroupPermission', + permissions: [ + 'read' + ], + userType: 'guest', + group: null, + id: null, + name: null + }, + { + __typename: 'GroupPermission', + permissions: [ + 'read' + ], + userType: 'registered', + group: null, + id: null, + name: null + } + ] + } +} + +export const mockCollectionPermissionSearch = { + request: { + query: GET_COLLECTION_PERMISSION, + variables: { + conceptId: 'ACL00000-CMR', + collectionParams: { + limit: 20, + offset: 0 + } + } + }, + result: { + data: { + acl: mockPermission + } + } +} + +export const mockCollectionPermissionSearchWithPages = { + request: { + query: GET_COLLECTION_PERMISSION, + variables: { + conceptId: 'ACL00000-CMR', + collectionParams: { + limit: 20, + offset: 0 + } + } + }, + result: { + data: { + acl: mockPermissions + } + } +}