diff --git a/public/locales/en/dataset.json b/public/locales/en/dataset.json index 9b970a3c3..916ab30b4 100644 --- a/public/locales/en/dataset.json +++ b/public/locales/en/dataset.json @@ -58,8 +58,25 @@ "uploadFiles": "Upload Files" }, "alerts": { - "draftVersion": "This draft version needs to be published. When ready for sharing, please publish it so that others can see these changes", - "requestedVersionNotFound": "Info – Version {0} was not found. This is version {1}", - "unpublishedDataset": "Privately share this dataset before it is published: {0}" + "draftVersion": { + "heading": "This draft version needs to be published", + "alertText": "When ready for sharing, please publish it so that others can see these changes" + }, + "requestedVersionNotFound": { + "heading": "Info", + "alertText": "Version {{requestedVersion}} was not found. This is version {{returnedVersion}}." + }, + "requestedVersionNotFoundShowDraft": { + "heading": "Info", + "alertText": "Version {{requestedVersion}} was not found. This is the DRAFT version." + }, + "shareUnpublishedDataset": { + "heading": "Unpublished Dataset Private URL", + "alertText": "Privately share this dataset before it is published: {{privateUrl}}" + }, + "unpublishedDataset": { + "heading": "Unpublished Dataset Private URL", + "alertText": "This unpublished dataset is being privately shared." + } } } diff --git a/src/dataset/domain/models/Dataset.ts b/src/dataset/domain/models/Dataset.ts index ed9a1c84c..a0d96e6c7 100644 --- a/src/dataset/domain/models/Dataset.ts +++ b/src/dataset/domain/models/Dataset.ts @@ -27,6 +27,8 @@ export class DatasetLabel { export enum DatasetAlertMessageKey { DRAFT_VERSION = 'draftVersion', REQUESTED_VERSION_NOT_FOUND = 'requestedVersionNotFound', + REQUESTED_VERSION_NOT_FOUND_SHOW_DRAFT = 'requestedVersionNotFoundShowDraft', + SHARE_UNPUBLISHED_DATASET = 'shareUnpublishedDataset', UNPUBLISHED_DATASET = 'unpublishedDataset' } @@ -34,8 +36,7 @@ export class DatasetAlert { constructor( public readonly variant: AlertVariant, public readonly message: DatasetAlertMessageKey, - public readonly dynamicFields?: string[], - public readonly customHeading?: string + public readonly dynamicFields?: object ) {} } @@ -274,6 +275,11 @@ export enum DatasetLockReason { FILE_VALIDATION_FAILED = 'fileValidationFailed' } +export interface PrivateUrl { + token: string + urlSnippet: string +} + export class Dataset { constructor( public readonly persistentId: string, @@ -288,7 +294,8 @@ export class Dataset { public readonly locks: DatasetLock[], public readonly hasValidTermsOfAccess: boolean, public readonly isValid: boolean, - public readonly isReleased: boolean + public readonly isReleased: boolean, + public readonly privateUrl?: PrivateUrl ) {} public getTitle(): string { @@ -333,7 +340,7 @@ export class Dataset { public readonly hasValidTermsOfAccess: boolean, public readonly isValid: boolean, public readonly isReleased: boolean, - public readonly privateUrl?: string + public readonly privateUrl?: PrivateUrl ) { this.withLabels() this.withAlerts() @@ -385,32 +392,51 @@ export class Dataset { } private withAlerts(): void { - if (this.version.publishingStatus === DatasetPublishingStatus.DRAFT) { - this.alerts.push( - new DatasetAlert('warning', DatasetAlertMessageKey.DRAFT_VERSION, undefined, 'Info') - ) + if ( + this.version.publishingStatus === DatasetPublishingStatus.DRAFT && + this.permissions.canPublishDataset + ) { + this.alerts.push(new DatasetAlert('warning', DatasetAlertMessageKey.DRAFT_VERSION)) } if (this.version.requestedVersion) { - const dynamicFields = [this.version.requestedVersion, `${this.version.toString()}`] - - this.alerts.push( - new DatasetAlert( - 'info', - DatasetAlertMessageKey.REQUESTED_VERSION_NOT_FOUND, - dynamicFields + if (this.version.latestVersionStatus == DatasetPublishingStatus.RELEASED) { + const dynamicFields = { + requestedVersion: this.version.requestedVersion, + returnedVersion: `${this.version.toString()}` + } + this.alerts.push( + new DatasetAlert( + 'warning', + DatasetAlertMessageKey.REQUESTED_VERSION_NOT_FOUND, + dynamicFields + ) ) - ) + } else { + const dynamicFields = { + requestedVersion: this.version.requestedVersion + } + this.alerts.push( + new DatasetAlert( + 'warning', + DatasetAlertMessageKey.REQUESTED_VERSION_NOT_FOUND_SHOW_DRAFT, + dynamicFields + ) + ) + } } if (this.privateUrl) { - const dynamicFields = [this.privateUrl] - this.alerts.push( - new DatasetAlert( - 'info', - DatasetAlertMessageKey.UNPUBLISHED_DATASET, - dynamicFields, - 'Unpublished Dataset Private URL' + if (this.permissions.canPublishDataset) { + const dynamicFields = { privateUrl: this.privateUrl.urlSnippet + this.privateUrl.token } + this.alerts.push( + new DatasetAlert( + 'info', + DatasetAlertMessageKey.SHARE_UNPUBLISHED_DATASET, + dynamicFields + ) ) - ) + } else { + this.alerts.push(new DatasetAlert('warning', DatasetAlertMessageKey.UNPUBLISHED_DATASET)) + } } } diff --git a/src/dataset/infrastructure/mappers/JSDatasetMapper.ts b/src/dataset/infrastructure/mappers/JSDatasetMapper.ts index 7b7bc47f8..065f95212 100644 --- a/src/dataset/infrastructure/mappers/JSDatasetMapper.ts +++ b/src/dataset/infrastructure/mappers/JSDatasetMapper.ts @@ -13,40 +13,17 @@ import { DatasetMetadataBlocks, DatasetMetadataFields, DatasetVersion, - MetadataBlockName + MetadataBlockName, + PrivateUrl } from '../../domain/models/Dataset' -/* - - static Builder = class { - public readonly labels: DatasetLabel[] = [] - public readonly alerts: DatasetAlert[] = [] - - constructor( - public readonly persistentId: string, - public readonly version: DatasetVersion, - public readonly citation: string, - public readonly summaryFields: DatasetMetadataBlock[], - public readonly license: DatasetLicense = defaultLicense, - public readonly metadataBlocks: DatasetMetadataBlocks, - public readonly permissions: DatasetPermissions, - public readonly locks: DatasetLock[], - public readonly hasValidTermsOfAccess: boolean, - public readonly isValid: boolean, - public readonly isReleased: boolean, - public readonly privateUrl?: string - ) { - this.withLabels() - this.withAlerts() - } - */ export class JSDatasetMapper { static toDataset( jsDataset: JSDataset, citation: string, summaryFieldsNames: string[], requestedVersion?: string, - privateUrl?: string + privateUrl?: PrivateUrl ): Dataset { return new Dataset.Builder( jsDataset.persistentId, @@ -71,7 +48,8 @@ export class JSDatasetMapper { [], // TODO Connect with dataset locks true, // TODO Connect with dataset hasValidTermsOfAccess true, // TODO Connect with dataset isValid - !!jsDataset.versionInfo.releaseTime, // TODO Connect with dataset isReleased, + jsDataset.versionInfo.releaseTime !== undefined && + !isNaN(jsDataset.versionInfo.releaseTime.getTime()), // TODO Connect with dataset isReleased, privateUrl ).build() } diff --git a/src/dataset/infrastructure/repositories/DatasetJSDataverseRepository.ts b/src/dataset/infrastructure/repositories/DatasetJSDataverseRepository.ts index a1409b317..317254b9b 100644 --- a/src/dataset/infrastructure/repositories/DatasetJSDataverseRepository.ts +++ b/src/dataset/infrastructure/repositories/DatasetJSDataverseRepository.ts @@ -44,7 +44,7 @@ export class DatasetJSDataverseRepository implements DatasetRepository { getPrivateUrlDatasetCitation.execute(privateUrlToken) ]) .then(([jsDataset, summaryFieldsNames, citation]: [JSDataset, string[], string]) => - JSDatasetMapper.toDataset(jsDataset, citation, summaryFieldsNames) + JSDatasetMapper.toDataset(jsDataset, citation, summaryFieldsNames, undefined) ) .catch((error: WriteError) => { throw new Error(error.message) diff --git a/src/sections/dataset/Dataset.tsx b/src/sections/dataset/Dataset.tsx index 4b0c7be82..ac02c8e04 100644 --- a/src/sections/dataset/Dataset.tsx +++ b/src/sections/dataset/Dataset.tsx @@ -13,6 +13,7 @@ import { FileRepository } from '../../files/domain/repositories/FileRepository' import { DatasetActionButtons } from './dataset-action-buttons/DatasetActionButtons' import { useDataset } from './DatasetContext' import { useEffect } from 'react' +import { DatasetAlerts } from './dataset-alerts/DatasetAlerts' interface DatasetProps { fileRepository: FileRepository @@ -37,6 +38,14 @@ export function Dataset({ fileRepository }: DatasetProps) { ) : (
+
+ + + + + +
+

{dataset.getTitle()}

diff --git a/src/sections/dataset/dataset-alerts/DatasetAlerts.module.scss b/src/sections/dataset/dataset-alerts/DatasetAlerts.module.scss new file mode 100644 index 000000000..3a63a82e6 --- /dev/null +++ b/src/sections/dataset/dataset-alerts/DatasetAlerts.module.scss @@ -0,0 +1,4 @@ +.container > * { + margin-top: 1em; + margin-right: 0.5em; +} \ No newline at end of file diff --git a/src/sections/dataset/dataset-alerts/DatasetAlerts.tsx b/src/sections/dataset/dataset-alerts/DatasetAlerts.tsx new file mode 100644 index 000000000..7d41990c0 --- /dev/null +++ b/src/sections/dataset/dataset-alerts/DatasetAlerts.tsx @@ -0,0 +1,34 @@ +import { Alert } from '@iqss/dataverse-design-system' +import { DatasetAlert } from '../../../dataset/domain/models/Dataset' +import { useTranslation } from 'react-i18next' +import styles from './DatasetAlerts.module.scss' +import parse from 'html-react-parser' + +interface DatasetAlertsProps { + alerts: DatasetAlert[] +} + +export function DatasetAlerts({ alerts }: DatasetAlertsProps) { + const { t } = useTranslation('dataset') + + return ( +
+ {alerts.map((alert: DatasetAlert, index) => { + const translatedMsg = alert.dynamicFields + ? t(`alerts.${alert.message}.alertText`, alert.dynamicFields) + : t(`alerts.${alert.message}.alertText`) + const translatedHeading = t(`alerts.${alert.message}.heading`) + const alertKey = `alert-${index}` + return ( + + {parse(translatedMsg)} + + ) + })} +
+ ) +} diff --git a/src/stories/dataset/Dataset.stories.tsx b/src/stories/dataset/Dataset.stories.tsx index a849d94cd..ab3c7e26e 100644 --- a/src/stories/dataset/Dataset.stories.tsx +++ b/src/stories/dataset/Dataset.stories.tsx @@ -3,17 +3,18 @@ import { WithI18next } from '../WithI18next' import { WithLayout } from '../WithLayout' import { Dataset } from '../../sections/dataset/Dataset' import { WithAnonymizedView } from './WithAnonymizedView' +import { WithDatasetPrivateUrl } from './WithDatasetPrivateUrl' import { FileMockRepository } from '../files/FileMockRepository' import { WithCitationMetadataBlockInfo } from './WithCitationMetadataBlockInfo' import { FileMockNoDataRepository } from '../files/FileMockNoDataRepository' import { WithSettings } from '../WithSettings' import { WithFilePermissionsDenied } from '../files/file-permission/WithFilePermissionsDenied' -import { WithLoggedInUser } from '../WithLoggedInUser' import { WithFilePermissionsGranted } from '../files/file-permission/WithFilePermissionsGranted' import { WithDataset } from './WithDataset' import { WithDatasetDraftAsOwner } from './WithDatasetDraftAsOwner' import { WithDatasetNotFound } from './WithDatasetNotFound' import { WithDatasetLoading } from './WithDatasetLoading' +import { WithLoggedInUser } from '../WithLoggedInUser' const meta: Meta = { title: 'Pages/Dataset', @@ -37,6 +38,10 @@ export const DraftWithAllDatasetPermissions: Story = { decorators: [WithLayout, WithDatasetDraftAsOwner, WithLoggedInUser, WithFilePermissionsGranted], render: () => } +export const LoggedInAsOwner: Story = { + decorators: [WithDataset, WithLayout, WithLoggedInUser, WithFilePermissionsGranted], + render: () => +} export const Loading: Story = { decorators: [WithLayout, WithDatasetLoading, WithFilePermissionsDenied], @@ -49,7 +54,7 @@ export const DatasetNotFound: Story = { } export const DatasetAnonymizedView: Story = { - decorators: [WithLayout, WithAnonymizedView, WithDataset, WithFilePermissionsGranted], + decorators: [WithLayout, WithAnonymizedView, WithDatasetPrivateUrl, WithFilePermissionsGranted], render: () => } diff --git a/src/stories/dataset/DatasetMockDataDraftVersion.ts b/src/stories/dataset/DatasetMockDataDraftVersion.ts new file mode 100644 index 000000000..a3f7dbbd3 --- /dev/null +++ b/src/stories/dataset/DatasetMockDataDraftVersion.ts @@ -0,0 +1,111 @@ +import { + ANONYMIZED_FIELD_VALUE, + DatasetPublishingStatus, + DatasetVersion, + DatasetLabelSemanticMeaning, + DatasetLabelValue, + DatasetMetadataBlocks +} from '../../dataset/domain/models/Dataset' +import { MetadataBlockName } from '../../dataset/domain/models/Dataset' +import { Dataset } from '../../dataset/domain/models/Dataset' + +export const DatasetMockDataDraftVersion = ( + props?: Partial, + anonymized = false +): Dataset => { + const dataset = { + persistentId: 'doi:10.5072/FK2/ABC123', + citation: `${ + anonymized ? 'Author name(s) withheld' : 'Bennet, Elizabeth; Darcy, Fitzwilliam' + }, 2023, "Dataset Title", https://doi.org/10.5072/FK2/BUDNRV, Root, V1`, + version: new DatasetVersion(1, DatasetPublishingStatus.DRAFT, 1, 0), + labels: [ + { value: 'Version 1.0', semanticMeaning: DatasetLabelSemanticMeaning.FILE }, + { value: DatasetLabelValue.DRAFT, semanticMeaning: DatasetLabelSemanticMeaning.DATASET } + ], + license: { + name: 'CC0 1.0', + uri: 'https://creativecommons.org/publicdomain/zero/1.0/', + iconUri: 'https://licensebuttons.net/p/zero/1.0/88x31.png' + }, + summaryFields: [ + { + name: MetadataBlockName.CITATION, + fields: { + dsDescription: [ + { + dsDescriptionValue: + 'This text is *italic* and this is **bold**. Here is an image ![Alt text](https://picsum.photos/id/10/20/20) ' + } + ], + keyword: 'Malaria, Tuberculosis, Drug Resistant', + subject: 'Medicine, Health and Life Sciences, Social Sciences', + publication: 'CNN Journal [CNN.com](https://cnn.com)', + notesText: 'Here is an image ![Alt text](https://picsum.photos/id/10/40/40)' + } + } + ], + metadataBlocks: [ + { + name: MetadataBlockName.CITATION, + fields: { + alternativePersistentId: 'doi:10.5072/FK2/ABC123', + publicationDate: anonymized ? ANONYMIZED_FIELD_VALUE : '2021-01-01', + citationDate: '2023-01-01', + title: 'Dataset Title', + subject: ['Subject1', 'Subject2'], + author: anonymized + ? ANONYMIZED_FIELD_VALUE + : [ + { + authorName: 'Admin, Dataverse', + authorAffiliation: 'Dataverse.org', + authorIdentifierScheme: 'ORCID', + authorIdentifier: '0000-0002-1825-1097' + }, + { + authorName: 'Owner, Dataverse', + authorAffiliation: 'Dataverse.org', + authorIdentifierScheme: 'ORCID', + authorIdentifier: '0000-0032-1825-0098' + } + ], + datasetContact: anonymized + ? ANONYMIZED_FIELD_VALUE + : [ + { + datasetContactName: 'Admin, Dataverse' + } + ], + dsDescription: [ + { + dsDescriptionValue: + 'This text is *italic* and this is **bold**. Here is an image ![Alt text](https://picsum.photos/id/10/20/20) ' + } + ] + } + }, + { + name: MetadataBlockName.GEOSPATIAL, + fields: { + geographicUnit: 'km', + geographicCoverage: anonymized + ? ANONYMIZED_FIELD_VALUE + : { + geographicCoverageCountry: 'United States', + geographicCoverageCity: 'Cambridge' + } + } + } + ] as DatasetMetadataBlocks, + ...props + } + return new Dataset.Builder( + dataset.persistentId, + dataset.version, + dataset.citation, + dataset.summaryFields, + dataset.license, + dataset.metadataBlocks + ).build() +} diff --git a/src/stories/dataset/DatasetMockDraftVersionRepository.ts b/src/stories/dataset/DatasetMockDraftVersionRepository.ts new file mode 100644 index 000000000..bff2952d6 --- /dev/null +++ b/src/stories/dataset/DatasetMockDraftVersionRepository.ts @@ -0,0 +1,22 @@ +import { DatasetRepository } from '../../dataset/domain/repositories/DatasetRepository' +import { Dataset as DatasetModel } from '../../dataset/domain/models/Dataset' +import { DatasetMockDataDraftVersion } from './DatasetMockDataDraftVersion' + +export class DatasetMockDraftVersionRepository implements DatasetRepository { + getByPersistentId(persistentId: string): Promise { + return new Promise((resolve) => { + setTimeout(() => { + resolve(DatasetMockDataDraftVersion({ persistentId: persistentId })) + }, 1000) + }) + } + + // eslint-disable-next-line unused-imports/no-unused-vars + getByPrivateUrlToken(privateUrlToken: string): Promise { + return new Promise((resolve) => { + setTimeout(() => { + resolve(DatasetMockDataDraftVersion({}, true)) + }, 1000) + }) + } +} diff --git a/src/stories/dataset/WithDatasetPrivateUrl.tsx b/src/stories/dataset/WithDatasetPrivateUrl.tsx new file mode 100644 index 000000000..1cc892f75 --- /dev/null +++ b/src/stories/dataset/WithDatasetPrivateUrl.tsx @@ -0,0 +1,33 @@ +import { StoryFn } from '@storybook/react' +import { DatasetProvider } from '../../sections/dataset/DatasetProvider' +import { DatasetRepository } from '../../dataset/domain/repositories/DatasetRepository' +import { Dataset } from '../../dataset/domain/models/Dataset' +import { DatasetMother } from '../../../tests/component/dataset/domain/models/DatasetMother' + +export const WithDatasetPrivateUrl = (Story: StoryFn) => { + const datasetRepository = {} as DatasetRepository + datasetRepository.getByPrivateUrlToken = ( + // eslint-disable-next-line unused-imports/no-unused-vars + privateUrlToken: string + ): Promise => { + return new Promise((resolve) => { + setTimeout(() => { + resolve( + DatasetMother.createRealistic({ + privateUrl: { + urlSnippet: 'http://localhost:8080/privateurl.xhtml?token=', + token: 'cd943c75-1cc7-4c1d-9717-98141d65d5cb' + } + }) + ) + }, 1000) + }) + } + return ( + + + + ) +} diff --git a/src/stories/dataset/dataset-alerts/DatasetAlert.stories.tsx b/src/stories/dataset/dataset-alerts/DatasetAlert.stories.tsx new file mode 100644 index 000000000..072994ad5 --- /dev/null +++ b/src/stories/dataset/dataset-alerts/DatasetAlert.stories.tsx @@ -0,0 +1,136 @@ +import type { Meta, StoryObj } from '@storybook/react' + +import { DatasetPublishingStatus, DatasetVersion } from '../../../dataset/domain/models/Dataset' +import { DatasetAlerts } from '../../../sections/dataset/dataset-alerts/DatasetAlerts' +import { WithI18next } from '../../WithI18next' + +import { + DatasetMother, + DatasetPermissionsMother +} from '../../../../tests/component/dataset/domain/models/DatasetMother' + +const meta: Meta = { + title: 'Sections/Dataset Page/DatasetAlerts', + component: DatasetAlerts, + decorators: [WithI18next] +} + +export default meta +type Story = StoryObj + +export const DraftVersion: Story = { + render: () => { + const dataset = DatasetMother.createRealistic({ + version: new DatasetVersion( + 1, + DatasetPublishingStatus.DRAFT, + true, + false, + DatasetPublishingStatus.DRAFT + ), + permissions: DatasetPermissionsMother.createWithPublishingDatasetAllowed() + }) + return ( +
+ +
+ ) + } +} + +export const VersionNotFound: Story = { + render: () => { + const dataset = DatasetMother.createRealistic({ + version: new DatasetVersion( + 1, + DatasetPublishingStatus.RELEASED, + true, + false, + DatasetPublishingStatus.RELEASED, + 1, + 0, + '3.0' + ) + }) + + return ( +
+ +
+ ) + } +} +export const VersionNotFoundShowDraft: Story = { + render: () => { + const dataset = DatasetMother.createRealistic({ + version: new DatasetVersion( + 1, + DatasetPublishingStatus.DRAFT, + true, + false, + DatasetPublishingStatus.DRAFT, + 1, + 0, + '3.0' + ) + }) + + return ( +
+ +
+ ) + } +} +export const SharePrivateUrl: Story = { + render: () => { + const dataset = DatasetMother.createRealistic({ + version: new DatasetVersion( + 1, + DatasetPublishingStatus.RELEASED, + true, + false, + DatasetPublishingStatus.DRAFT, + 1, + 0 + ), + permissions: DatasetPermissionsMother.createWithAllAllowed(), + privateUrl: { + urlSnippet: 'http://localhost:8080/privateurl.xhtml?token=', + token: 'cd943c75-1cc7-4c1d-9717-98141d65d5cb' + } + }) + + return ( +
+ +
+ ) + } +} +export const UsePrivateUrl: Story = { + render: () => { + const dataset = DatasetMother.createRealistic({ + version: new DatasetVersion( + 1, + DatasetPublishingStatus.RELEASED, + true, + false, + DatasetPublishingStatus.DRAFT, + 1, + 0 + ), + permissions: DatasetPermissionsMother.createWithNoneAllowed(), + privateUrl: { + urlSnippet: 'http://localhost:8080/privateurl.xhtml?token=', + token: 'cd943c75-1cc7-4c1d-9717-98141d65d5cb' + } + }) + + return ( +
+ +
+ ) + } +} diff --git a/tests/component/dataset/domain/models/DatasetMother.ts b/tests/component/dataset/domain/models/DatasetMother.ts index 428711053..c96e0a5f8 100644 --- a/tests/component/dataset/domain/models/DatasetMother.ts +++ b/tests/component/dataset/domain/models/DatasetMother.ts @@ -301,7 +301,8 @@ export class DatasetMother { dataset.locks, dataset.hasValidTermsOfAccess, dataset.isValid, - dataset.isReleased + dataset.isReleased, + dataset.privateUrl ).build() } diff --git a/tests/component/dataset/infrastructure/mappers/JSDatasetMapper.spec.ts b/tests/component/dataset/infrastructure/mappers/JSDatasetMapper.spec.ts index 070205b36..cf04a2edc 100644 --- a/tests/component/dataset/infrastructure/mappers/JSDatasetMapper.spec.ts +++ b/tests/component/dataset/infrastructure/mappers/JSDatasetMapper.spec.ts @@ -68,9 +68,7 @@ const expectedDataset = { { semanticMeaning: 'dataset', value: 'Draft' }, { semanticMeaning: 'warning', value: 'Unpublished' } ], - alerts: [ - { variant: 'warning', message: 'draftVersion', dynamicFields: undefined, customHeading: 'Info' } - ], + alerts: [{ variant: 'warning', message: 'draftVersion', dynamicFields: undefined }], summaryFields: [ { name: 'citation', @@ -120,7 +118,8 @@ const expectedDataset = { locks: [], hasValidTermsOfAccess: true, isValid: true, - isReleased: false + isReleased: false, + privateUrl: undefined } const expectedDatasetAlternateVersion = { persistentId: 'doi:10.5072/FK2/B4B2MJ', @@ -139,6 +138,7 @@ const expectedDatasetAlternateVersion = { hasValidTermsOfAccess: true, isReleased: false, isValid: true, + privateUrl: undefined, labels: [ { semanticMeaning: 'dataset', value: 'Draft' }, { semanticMeaning: 'warning', value: 'Unpublished' } @@ -147,14 +147,12 @@ const expectedDatasetAlternateVersion = { { variant: 'warning', message: 'draftVersion', - dynamicFields: undefined, - customHeading: 'Info' + dynamicFields: undefined }, { - message: 'requestedVersionNotFound', - variant: 'info', - dynamicFields: ['4.0', '0.0'], - customHeading: undefined + message: 'requestedVersionNotFoundShowDraft', + variant: 'warning', + dynamicFields: { requestedVersion: '4.0' } } ], summaryFields: [ @@ -217,8 +215,6 @@ describe('JS Dataset Mapper', () => { datasetSummaryFields, '4.0' ) - console.log('mapped: ' + JSON.stringify(mappedWithAlternate)) - console.log('expected: ' + JSON.stringify(expectedDatasetAlternateVersion)) expect(expectedDatasetAlternateVersion).to.deep.equal(mappedWithAlternate) }) diff --git a/tests/component/sections/dataset/dataset-alerts/DatasetAlerts.spec.tsx b/tests/component/sections/dataset/dataset-alerts/DatasetAlerts.spec.tsx new file mode 100644 index 000000000..d70fd4977 --- /dev/null +++ b/tests/component/sections/dataset/dataset-alerts/DatasetAlerts.spec.tsx @@ -0,0 +1,153 @@ +import { DatasetAlerts } from '../../../../../src/sections/dataset/dataset-alerts/DatasetAlerts' +import { faker } from '@faker-js/faker' + +import { + DatasetAlert, + DatasetAlertMessageKey +} from '../../../../../src/dataset/domain/models/Dataset' +import { + DatasetMother, + DatasetPermissionsMother, + DatasetVersionMother +} from '../../../dataset/domain/models/DatasetMother' + +function removeMarkup(htmlString: string): string { + // Use a regular expression to match HTML tags and replace them with an empty string + return htmlString.replace(/<\/?[^>]+(>|$)/g, '') +} + +interface AlertTranslation { + heading: string + alertText: string +} + +interface DatasetTranslation { + alerts: { + [DatasetAlertMessageKey.DRAFT_VERSION]: AlertTranslation + [DatasetAlertMessageKey.REQUESTED_VERSION_NOT_FOUND]: AlertTranslation + [DatasetAlertMessageKey.REQUESTED_VERSION_NOT_FOUND_SHOW_DRAFT]: AlertTranslation + [DatasetAlertMessageKey.UNPUBLISHED_DATASET]: AlertTranslation + [DatasetAlertMessageKey.SHARE_UNPUBLISHED_DATASET]: AlertTranslation + } +} + +it('renders the correct number of alerts', () => { + const alerts = [ + new DatasetAlert('warning', DatasetAlertMessageKey.DRAFT_VERSION), + new DatasetAlert('warning', DatasetAlertMessageKey.REQUESTED_VERSION_NOT_FOUND, { + requestedVersion: 4.0, + returnedVersion: 2.0 + }), + new DatasetAlert('info', DatasetAlertMessageKey.SHARE_UNPUBLISHED_DATASET, { + privateUrl: faker.internet.url() + }) + ] + cy.fixture('../../../public/locales/en/dataset.json').then((dataset: DatasetTranslation) => { + cy.mount() + const headingProps = [ + dataset.alerts.draftVersion.heading, + dataset.alerts.requestedVersionNotFound.heading, + dataset.alerts.unpublishedDataset.heading + ] + cy.findAllByRole('alert').should('have.length', 3) + cy.findAllByRole('alert').each(($alert, index) => { + cy.wrap($alert).findByText(headingProps[index]).should('exist') + }) + }) +}) + +it('renders alerts with correct text', () => { + const draftAlert = new DatasetAlert('info', DatasetAlertMessageKey.DRAFT_VERSION) + const alerts = [draftAlert] + + cy.fixture('../../../public/locales/en/dataset.json').then((dataset: DatasetTranslation) => { + cy.mount() + + const alertHeading = dataset.alerts[draftAlert.message].heading + const alertText = removeMarkup(dataset.alerts[draftAlert.message].alertText) + cy.findByText(alertHeading).should('exist') + cy.findByRole('alert').should(($element) => { + // text() removes markup, so we can compare to the expected text + const text = $element.text() + expect(text).to.include(alertText) + }) + }) +}) +it('renders dynamic text', () => { + const dynamicFields = { + requestedVersion: '4.0', + returnedVersion: '2.0' + } + const notFoundAlert = new DatasetAlert( + 'warning', + DatasetAlertMessageKey.REQUESTED_VERSION_NOT_FOUND, + dynamicFields + ) + cy.mount() + cy.findByRole('alert').should('contain.text', dynamicFields.requestedVersion) + cy.findByRole('alert').should('contain.text', dynamicFields.returnedVersion) +}) +it('shows draft alert if version is DRAFT', () => { + const dataset = DatasetMother.create({ + version: DatasetVersionMother.createDraftAsLatestVersion(), + permissions: DatasetPermissionsMother.createWithPublishingDatasetAllowed() + }) + + cy.customMount() + + cy.findByRole('alert').should('contain.text', 'draft') +}) +it('does not show draft alert if version is RELEASED', () => { + const dataset = DatasetMother.create({ + version: DatasetVersionMother.createReleased(), + permissions: DatasetPermissionsMother.createWithPublishingDatasetAllowed() + }) + + cy.customMount() + cy.findByRole('alert').should('not.exist') +}) + +it('shows draft & share private url message if privateUrl exists and user can edit', () => { + cy.fixture('../../../public/locales/en/dataset.json').then((datasetText: DatasetTranslation) => { + const dataset = DatasetMother.createRealistic({ + version: DatasetVersionMother.createDraftAsLatestVersion(), + permissions: DatasetPermissionsMother.createWithAllAllowed(), + privateUrl: { + urlSnippet: 'http://localhost:8080/privateurl.xhtml?token=', + token: 'cd943c75-1cc7-4c1d-9717-98141d65d5cb' + } + }) + cy.customMount() + const expectedMessageKeys = [ + DatasetAlertMessageKey.DRAFT_VERSION, + DatasetAlertMessageKey.SHARE_UNPUBLISHED_DATASET + ] + cy.findAllByRole('alert').should('have.length', 2) + cy.findAllByRole('alert').each(($alert, index) => { + const messageKey = expectedMessageKeys[index] + const itemText = datasetText.alerts[messageKey] + cy.wrap($alert).findByText(itemText.heading).should('exist') + }) + }) +}) +it('shows private url message only if privateUrl exists and user cannot edit', () => { + cy.fixture('../../../public/locales/en/dataset.json').then((datasetText: DatasetTranslation) => { + const dataset = DatasetMother.createRealistic({ + version: DatasetVersionMother.createDraftAsLatestVersion(), + permissions: DatasetPermissionsMother.createWithNoneAllowed(), + privateUrl: { + urlSnippet: 'http://localhost:8080/privateurl.xhtml?token=', + token: 'cd943c75-1cc7-4c1d-9717-98141d65d5cb' + } + }) + cy.customMount() + const expectedMessageKey = DatasetAlertMessageKey.UNPUBLISHED_DATASET + + cy.findAllByRole('alert').should('have.length', 1) + cy.findByRole('alert').then(($alert) => { + const itemText = datasetText.alerts[expectedMessageKey] + cy.wrap($alert).findByText(itemText.heading).should('exist') + expect($alert.text()).to.include(itemText.alertText) + }) + }) +})