diff --git a/CHANGELOG.md b/CHANGELOG.md index f97167873..c0c7bc585 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,7 @@ This changelog follows the principles of [Keep a Changelog](https://keepachangel ### Fixed +- Publish Dataset modal custom messages now render configured HTML links and line breaks. - Edit Dataset Terms: navigate to the draft version of the dataset after saving changes to the terms, instead of the latest published version. - After saving on either Edit Template tab (Metadata or Terms), the user is redirected to the templates listing with a success toast instead of staying on the edit page. - Edit Template breadcrumb on the Terms page no longer renders the dataset's "Terms and Guestbook" label (templates have no guestbook). diff --git a/src/sections/dataset/publish-dataset/PublishDatasetModal.tsx b/src/sections/dataset/publish-dataset/PublishDatasetModal.tsx index e1300cef8..d8c8b3d99 100644 --- a/src/sections/dataset/publish-dataset/PublishDatasetModal.tsx +++ b/src/sections/dataset/publish-dataset/PublishDatasetModal.tsx @@ -1,4 +1,6 @@ import { useState } from 'react' +import DOMPurify from 'dompurify' +import parse from 'html-react-parser' import { useTranslation } from 'react-i18next' import { useNavigate } from 'react-router-dom' import { Button, Modal, Spinner, Stack } from '@iqss/dataverse-design-system' @@ -81,6 +83,9 @@ export function PublishDatasetModal({ )?.value const shouldShowCustomPopupText = Boolean(datasetPublishPopupCustomText?.trim()) + const sanitizedDatasetPublishPopupCustomText = datasetPublishPopupCustomText + ? DOMPurify.sanitize(datasetPublishPopupCustomText, { USE_PROFILES: { html: true } }) + : '' const shouldShowDisclaimer = Boolean(publishDisclaimerText?.trim()) const [isDisclaimerAccepted, setIsDisclaimerAccepted] = useState(false) @@ -119,7 +124,9 @@ export function PublishDatasetModal({ {shouldShowCustomPopupText && (
-

{datasetPublishPopupCustomText}

+

+ {parse(sanitizedDatasetPublishPopupCustomText)} +

)} diff --git a/tests/component/sections/dataset/dataset-publish/PublishDatasetModal.spec.tsx b/tests/component/sections/dataset/dataset-publish/PublishDatasetModal.spec.tsx index a585e9d76..f3ca69847 100644 --- a/tests/component/sections/dataset/dataset-publish/PublishDatasetModal.spec.tsx +++ b/tests/component/sections/dataset/dataset-publish/PublishDatasetModal.spec.tsx @@ -298,4 +298,36 @@ describe('PublishDatasetModal', () => { cy.findByText(popupText).should('exist') cy.findByRole('button', { name: 'Continue' }).should('not.be.disabled') }) + + it('Renders sanitized HTML in the custom popup text', () => { + const dataverseInfoRepository = new DataverseInfoMockRepository() + const popupText = + 'Read the Dataverse guide
before publishing.' + + dataverseInfoRepository.getZipDownloadLimit = cy + .stub() + .resolves(SettingMother.createZipDownloadLimit()) + dataverseInfoRepository.getMaxEmbargoDurationInMonths = cy + .stub() + .resolves(SettingMother.createMaxEmbargoDurationInMonths()) + dataverseInfoRepository.getHasPublicStore = cy + .stub() + .resolves(SettingMother.createHasPublicStore()) + dataverseInfoRepository.getExternalStatusesAllowed = cy + .stub() + .resolves(SettingMother.createExternalStatusesAllowed()) + dataverseInfoRepository.getDatasetPublishPopupCustomText = cy + .stub() + .resolves(SettingMother.createDatasetPublishPopupCustomText(popupText)) + dataverseInfoRepository.getPublishDatasetDisclaimerText = cy.stub().resolves('') + + mountPublishDatasetModal({ dataverseInfoRepository }) + + cy.findByRole('link', { name: 'Dataverse guide' }).should( + 'have.attr', + 'href', + 'https://guides.dataverse.org' + ) + cy.get('p').contains('before publishing.').find('br').should('exist') + }) })