From 129f036e3af25d82989e6679f9f76061f77bf3bc Mon Sep 17 00:00:00 2001 From: Mandy Parson Date: Mon, 29 Sep 2025 09:59:52 -0600 Subject: [PATCH 1/6] MMT-4058: Enabling citation association to collection --- static/src/js/operations/queries/getCitation.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/static/src/js/operations/queries/getCitation.js b/static/src/js/operations/queries/getCitation.js index 2d8d69eb4..9bc1bdd7b 100644 --- a/static/src/js/operations/queries/getCitation.js +++ b/static/src/js/operations/queries/getCitation.js @@ -1,10 +1,20 @@ import { gql } from '@apollo/client' export const GET_CITATION = gql` - query GetCitation ($params: CitationInput) { + query GetCitation ($params: CitationInput, $collectionsParams: CollectionsInput) { citation (params: $params) { abstract citationMetadata + collections (params: $collectionsParams) { + count + items { + conceptId + provider + shortName + title + version + } + } conceptId identifier identifierType From 2af1f185f92f844e42b2800d204ba417e17e393e Mon Sep 17 00:00:00 2001 From: Mandy Parson Date: Mon, 29 Sep 2025 10:46:39 -0600 Subject: [PATCH 2/6] MMT-4058: Adding 'name' to query --- static/src/js/operations/queries/getCitation.js | 1 + 1 file changed, 1 insertion(+) diff --git a/static/src/js/operations/queries/getCitation.js b/static/src/js/operations/queries/getCitation.js index 9bc1bdd7b..04b12e8ee 100644 --- a/static/src/js/operations/queries/getCitation.js +++ b/static/src/js/operations/queries/getCitation.js @@ -18,6 +18,7 @@ export const GET_CITATION = gql` conceptId identifier identifierType + name, pageTitle: name nativeId providerId From bb5f616ae5f7fed2b77aabbfaa1f3e870e293a27 Mon Sep 17 00:00:00 2001 From: Mandy Parson Date: Mon, 29 Sep 2025 14:04:12 -0600 Subject: [PATCH 3/6] MMT-4058: Fixing disabled rows issue --- .../CollectionAssociationForm.jsx | 10 ++--- .../CollectionAssociationFormPage.jsx | 40 +++++++++++++------ 2 files changed, 33 insertions(+), 17 deletions(-) diff --git a/static/src/js/components/CollectionAssociationForm/CollectionAssociationForm.jsx b/static/src/js/components/CollectionAssociationForm/CollectionAssociationForm.jsx index af966a0df..bfa19d01a 100644 --- a/static/src/js/components/CollectionAssociationForm/CollectionAssociationForm.jsx +++ b/static/src/js/components/CollectionAssociationForm/CollectionAssociationForm.jsx @@ -309,15 +309,15 @@ const CollectionAssociationForm = ({ metadata }) => { let checked = null const { conceptId: collectionConceptId } = rowData - const { associationDetails } = fetchedDraft - const { collections } = associationDetails || {} + const { collections = {} } = fetchedDraft + const { items } = collections // Checks if collection is already associated to the record. - if (collections) { - const associatedCollection = collections.filter( + if (items) { + const associatedCollection = items.find( (item) => item.conceptId === collectionConceptId ) - if (associatedCollection[0]?.conceptId === collectionConceptId) { + if (associatedCollection) { disabled = true checked = true } diff --git a/static/src/js/pages/CollectionAssociationFormPage/CollectionAssociationFormPage.jsx b/static/src/js/pages/CollectionAssociationFormPage/CollectionAssociationFormPage.jsx index b1c0bd075..4cce67d1d 100644 --- a/static/src/js/pages/CollectionAssociationFormPage/CollectionAssociationFormPage.jsx +++ b/static/src/js/pages/CollectionAssociationFormPage/CollectionAssociationFormPage.jsx @@ -82,17 +82,33 @@ const CollectionAssociationFormPageHeader = () => { * * ) */ -const CollectionAssociationFormPage = () => ( - } - > - - - - - - -) +const CollectionAssociationFormPage = () => { + const { conceptId } = useParams() + + const derivedConceptType = getConceptTypeByConceptId(conceptId) + + const { data } = useSuspenseQuery(conceptTypeQueries[derivedConceptType], { + variables: { + params: { + conceptId + } + } + }) + + const { [camelCase(derivedConceptType)]: concept } = data + + return ( + } + > + + + + + + + ) +} export default CollectionAssociationFormPage From fe54f27b8bf57a4d8dcf5ec4054fb23f77ff9a5c Mon Sep 17 00:00:00 2001 From: Mandy Parson Date: Tue, 30 Sep 2025 09:30:30 -0600 Subject: [PATCH 4/6] MMT-4058: Adding tests, fixing comment/warnings elsewhere --- .../__mocks__/CollectionAssociationResults.js | 10 + .../ManageCollectionAssociation.jsx | 2 +- .../CollectionAssociationFormPage.test.jsx | 323 ++++++++++++++++++ 3 files changed, 334 insertions(+), 1 deletion(-) create mode 100644 static/src/js/pages/CollectionAssociationFormPage/__tests__/CollectionAssociationFormPage.test.jsx diff --git a/static/src/js/components/CollectionAssociationForm/__tests__/__mocks__/CollectionAssociationResults.js b/static/src/js/components/CollectionAssociationForm/__tests__/__mocks__/CollectionAssociationResults.js index e10d01403..aaf11c650 100644 --- a/static/src/js/components/CollectionAssociationForm/__tests__/__mocks__/CollectionAssociationResults.js +++ b/static/src/js/components/CollectionAssociationForm/__tests__/__mocks__/CollectionAssociationResults.js @@ -165,6 +165,7 @@ export const mockTool = { version: '1.2.0' }, name: 'Collection Association Mock Test', + pageTitle: 'Collection Association Mock Test', organizations: [ { roles: [ @@ -180,6 +181,15 @@ export const mockTool = { quality: null, revisionId: '1', revisionDate: '2024-03-21T15:01:58.533Z', + revisions: { + count: 1, + items: { + conceptId: 'T1200000098-MMT_2', + revisionDate: '2024-03-21T15:01:58.533Z', + revisionId: '1', + userId: 'user1' + } + }, relatedUrls: null, searchAction: null, supportedBrowsers: null, diff --git a/static/src/js/components/ManageCollectionAssociation/ManageCollectionAssociation.jsx b/static/src/js/components/ManageCollectionAssociation/ManageCollectionAssociation.jsx index 7ea0d39c0..dcab4dfdf 100644 --- a/static/src/js/components/ManageCollectionAssociation/ManageCollectionAssociation.jsx +++ b/static/src/js/components/ManageCollectionAssociation/ManageCollectionAssociation.jsx @@ -217,7 +217,7 @@ const ManageCollectionAssociation = () => { }) // Handle refresh, calls getMetadata to get the list of association - // TODO: See if we can get rid of this refresh button. + // TODO: MMT-4089 See if we can get rid of this refresh button. const handleRefreshPage = () => { refetch() } diff --git a/static/src/js/pages/CollectionAssociationFormPage/__tests__/CollectionAssociationFormPage.test.jsx b/static/src/js/pages/CollectionAssociationFormPage/__tests__/CollectionAssociationFormPage.test.jsx new file mode 100644 index 000000000..68617f506 --- /dev/null +++ b/static/src/js/pages/CollectionAssociationFormPage/__tests__/CollectionAssociationFormPage.test.jsx @@ -0,0 +1,323 @@ +// CollectionAssociationFormPage.test.jsx + +import React, { Suspense } from 'react' +import { render, screen } from '@testing-library/react' +import { MockedProvider } from '@apollo/client/testing' +import { + MemoryRouter, + Route, + Routes +} from 'react-router' + +import { GET_TOOL } from '@/js/operations/queries/getTool' +import { GET_ORDER_OPTION } from '@/js/operations/queries/getOrderOption' + +import CollectionAssociationForm from '@/js/components/CollectionAssociationForm/CollectionAssociationForm' +import CollectionAssociationFormPage from '../CollectionAssociationFormPage' + +vi.mock('@/js/components/CollectionAssociationForm/CollectionAssociationForm') + +const mockTool = { + accessConstraints: null, + ancillaryKeywords: null, + associationDetails: { + collections: [ + { conceptId: 'C1200000035-SEDAC' }, + { conceptId: 'C1200000034-SEDAC' } + ] + }, + conceptId: 'T1234-MMT', + contactGroups: null, + contactPersons: null, + description: 'mock description', + doi: null, + nativeId: 'MMT_e090f57a-d611-48eb-a5d2-c6a94073f3f9', + lastUpdatedDate: null, + longName: 'mock long name', + metadataSpecification: { + url: 'https://cdn.earthdata.nasa.gov/umm/tool/v1.2.0', + name: 'UMM-T', + version: '1.2.0' + }, + name: 'Mock Tool', + pageTitle: 'Mock Tool', + organizations: [ + { + roles: ['PUBLISHER'], + shortName: 'UCAR/NCAR/EOL/CEOPDM', + longName: 'CEOP Data Management, Earth Observing Laboratory, National Center for Atmospheric Research, University Corporation for Atmospheric Research', + urlValue: 'http://www.eol.ucar.edu/projects/ceop/dm/' + } + ], + providerId: 'MMT_2', + potentialAction: null, + quality: null, + revisionId: '1', + revisionDate: '2024-03-21T15:01:58.533Z', + revisions: { + count: 1, + items: { + conceptId: 'T1234-MMT', + revisionDate: '2024-03-21T15:01:58.533Z', + revisionId: '1', + userId: 'user1' + } + }, + relatedUrls: null, + searchAction: null, + supportedBrowsers: null, + supportedInputFormats: null, + supportedOperatingSystems: null, + supportedOutputFormats: null, + supportedSoftwareLanguages: null, + toolKeywords: [ + { + toolCategory: 'EARTH SCIENCE SERVICES', + toolTopic: 'DATA ANALYSIS AND VISUALIZATION', + toolTerm: 'CALIBRATION/VALIDATION' + } + ], + type: 'Downloadable Tool', + ummMetadata: { + URL: { + URLContentType: 'DistributionURL', + Type: 'GOTO WEB TOOL', + URLValue: 'mock url' + }, + Type: 'Downloadable Tool', + Description: 'mock description', + Version: '1', + ToolKeywords: [ + { + ToolCategory: 'EARTH SCIENCE SERVICES', + ToolTopic: 'DATA ANALYSIS AND VISUALIZATION', + ToolTerm: 'CALIBRATION/VALIDATION' + } + ], + Name: 'Mock Test', + Organizations: [ + { + Roles: ['PUBLISHER'], + ShortName: 'UCAR/NCAR/EOL/CEOPDM', + LongName: 'CEOP Data Management, Earth Observing Laboratory, National Center for Atmospheric Research, University Corporation for Atmospheric Research', + URLValue: 'http://www.eol.ucar.edu/projects/ceop/dm/' + } + ], + MetadataSpecification: { + URL: 'https://cdn.earthdata.nasa.gov/umm/tool/v1.2.0', + Name: 'UMM-T', + Version: '1.2.0' + }, + LongName: 'mock long name' + }, + url: { + urlContentType: 'DistributionURL', + type: 'GOTO WEB TOOL', + urlValue: 'mock url' + }, + useConstraints: null, + version: '1', + versionDescription: null, + collections: { + count: 2, + items: [ + { + title: '2000 Pilot Environmental Sustainability Index (ESI)', + conceptId: 'C1200000034-SEDAC', + entryTitle: '2000 Pilot Environmental Sustainability Index (ESI)', + shortName: 'CIESIN_SEDAC_ESI_2000', + version: '2000.00', + provider: 'SEDAC', + __typename: 'Collection' + }, + { + title: '2001 Environmental Sustainability Index (ESI)', + conceptId: 'C1200000035-SEDAC', + entryTitle: '2001 Environmental Sustainability Index (ESI)', + shortName: 'CIESIN_SEDAC_ESI_2001', + version: '2001.00', + provider: 'SEDAC', + __typename: 'Collection' + } + ], + __typename: 'CollectionList' + }, + __typename: 'Tool' +} + +const setup = ({ + mocks, + pageUrl +}) => { + render( + + + + + + + ) + } + /> + + + + ) +} + +describe('CollectionAssociationFormPage', () => { + describe('when showing the header for a Tool', () => { + test('should render the header', async () => { + const mocks = [{ + request: { + query: GET_TOOL, + variables: { params: { conceptId: 'T1234-MMT' } } + }, + result: { + data: { + tool: mockTool + } + } + }] + + setup({ + mocks, + pageUrl: '/tools/T1234-MMT/collection-association-search' + }) + + expect(await screen.findByText('Tools')).toBeInTheDocument() + expect(screen.getByRole('heading', { name: 'Mock Tool Collection Associations' })).toBeInTheDocument() + }) + }) + + describe('when showing the header for an Order Option', () => { + test('should render the header', async () => { + const mocks = [{ + request: { + query: GET_ORDER_OPTION, + variables: { + params: { conceptId: 'OO1234-MMT' } + } + }, + result: { + data: { + orderOption: { + associationDetails: { + collections: [ + { conceptId: 'C1200000001-PROVIDER' }, + { conceptId: 'C1200000002-PROVIDER' } + ] + }, + conceptId: 'OO1234-MMT', + deprecated: false, + description: 'Test Order Option Description', + form: 'Test Form', + name: 'Test Order Option', + nativeId: 'OO1234-MMT', + pageTitle: 'Test Order Option', + providerId: 'MMT_2', + revisionId: '1', + revisionDate: '2024-03-22T10:00:00.000Z', + scope: 'PROVIDER', + sortKey: 'Test Order Option', + collections: { + count: 2, + items: [ + { + title: 'Test Collection 1', + conceptId: 'C1200000001-PROVIDER', + entryTitle: 'Test Collection 1', + shortName: 'TEST_COLL_1', + version: '1', + provider: 'PROVIDER' + }, + { + title: 'Test Collection 2', + conceptId: 'C1200000002-PROVIDER', + entryTitle: 'Test Collection 2', + shortName: 'TEST_COLL_2', + version: '1', + provider: 'PROVIDER' + } + ] + } + } + } + } + }] + + setup({ + mocks, + pageUrl: '/order-options/OO1234-MMT/collection-association-search' + }) + + expect(await screen.findByText('Order Options')).toBeInTheDocument() + expect(screen.getByRole('heading', { name: 'Test Order Option Collection Associations' })).toBeInTheDocument() + }) + }) + + describe('when rendering the CollectionAssociationForm', () => { + test('should pass the correct props', async () => { + const mocks = [{ + request: { + query: GET_TOOL, + variables: { params: { conceptId: 'T1234-MMT' } } + }, + result: { + data: { + tool: mockTool + } + } + }] + + setup({ + mocks, + pageUrl: '/tools/T1234-MMT/collection-association-search' + }) + + // Wait for the query to resolve + await screen.findByText('Mock Tool Collection Associations') + + // Check if CollectionAssociationForm is rendered with correct props + expect(CollectionAssociationForm).toHaveBeenCalledWith( + expect.objectContaining({ + metadata: expect.objectContaining({ + conceptId: 'T1234-MMT', + name: 'Mock Tool' + }) + }), + expect.anything() + ) + }) + }) + + describe('breadcrumbs', () => { + test('should render correct breadcrumbs for tools', async () => { + const mocks = [{ + request: { + query: GET_TOOL, + variables: { params: { conceptId: 'T1234-MMT' } } + }, + result: { + data: { + tool: mockTool + } + } + }] + + setup({ + mocks, + pageUrl: '/tools/T1234-MMT/collection-association-search' + }) + + expect(await screen.findByText('Tools')).toBeInTheDocument() + expect(screen.getByText('Mock Tool')).toBeInTheDocument() + expect(screen.getByText('Collection Associations')).toBeInTheDocument() + expect(screen.getByText('Collection Association Search')).toBeInTheDocument() + }) + }) +}) From ba07e13760b7b3da41ca456bc06405570ef24316 Mon Sep 17 00:00:00 2001 From: Mandy Parson Date: Tue, 30 Sep 2025 13:22:57 -0600 Subject: [PATCH 5/6] MMT-4058: Removing comment --- .../__tests__/CollectionAssociationFormPage.test.jsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/static/src/js/pages/CollectionAssociationFormPage/__tests__/CollectionAssociationFormPage.test.jsx b/static/src/js/pages/CollectionAssociationFormPage/__tests__/CollectionAssociationFormPage.test.jsx index 68617f506..3af117b77 100644 --- a/static/src/js/pages/CollectionAssociationFormPage/__tests__/CollectionAssociationFormPage.test.jsx +++ b/static/src/js/pages/CollectionAssociationFormPage/__tests__/CollectionAssociationFormPage.test.jsx @@ -1,5 +1,3 @@ -// CollectionAssociationFormPage.test.jsx - import React, { Suspense } from 'react' import { render, screen } from '@testing-library/react' import { MockedProvider } from '@apollo/client/testing' From 4702849cb22a2524408a99f845e09c41b85ba9ff Mon Sep 17 00:00:00 2001 From: Mandy Parson Date: Thu, 2 Oct 2025 10:14:20 -0600 Subject: [PATCH 6/6] MMT-4058: PR feedback --- .../CollectionAssociationForm/CollectionAssociationForm.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/src/js/components/CollectionAssociationForm/CollectionAssociationForm.jsx b/static/src/js/components/CollectionAssociationForm/CollectionAssociationForm.jsx index bfa19d01a..f1a823a1c 100644 --- a/static/src/js/components/CollectionAssociationForm/CollectionAssociationForm.jsx +++ b/static/src/js/components/CollectionAssociationForm/CollectionAssociationForm.jsx @@ -306,7 +306,7 @@ const CollectionAssociationForm = ({ metadata }) => { // Creates an action cell based on the current concept type const buildActionsCell = useCallback((cellData, rowData) => { let disabled = false - let checked = null + let checked = false const { conceptId: collectionConceptId } = rowData const { collections = {} } = fetchedDraft