From 53babaa528cbbe2b1932ea9e5cade572468c4d57 Mon Sep 17 00:00:00 2001 From: Mandy Parson Date: Mon, 28 Apr 2025 11:26:58 -0600 Subject: [PATCH 01/11] MMT-3990: Adding Published and Draft Visualizations --- static/src/js/pages/SearchList/SearchList.jsx | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/static/src/js/pages/SearchList/SearchList.jsx b/static/src/js/pages/SearchList/SearchList.jsx index bd6609aab..0591dd0f4 100644 --- a/static/src/js/pages/SearchList/SearchList.jsx +++ b/static/src/js/pages/SearchList/SearchList.jsx @@ -88,6 +88,15 @@ const SearchList = ({ limit }) => { } } + if (formattedType === conceptTypes.Visualizations) { + params = { + limit, + offset, + provider: providerParam, + sortKey: sortKeyParam + } + } + const { data } = useSuspenseQuery(conceptTypeQueries[formattedType], { variables: { params @@ -124,13 +133,29 @@ const SearchList = ({ limit }) => { if (!newCellData && conceptType === 'visualizations') newCellData = '' + let newCellData = cellData + + if (!newCellData && conceptType === 'visualizations') newCellData = '' + return ( {newCellData} + {newCellData} ) }, [conceptType]) + const buildEllipsisTextCell = useCallback((cellData) => { + let newCellData = cellData + + if (!newCellData && conceptType === 'visualizations') newCellData = '' + + return ( + + {newCellData} + + ) + }, []) const buildEllipsisTextCell = useCallback((cellData) => { let newCellData = cellData @@ -248,9 +273,8 @@ const SearchList = ({ limit }) => { className: 'col-auto', dataAccessorFn: buildEllipsisTextCell, dataKey: 'title', - // To be completed in MMT-4023 // SortFn, - // sortKey: 'title', + // sortKey: 'title', // Need to enable something to get this work title: 'Long Name' }, { From 91fbe7fc8830ca35eb22c36a2f2e785952b91f2e Mon Sep 17 00:00:00 2001 From: Mandy Parson Date: Tue, 29 Apr 2025 15:20:05 -0600 Subject: [PATCH 02/11] MMT-3990: Removing Search Bar for now --- static/src/js/pages/SearchPage/SearchPage.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/static/src/js/pages/SearchPage/SearchPage.jsx b/static/src/js/pages/SearchPage/SearchPage.jsx index 094a74136..71a2b23b2 100644 --- a/static/src/js/pages/SearchPage/SearchPage.jsx +++ b/static/src/js/pages/SearchPage/SearchPage.jsx @@ -210,7 +210,6 @@ const SearchBar = () => { * ) */ -// Remove this in MMT-4023 const renderSearchBar = () => { const { type: searchTypeFromPath } = useParams() // Don't render SearchBar for Visualizations @@ -229,6 +228,7 @@ const SearchPageHeader = () => { title={`All ${capitalize(getHumanizedNameFromTypeParam(conceptType))}s`} pageType="secondary" beforeActions={renderSearchBar()} + beforeActions={renderSearchBar()} breadcrumbs={ [ { From 45e9260ea8edc111702967f29f245fe7745fefd4 Mon Sep 17 00:00:00 2001 From: Mandy Parson Date: Fri, 2 May 2025 10:56:19 -0600 Subject: [PATCH 03/11] MMT-3991: Saving progress --- .../CollectionAssociationForm.jsx | 17 +- .../components/DraftPreview/DraftPreview.jsx | 38 +- static/src/js/components/For/For.jsx | 3 + static/src/js/components/Layout/Layout.jsx | 4 +- .../ManageCollectionAssociation.jsx | 15 +- .../MetadataPreview/MetadataPreview.jsx | 8 +- .../PublishPreview/PublishPreview.jsx | 43 +- .../components/RevisionList/RevisionList.jsx | 15 +- .../js/constants/conceptTypeDraftQueries.js | 4 +- static/src/js/constants/conceptTypeQueries.js | 2 + .../src/js/constants/deleteMutationTypes.js | 12 +- .../mutations/deleteVisualization.js | 22 + .../js/operations/queries/getVisualization.js | 35 + .../queries/getVisualizationDraft.js | 39 + .../CollectionAssociationFormPage.jsx | 20 +- static/src/js/pages/DraftPage/DraftPage.jsx | 27 +- .../ManageCollectionAssociationPage.jsx | 18 +- .../pages/OrderOptionPage/OrderOptionPage.jsx | 7 +- .../RevisionListPage/RevisionListPage.jsx | 17 +- .../GraphQLProvider/GraphQLProvider.jsx | 3 + static/src/js/schemas/uiForms/index.js | 6 +- .../uiForms/visualizationMapsConfiguration.js | 66 ++ .../visualizationTilesConfiguration.js | 82 ++ .../umm/ummVisSchema/maps/ummVisMapsSchema.js | 52 + .../tiles/ummVisTilesDefinitions.js | 340 ++++++ .../ummVisSchema/tiles/ummVisTilesSchema.js | 642 ++++++++++++ .../umm/ummVisSchema/ummVisRootDefinitions.js | 977 ++++++++++++++++++ .../umm/ummVisSchema/ummVisRootSchema.js | 166 +++ .../src/js/utils/getCombinedUmmVisSchema.js | 87 ++ static/src/js/utils/getUmmSchema.js | 5 + 30 files changed, 2659 insertions(+), 113 deletions(-) create mode 100644 static/src/js/operations/mutations/deleteVisualization.js create mode 100644 static/src/js/operations/queries/getVisualization.js create mode 100644 static/src/js/operations/queries/getVisualizationDraft.js create mode 100644 static/src/js/schemas/uiForms/visualizationMapsConfiguration.js create mode 100644 static/src/js/schemas/uiForms/visualizationTilesConfiguration.js create mode 100644 static/src/js/schemas/umm/ummVisSchema/maps/ummVisMapsSchema.js create mode 100644 static/src/js/schemas/umm/ummVisSchema/tiles/ummVisTilesDefinitions.js create mode 100644 static/src/js/schemas/umm/ummVisSchema/tiles/ummVisTilesSchema.js create mode 100644 static/src/js/schemas/umm/ummVisSchema/ummVisRootDefinitions.js create mode 100644 static/src/js/schemas/umm/ummVisSchema/ummVisRootSchema.js create mode 100644 static/src/js/utils/getCombinedUmmVisSchema.js diff --git a/static/src/js/components/CollectionAssociationForm/CollectionAssociationForm.jsx b/static/src/js/components/CollectionAssociationForm/CollectionAssociationForm.jsx index b41f165f2..900c6fce2 100644 --- a/static/src/js/components/CollectionAssociationForm/CollectionAssociationForm.jsx +++ b/static/src/js/components/CollectionAssociationForm/CollectionAssociationForm.jsx @@ -19,7 +19,7 @@ import { useMutation, useQuery } from '@apollo/client' -import { camelCase, cloneDeep } from 'lodash-es' +import { camelCase, capitalize, cloneDeep, trimEnd } from 'lodash-es' import moment from 'moment' @@ -47,7 +47,6 @@ import collectionAssociationUiSchema from '@/js/schemas/uiSchemas/CollectionAsso import collectionAssociationSearch from '@/js/utils/collectionAssociationSearch' import errorLogger from '@/js/utils/errorLogger' -import getConceptTypeByConceptId from '@/js/utils/getConceptTypeByConceptId' import removeEmpty from '@/js/utils/removeEmpty' @@ -68,7 +67,7 @@ import conceptTypeQueries from '@/js/constants/conceptTypeQueries' * ) */ const CollectionAssociationForm = ({ metadata }) => { - const { conceptId } = useParams() + const { conceptId, type } = useParams() const navigate = useNavigate() @@ -90,7 +89,7 @@ const CollectionAssociationForm = ({ metadata }) => { setCollectionLoading(false) }, [metadata]) - const derivedConceptType = getConceptTypeByConceptId(conceptId) + const formattedType = capitalize(trimEnd(type, 's')) const limit = 20 const activePage = parseInt(searchParams.get('page'), 10) || 1 @@ -130,9 +129,9 @@ const CollectionAssociationForm = ({ metadata }) => { limit: 2000 } } - }, { skip: derivedConceptType !== conceptIdTypes.O }) + }, { skip: formattedType !== conceptIdTypes.O }) - if (derivedConceptType === conceptIdTypes.O) { + if (formattedType === conceptIdTypes.O) { const { required } = schema required.push('ServiceField') @@ -248,7 +247,7 @@ const CollectionAssociationForm = ({ metadata }) => { associatedConceptIds: collectionConceptIds } - if (derivedConceptType === conceptIdTypes.O) { + if (formattedType === conceptIdTypes.O) { const serviceItems = serviceData?.services.items const { ServiceField: name } = searchFormData const serviceConceptId = serviceItems?.filter((service) => service.name === name)[0].conceptId @@ -266,10 +265,10 @@ const CollectionAssociationForm = ({ metadata }) => { variables, onCompleted: () => { setLoading(true) - if (derivedConceptType === conceptIdTypes.O) { + if (formattedType === conceptIdTypes.O) { navigate(`/order-options/${conceptId}`) } else { - navigate(`/${pluralize(camelCase(derivedConceptType)).toLowerCase()}/${conceptId}/collection-association`) + navigate(`/${pluralize(camelCase(formattedType)).toLowerCase()}/${conceptId}/collection-association`) } addNotification({ diff --git a/static/src/js/components/DraftPreview/DraftPreview.jsx b/static/src/js/components/DraftPreview/DraftPreview.jsx index 86de4bc46..a9c8b8017 100644 --- a/static/src/js/components/DraftPreview/DraftPreview.jsx +++ b/static/src/js/components/DraftPreview/DraftPreview.jsx @@ -1,17 +1,20 @@ -import React from 'react' -import Container from 'react-bootstrap/Container' -import Row from 'react-bootstrap/Row' -import Col from 'react-bootstrap/Col' import { useParams } from 'react-router' import { useSuspenseQuery } from '@apollo/client' +import Col from 'react-bootstrap/Col' +import Container from 'react-bootstrap/Container' +import React from 'react' +import Row from 'react-bootstrap/Row' import validator from '@rjsf/validator-ajv8' +import { capitalize, trimEnd } from 'lodash-es' +import { preview } from 'vite' +import { formatError } from 'graphql' import ErrorBoundary from '../ErrorBoundary/ErrorBoundary' -import formConfigurations from '../../schemas/uiForms' import MetadataPreview from '../MetadataPreview/MetadataPreview' import PreviewProgress from '../PreviewProgress/PreviewProgress' -import getConceptTypeByDraftConceptId from '../../utils/getConceptTypeByDraftConceptId' +import formConfigurations from '../../schemas/uiForms' + import getUmmSchema from '../../utils/getUmmSchema' import conceptTypeDraftQueries from '../../constants/conceptTypeDraftQueries' @@ -28,20 +31,21 @@ import './DraftPreview.scss' * ) */ const DraftPreview = () => { - const { conceptId } = useParams() + const { conceptId, draftType } = useParams() - const derivedConceptType = getConceptTypeByDraftConceptId(conceptId) + let formattedDraftType = capitalize(trimEnd(draftType, 's')) - const { data } = useSuspenseQuery(conceptTypeDraftQueries[derivedConceptType], { + const { data } = useSuspenseQuery(conceptTypeDraftQueries[formattedDraftType], { variables: { params: { conceptId, - conceptType: derivedConceptType + conceptType: formattedDraftType } } }) const { draft } = data + console.log('πŸš€ ~ DraftPreview ~ draft:', draft) // This may be due to a CMR lag error and affects functionality in ErrorBanner if (!draft) { @@ -52,8 +56,16 @@ const DraftPreview = () => { ummMetadata } = draft + const { VisualizationType = '' } = ummMetadata + + if (VisualizationType === 'tiles') { + formattedDraftType = `${formattedDraftType}_Tiles` + } else { + formattedDraftType = `${formattedDraftType}_Maps` + } + // Get the UMM Schema for the draft - const schema = getUmmSchema(derivedConceptType) + const schema = getUmmSchema(formattedDraftType) // Validate ummMetadata const { errors: validationErrors } = validator.validateFormData(ummMetadata, schema) @@ -61,7 +73,7 @@ const DraftPreview = () => { const { errors } = ummMetadata // Pull the formSections out of the formConfigurations - const formSections = formConfigurations[derivedConceptType] + const formSections = formConfigurations[formattedDraftType] return ( @@ -94,7 +106,7 @@ const DraftPreview = () => { diff --git a/static/src/js/components/For/For.jsx b/static/src/js/components/For/For.jsx index 0b882beda..3fe5bd156 100644 --- a/static/src/js/components/For/For.jsx +++ b/static/src/js/components/For/For.jsx @@ -35,6 +35,9 @@ export const For = ({ each, empty }) => { + // console.log("πŸš€ ~ empty:", empty) + // console.log("πŸš€ ~ each:", each) + // console.log("πŸš€ ~ children:", children) const items = each.map((item, index) => children(item, index)) if (isEmpty(items) && empty) return empty diff --git a/static/src/js/components/Layout/Layout.jsx b/static/src/js/components/Layout/Layout.jsx index e6faaaeb0..865976e17 100644 --- a/static/src/js/components/Layout/Layout.jsx +++ b/static/src/js/components/Layout/Layout.jsx @@ -19,13 +19,13 @@ import { import useAuthContext from '@/js/hooks/useAuthContext' import usePermissions from '@/js/hooks/usePermissions' +import { getApplicationConfig, getUmmVersionsConfig } from 'sharedUtils/getConfig' + import Button from '../Button/Button' import ErrorBoundary from '../ErrorBoundary/ErrorBoundary' import PrimaryNavigation from '../PrimaryNavigation/PrimaryNavigation' import AboutModal from '../AboutModal/AboutModal' -import { getApplicationConfig, getUmmVersionsConfig } from '../../../../../sharedUtils/getConfig' - import './Layout.scss' /* diff --git a/static/src/js/components/ManageCollectionAssociation/ManageCollectionAssociation.jsx b/static/src/js/components/ManageCollectionAssociation/ManageCollectionAssociation.jsx index 7ea0d39c0..95023999e 100644 --- a/static/src/js/components/ManageCollectionAssociation/ManageCollectionAssociation.jsx +++ b/static/src/js/components/ManageCollectionAssociation/ManageCollectionAssociation.jsx @@ -3,7 +3,7 @@ import { Col, Row } from 'react-bootstrap' -import { camelCase } from 'lodash-es' +import { camelCase, capitalize, trimEnd } from 'lodash-es' import { useMutation, useSuspenseQuery } from '@apollo/client' import { useParams } from 'react-router' import { useSearchParams } from 'react-router-dom' @@ -25,7 +25,6 @@ import useNotificationsContext from '@/js/hooks/useNotificationsContext' import { DELETE_ASSOCIATION } from '@/js/operations/mutations/deleteAssociation' import errorLogger from '@/js/utils/errorLogger' -import getConceptTypeByConceptId from '@/js/utils/getConceptTypeByConceptId' /** * Renders a ManageCollectionAssociation component @@ -37,7 +36,7 @@ import getConceptTypeByConceptId from '@/js/utils/getConceptTypeByConceptId' * ) */ const ManageCollectionAssociation = () => { - const { conceptId } = useParams() + const { conceptId, type } = useParams() const { addNotification } = useNotificationsContext() @@ -45,7 +44,7 @@ const ManageCollectionAssociation = () => { const [collectionConceptIds, setCollectionConceptIds] = useState([]) const [showDeleteModal, setShowDeleteModal] = useState(false) - const derivedConceptType = getConceptTypeByConceptId(conceptId) + const formattedType = capitalize(trimEnd(type, 's')) const limit = 20 const activePage = parseInt(searchParams.get('page'), 10) || 1 @@ -74,13 +73,13 @@ const ManageCollectionAssociation = () => { } } - const { data, refetch } = useSuspenseQuery(conceptTypeQueries[derivedConceptType], { + const { data, refetch } = useSuspenseQuery(conceptTypeQueries[formattedType], { variables: params }) const [deleteAssociationMutation] = useMutation(DELETE_ASSOCIATION, { refetchQueries: [{ - query: conceptTypeQueries[derivedConceptType], + query: conceptTypeQueries[formattedType], variables: params }], onCompleted: () => { @@ -100,7 +99,7 @@ const ManageCollectionAssociation = () => { variant: 'danger' }) - errorLogger(`Unable to disassociate collection record for ${derivedConceptType}`, 'Manage Collection Association: deleteAssociation Mutation') + errorLogger(`Unable to disassociate collection record for ${formattedType}`, 'Manage Collection Association: deleteAssociation Mutation') } }) @@ -226,7 +225,7 @@ const ManageCollectionAssociation = () => { handleRefreshPage() }) - const { [camelCase(derivedConceptType)]: concept } = data + const { [camelCase(formattedType)]: concept } = data const { collections: associatedCollections } = concept diff --git a/static/src/js/components/MetadataPreview/MetadataPreview.jsx b/static/src/js/components/MetadataPreview/MetadataPreview.jsx index 6f1eac59f..ad5081605 100644 --- a/static/src/js/components/MetadataPreview/MetadataPreview.jsx +++ b/static/src/js/components/MetadataPreview/MetadataPreview.jsx @@ -19,6 +19,7 @@ import conceptTypeQueries from '../../constants/conceptTypeQueries' import { getApplicationConfig } from '../../../../../sharedUtils/getConfig' import '@edsc/metadata-preview/dist/style.min.css' +import { capitalize, trimEnd } from 'lodash-es' /** * MetadataPreview * @typedef {Object} MetadataPreview @@ -49,16 +50,17 @@ const MetadataPreview = ({ conceptId } - let query = conceptTypeQueries[conceptType] + const formattedConceptType = capitalize(trimEnd(conceptType, 's')) + let query = conceptTypeQueries[formattedConceptType] let conceptKey = conceptType.toLowerCase() if (isDraft) { conceptKey = 'draft' - query = conceptTypeDraftQueries[getConceptTypeByDraftConceptId(conceptId)] + query = conceptTypeDraftQueries[formattedConceptType] params = { ...params, - conceptType: getConceptTypeByDraftConceptId(conceptId) + conceptType: formattedConceptType } } diff --git a/static/src/js/components/PublishPreview/PublishPreview.jsx b/static/src/js/components/PublishPreview/PublishPreview.jsx index 89df81124..dbee09d28 100644 --- a/static/src/js/components/PublishPreview/PublishPreview.jsx +++ b/static/src/js/components/PublishPreview/PublishPreview.jsx @@ -37,12 +37,12 @@ import Page from '@/js/components/Page/Page' import PageHeader from '@/js/components/PageHeader/PageHeader' import errorLogger from '@/js//utils/errorLogger' -import getConceptTypeByConceptId from '@/js//utils/getConceptTypeByConceptId' import removeMetadataKeys from '@/js//utils/removeMetadataKeys' import constructDownloadableFile from '@/js//utils/constructDownloadableFile' import getConceptTypeByDraftConceptId from '@/js//utils/getConceptTypeByDraftConceptId' import './PublishPreview.scss' +import { capitalize, trimEnd } from 'lodash-es' /** * Renders a PublishPreviewHeader component @@ -54,11 +54,11 @@ import './PublishPreview.scss' * ) */ const PublishPreviewHeader = () => { - const { conceptId } = useParams() + const { conceptId, type } = useParams() - const navigate = useNavigate() + const formattedType = capitalize(trimEnd(type, 's')) - const derivedConceptType = getConceptTypeByConceptId(conceptId) + const navigate = useNavigate() const [showDeleteModal, setShowDeleteModal] = useState(false) const [showTagModal, setShowTagModal] = useState(false) @@ -76,18 +76,18 @@ const PublishPreviewHeader = () => { } const { addNotification } = useNotificationsContext() - const [deleteMutation] = useMutation(deleteMutationTypes[derivedConceptType], { + const [deleteMutation] = useMutation(deleteMutationTypes[formattedType], { update: (cache) => { cache.modify({ fields: { // Remove the list of the derivedContceptType from the cache. This ensures that if the user returns to the list page they will see the correct data. - [pluralize(derivedConceptType).toLowerCase()]: () => {} + [pluralize(formattedType).toLowerCase()]: () => {} } }) } }) - const { data } = useSuspenseQuery(conceptTypeQueries[derivedConceptType], { + const { data } = useSuspenseQuery(conceptTypeQueries[formattedType], { variables: { params: { conceptId @@ -95,7 +95,7 @@ const PublishPreviewHeader = () => { } }) - const { [derivedConceptType.toLowerCase()]: concept } = data + const { [formattedType.toLowerCase()]: concept } = data // This may be due to a CMR lag error and affects functionality in ErrorBanner if (!concept) { @@ -142,7 +142,7 @@ const PublishPreviewHeader = () => { // Removes the value from the metadata that has to be unique const modifiedMetadata = removeMetadataKeys(ummMetadata, ['Name', 'LongName', 'ShortName', 'EntryTitle']) - ingestMutation(derivedConceptType, modifiedMetadata, cloneNativeId, providerId) + ingestMutation(formattedType, modifiedMetadata, cloneNativeId, providerId) } // Handles the user selecting download record @@ -190,7 +190,7 @@ const PublishPreviewHeader = () => { toggleShowDeleteModal(false) // Navigate to the search page - navigate(`/${pluralize(derivedConceptType).toLowerCase()}`) + navigate(`/${pluralize(formattedType).toLowerCase()}`) }, onError: (deleteError) => { // Add an error notification @@ -220,12 +220,12 @@ const PublishPreviewHeader = () => { }, { icon: FaEye, - to: `/${pluralize(derivedConceptType).toLowerCase()}/${conceptId}/revisions`, + to: `/${pluralize(formattedType).toLowerCase()}/${conceptId}/revisions`, title: 'View Revisions', count: revisionCount }, ...( - derivedConceptType === conceptTypes.Collection + formattedType === conceptTypes.Collection ? [ { icon: FaEye, @@ -250,7 +250,7 @@ const PublishPreviewHeader = () => { : [ { icon: FaEye, - to: `/${pluralize(derivedConceptType).toLowerCase()}/${conceptId}/collection-association`, + to: `/${pluralize(formattedType).toLowerCase()}/${conceptId}/collection-association`, title: 'Collection Associations' } ] @@ -260,8 +260,8 @@ const PublishPreviewHeader = () => { breadcrumbs={ [ { - label: `${pluralize(derivedConceptType)}`, - to: `/${pluralize(derivedConceptType).toLowerCase()}` + label: `${pluralize(formattedType)}`, + to: `/${pluralize(formattedType).toLowerCase()}` }, { label: pageTitle, @@ -274,7 +274,7 @@ const PublishPreviewHeader = () => { [ { icon: FaEdit, - onClick: () => ingestMutation(derivedConceptType, ummMetadata, nativeId, providerId), + onClick: () => ingestMutation(formattedType, ummMetadata, nativeId, providerId), title: 'Edit', iconTitle: 'A edit icon', variant: 'primary' @@ -383,15 +383,16 @@ const PublishPreviewPlaceholder = () => ( */ const PublishPreview = ({ isRevision }) => { const { - conceptId + conceptId, + type } = useParams() const navigate = useNavigate() - const derivedConceptType = getConceptTypeByConceptId(conceptId) + const formattedType = capitalize(trimEnd(type, 's')) const viewPublishedRecord = () => { - navigate(`/${pluralize(derivedConceptType).toLowerCase()}/${conceptId}`) + navigate(`/${pluralize(formattedType).toLowerCase()}/${conceptId}`) } return ( @@ -408,7 +409,7 @@ const PublishPreview = ({ isRevision }) => { {' '} You are viewing an older revision of this {' '} - {`${derivedConceptType}.`} + {`${formattedType}.`} {' '}