diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f6a07776f..d962cc4f4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -133,6 +133,9 @@ jobs: working-directory: packages/design-system run: npm run build + - name: Install Playwright + run: npx playwright install + - name: Build Storybook Design System working-directory: packages/design-system run: npm run build-storybook --quiet diff --git a/packages/design-system/src/lib/assets/styles/bootstrap-customized.scss b/packages/design-system/src/lib/assets/styles/bootstrap-customized.scss index 9d7410f79..c12c60ff3 100644 --- a/packages/design-system/src/lib/assets/styles/bootstrap-customized.scss +++ b/packages/design-system/src/lib/assets/styles/bootstrap-customized.scss @@ -101,6 +101,18 @@ $navbar-brand-font-size: $dv-brand-font-size; justify-content: end; } +.dropdown-menu > .dropdown > .dropdown-toggle { + width: 100%; + text-align: start; + background-color: transparent; + border-color: transparent; +} + +.dropdown-menu > .dropdown > .dropdown-toggle:hover { + background-color: $dropdown-link-hover-bg; + border-color: transparent; +} + th { vertical-align: middle; } diff --git a/packages/design-system/src/lib/components/button-group/ButtonGroup.module.scss b/packages/design-system/src/lib/components/button-group/ButtonGroup.module.scss index a382291d2..78fd402fc 100644 --- a/packages/design-system/src/lib/components/button-group/ButtonGroup.module.scss +++ b/packages/design-system/src/lib/components/button-group/ButtonGroup.module.scss @@ -1,5 +1,5 @@ @import "src/lib/assets/styles/design-tokens/colors.module"; -.border > button { +.border > button, .border > [role="group"] > button { border: 1px solid $dv-button-border-color; } \ No newline at end of file diff --git a/packages/design-system/src/lib/components/button-group/ButtonGroup.tsx b/packages/design-system/src/lib/components/button-group/ButtonGroup.tsx index be6d500d1..b90facd92 100644 --- a/packages/design-system/src/lib/components/button-group/ButtonGroup.tsx +++ b/packages/design-system/src/lib/components/button-group/ButtonGroup.tsx @@ -7,9 +7,17 @@ interface ButtonGroupProps extends React.HTMLAttributes { vertical?: boolean } -export function ButtonGroup({ vertical, children, ...props }: PropsWithChildren) { +export function ButtonGroup({ + vertical, + children, + className, + ...props +}: PropsWithChildren) { return ( - + {children} ) diff --git a/public/locales/en/dataset.json b/public/locales/en/dataset.json index ba62759a4..88a0983ec 100644 --- a/public/locales/en/dataset.json +++ b/public/locales/en/dataset.json @@ -18,8 +18,43 @@ "learnAbout": "Learn About", "standards": "Data Citation Standards" }, - - "actions": { + "datasetActionButtons": { + "title": "Dataset Action Buttons", + "submitForReview": { + "enabled": "Submit for Review", + "disabled": "Submitted for Review" + }, + "publish": { + "title": "Publish Dataset", + "publish": "Publish", + "returnToAuthor": "Return to Author", + "changeCurationStatus": "Change Curation Status", + "removeCurrentStatus": "Remove Current Status" + }, + "linkDataset": { + "title": "Link Dataset" + }, + "editDataset": { + "title": "Edit Dataset", + "filesUpload": "Files (Upload)", + "metadata": "Metadata", + "terms": "Terms", + "privateUrl": "Private URL", + "thumbnailsPlusWidgets": "Thumbnails + Widgets", + "delete": { + "draft": "Delete Draft Version", + "released": "Delete Dataset" + }, + "deaccession": "Deaccession Dataset", + "permissions": { + "title": "Permissions", + "dataset": "Dataset", + "file": "File" + } + }, + "accessDataset": { + "title": "Access Dataset" + }, "uploadFiles": "Upload Files" } } diff --git a/src/dataset/domain/models/Dataset.ts b/src/dataset/domain/models/Dataset.ts index f42bc6819..6819e62b7 100644 --- a/src/dataset/domain/models/Dataset.ts +++ b/src/dataset/domain/models/Dataset.ts @@ -201,8 +201,7 @@ export enum DatasetPublishingStatus { RELEASED = 'released', DRAFT = 'draft', DEACCESSIONED = 'deaccessioned', - EMBARGOED = 'embargoed', - IN_REVIEW = 'inReview' + EMBARGOED = 'embargoed' } export enum DatasetNonNumericVersion { @@ -214,6 +213,9 @@ export class DatasetVersion { constructor( public readonly id: number, public readonly publishingStatus: DatasetPublishingStatus, + public readonly isLatest: boolean, + public readonly isInReview: boolean, + public readonly latestVersionStatus: DatasetPublishingStatus, public readonly majorNumber?: number, public readonly minorNumber?: number ) {} @@ -226,6 +228,32 @@ export class DatasetVersion { } } +export interface DatasetPermissions { + canDownloadFiles: boolean + canUpdateDataset: boolean + canPublishDataset: boolean + canManageDatasetPermissions: boolean + canManageFilesPermissions: boolean + canDeleteDataset: boolean +} + +export interface DatasetLock { + id: number + reason: DatasetLockReason +} + +export enum DatasetLockReason { + INGEST = 'ingest', + WORKFLOW = 'workflow', + IN_REVIEW = 'inReview', + DCM_UPLOAD = 'dcmUpload', + GLOBUS_UPLOAD = 'globusUpload', + FINALIZE_PUBLICATION = 'finalizePublication', + + EDIT_IN_PROGRESS = 'editInProgress', + FILE_VALIDATION_FAILED = 'fileValidationFailed' +} + export class Dataset { constructor( public readonly persistentId: string, @@ -234,13 +262,40 @@ export class Dataset { public readonly labels: DatasetLabel[], public readonly summaryFields: DatasetMetadataBlock[], public readonly license: DatasetLicense, - public readonly metadataBlocks: DatasetMetadataBlocks + 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 getTitle(): string { return this.metadataBlocks[0].fields.title } + public get isLockedFromPublishing(): boolean { + return this.isLockedFromEdits + } + + public get isLocked(): boolean { + return this.locks.length > 0 + } + + public get isLockedInWorkflow(): boolean { + return this.locks.some((lock) => lock.reason === DatasetLockReason.WORKFLOW) + } + + public get isLockedFromEdits(): boolean { + const lockedReasonIsInReview = this.locks.some( + (lock) => lock.reason === DatasetLockReason.IN_REVIEW + ) + // If the lock reason is workflow and the workflow userId is the same as the current user, then the user can edit + // TODO - Ask how we want to manage pending workflows + + return this.isLocked && !(lockedReasonIsInReview && this.permissions.canPublishDataset) + } + static Builder = class { public readonly labels: DatasetLabel[] = [] @@ -250,7 +305,12 @@ export class Dataset { public readonly citation: string, public readonly summaryFields: DatasetMetadataBlock[], public readonly license: DatasetLicense = defaultLicense, - public readonly metadataBlocks: DatasetMetadataBlocks + public readonly metadataBlocks: DatasetMetadataBlocks, + public readonly permissions: DatasetPermissions, + public readonly locks: DatasetLock[], + public readonly hasValidTermsOfAccess: boolean, + public readonly isValid: boolean, + public readonly isReleased: boolean ) { this.withLabels() } @@ -267,7 +327,7 @@ export class Dataset { ) } - if (this.version.publishingStatus !== DatasetPublishingStatus.RELEASED) { + if (!this.isReleased) { this.labels.push( new DatasetLabel(DatasetLabelSemanticMeaning.WARNING, DatasetLabelValue.UNPUBLISHED) ) @@ -285,7 +345,7 @@ export class Dataset { ) } - if (this.version.publishingStatus === DatasetPublishingStatus.IN_REVIEW) { + if (this.version.isInReview) { this.labels.push( new DatasetLabel(DatasetLabelSemanticMeaning.SUCCESS, DatasetLabelValue.IN_REVIEW) ) @@ -308,7 +368,12 @@ export class Dataset { this.labels, this.summaryFields, this.license, - this.metadataBlocks + this.metadataBlocks, + this.permissions, + this.locks, + this.hasValidTermsOfAccess, + this.isValid, + this.isReleased ) } } diff --git a/src/dataset/infrastructure/mappers/JSDatasetMapper.ts b/src/dataset/infrastructure/mappers/JSDatasetMapper.ts index 0207de851..ce3ade4b9 100644 --- a/src/dataset/infrastructure/mappers/JSDatasetMapper.ts +++ b/src/dataset/infrastructure/mappers/JSDatasetMapper.ts @@ -1,7 +1,7 @@ import { Dataset as JSDataset, - DatasetMetadataBlocks as JSDatasetMetadataBlocks, DatasetMetadataBlock as JSDatasetMetadataBlock, + DatasetMetadataBlocks as JSDatasetMetadataBlocks, DatasetMetadataFields as JSDatasetMetadataFields, DatasetVersionInfo as JSDatasetVersionInfo } from '@iqss/dataverse-client-javascript' @@ -9,11 +9,11 @@ import { DatasetVersionState as JSDatasetVersionState } from '@iqss/dataverse-cl import { Dataset, DatasetPublishingStatus, - MetadataBlockName, DatasetMetadataBlock, - DatasetVersion, + DatasetMetadataBlocks, DatasetMetadataFields, - DatasetMetadataBlocks + DatasetVersion, + MetadataBlockName } from '../../domain/models/Dataset' export class JSDatasetMapper { @@ -29,7 +29,19 @@ export class JSDatasetMapper { jsDataset.alternativePersistentId, jsDataset.publicationDate, jsDataset.citationDate - ) + ), + { + canDownloadFiles: true, + canUpdateDataset: true, + canPublishDataset: true, + canManageDatasetPermissions: true, + canManageFilesPermissions: true, + canDeleteDataset: true + }, // TODO Connect with dataset permissions + [], // 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 ).build() } @@ -40,6 +52,9 @@ export class JSDatasetMapper { return new DatasetVersion( jDatasetVersionId, JSDatasetMapper.toStatus(jsDatasetVersionInfo.state), + true, // TODO Connect with dataset version isLatest + false, // TODO Connect with dataset version isInReview + JSDatasetMapper.toStatus(jsDatasetVersionInfo.state), // TODO Connect with dataset version latestVersionState jsDatasetVersionInfo.majorNumber, jsDatasetVersionInfo.minorNumber ) diff --git a/src/sections/dataset/Dataset.tsx b/src/sections/dataset/Dataset.tsx index b03d76a55..4b0c7be82 100644 --- a/src/sections/dataset/Dataset.tsx +++ b/src/sections/dataset/Dataset.tsx @@ -1,5 +1,3 @@ -import { DatasetRepository } from '../../dataset/domain/repositories/DatasetRepository' -import { useDataset } from './useDataset' import { Tabs, Col, Row } from '@iqss/dataverse-design-system' import styles from './Dataset.module.scss' import { DatasetLabels } from './dataset-labels/DatasetLabels' @@ -12,22 +10,23 @@ import { DatasetSummary } from './dataset-summary/DatasetSummary' import { DatasetCitation } from './dataset-citation/DatasetCitation' import { DatasetFiles } from './dataset-files/DatasetFiles' import { FileRepository } from '../../files/domain/repositories/FileRepository' +import { DatasetActionButtons } from './dataset-action-buttons/DatasetActionButtons' +import { useDataset } from './DatasetContext' +import { useEffect } from 'react' interface DatasetProps { - datasetRepository: DatasetRepository fileRepository: FileRepository - searchParams: { - persistentId?: string - privateUrlToken?: string - version?: string - } } -export function Dataset({ datasetRepository, fileRepository, searchParams }: DatasetProps) { - const { dataset } = useDataset(datasetRepository, searchParams) - const { isLoading } = useLoading() +export function Dataset({ fileRepository }: DatasetProps) { + const { setIsLoading } = useLoading() + const { dataset, isLoading } = useDataset() const { t } = useTranslation('dataset') + useEffect(() => { + setIsLoading(isLoading) + }, [isLoading]) + if (isLoading) { return } @@ -47,6 +46,9 @@ export function Dataset({ datasetRepository, fileRepository, searchParams }: Dat + + + diff --git a/src/sections/dataset/DatasetContext.ts b/src/sections/dataset/DatasetContext.ts new file mode 100644 index 000000000..b6b31f3e4 --- /dev/null +++ b/src/sections/dataset/DatasetContext.ts @@ -0,0 +1,13 @@ +import { createContext, useContext } from 'react' +import { Dataset } from '../../dataset/domain/models/Dataset' + +interface DatasetContextProps { + dataset: Dataset | undefined + isLoading: boolean +} +export const DatasetContext = createContext({ + dataset: undefined, + isLoading: false +}) + +export const useDataset = () => useContext(DatasetContext) diff --git a/src/sections/dataset/DatasetFactory.tsx b/src/sections/dataset/DatasetFactory.tsx index ae3941f66..1ac3e1e15 100644 --- a/src/sections/dataset/DatasetFactory.tsx +++ b/src/sections/dataset/DatasetFactory.tsx @@ -10,6 +10,7 @@ import { MetadataBlockInfoJSDataverseRepository } from '../../metadata-block-inf import { SettingJSDataverseRepository } from '../../settings/infrastructure/SettingJSDataverseRepository' import { FilePermissionsProvider } from '../file/file-permissions/FilePermissionsProvider' import { SettingsProvider } from '../settings/SettingsProvider' +import { DatasetProvider } from './DatasetProvider' const datasetRepository = new DatasetJSDataverseRepository() const fileRepository = new FileJSDataverseRepository() @@ -45,19 +46,19 @@ function DatasetWithSearchParams() { if (privateUrlToken) { return ( - + + + ) } return ( - + + + ) } diff --git a/src/sections/dataset/useDataset.tsx b/src/sections/dataset/DatasetProvider.tsx similarity index 71% rename from src/sections/dataset/useDataset.tsx rename to src/sections/dataset/DatasetProvider.tsx index c03ad11f5..41ebd2504 100644 --- a/src/sections/dataset/useDataset.tsx +++ b/src/sections/dataset/DatasetProvider.tsx @@ -1,20 +1,25 @@ -import { useEffect, useState } from 'react' +import { PropsWithChildren, useEffect, useState } from 'react' +import { DatasetContext } from './DatasetContext' import { DatasetRepository } from '../../dataset/domain/repositories/DatasetRepository' import { Dataset } from '../../dataset/domain/models/Dataset' import { getDatasetByPersistentId } from '../../dataset/domain/useCases/getDatasetByPersistentId' -import { useLoading } from '../loading/LoadingContext' import { getDatasetByPrivateUrlToken } from '../../dataset/domain/useCases/getDatasetByPrivateUrlToken' -export function useDataset( - repository: DatasetRepository, +interface DatasetProviderProps { + repository: DatasetRepository searchParams: { persistentId?: string privateUrlToken?: string version?: string } -) { +} +export function DatasetProvider({ + repository, + searchParams, + children +}: PropsWithChildren) { const [dataset, setDataset] = useState() - const { setIsLoading } = useLoading() + const [isLoading, setIsLoading] = useState(true) const getDataset = () => { if (searchParams.persistentId) { return getDatasetByPersistentId(repository, searchParams.persistentId, searchParams.version) @@ -39,5 +44,7 @@ export function useDataset( }) }, [repository, searchParams]) - return { dataset } + return ( + {children} + ) } diff --git a/src/sections/dataset/dataset-action-buttons/DatasetActionButtons.module.scss b/src/sections/dataset/dataset-action-buttons/DatasetActionButtons.module.scss new file mode 100644 index 000000000..f2729d4d0 --- /dev/null +++ b/src/sections/dataset/dataset-action-buttons/DatasetActionButtons.module.scss @@ -0,0 +1,5 @@ +.group { + display: flex; + width: 100%; + margin: 0.5rem 0; +} \ No newline at end of file diff --git a/src/sections/dataset/dataset-action-buttons/DatasetActionButtons.tsx b/src/sections/dataset/dataset-action-buttons/DatasetActionButtons.tsx new file mode 100644 index 000000000..ce57675e0 --- /dev/null +++ b/src/sections/dataset/dataset-action-buttons/DatasetActionButtons.tsx @@ -0,0 +1,26 @@ +import { Dataset } from '../../../dataset/domain/models/Dataset' +import { ButtonGroup } from '@iqss/dataverse-design-system' +import { AccessDatasetMenu } from './access-dataset-menu/AccessDatasetMenu' +import { PublishDatasetMenu } from './publish-dataset-menu/PublishDatasetMenu' +import styles from './DatasetActionButtons.module.scss' +import { SubmitForReviewButton } from './submit-for-review-button/SubmitForReviewButton' +import { EditDatasetMenu } from './edit-dataset-menu/EditDatasetMenu' +import { LinkDatasetButton } from './link-dataset-button/LinkDatasetButton' +import { useTranslation } from 'react-i18next' + +interface DatasetActionButtonsProps { + dataset: Dataset +} + +export function DatasetActionButtons({ dataset }: DatasetActionButtonsProps) { + const { t } = useTranslation('dataset') + return ( + + + + + + + + ) +} diff --git a/src/sections/dataset/dataset-action-buttons/access-dataset-menu/AccessDatasetMenu.tsx b/src/sections/dataset/dataset-action-buttons/access-dataset-menu/AccessDatasetMenu.tsx new file mode 100644 index 000000000..542ad49c0 --- /dev/null +++ b/src/sections/dataset/dataset-action-buttons/access-dataset-menu/AccessDatasetMenu.tsx @@ -0,0 +1,36 @@ +import { + DatasetPermissions, + DatasetPublishingStatus, + DatasetVersion +} from '../../../../dataset/domain/models/Dataset' +import { DropdownButton, DropdownButtonItem } from '@iqss/dataverse-design-system' +import { useTranslation } from 'react-i18next' + +interface AccessDatasetMenuProps { + version: DatasetVersion + permissions: DatasetPermissions +} + +export function AccessDatasetMenu({ version, permissions }: AccessDatasetMenuProps) { + if ( + !permissions.canDownloadFiles || + (version.publishingStatus === DatasetPublishingStatus.DEACCESSIONED && + !permissions.canUpdateDataset) + ) { + return <> + } + + const { t } = useTranslation('dataset') + return ( + + Download + + ) +} +// TODO: add download feature https://github.com/IQSS/dataverse-frontend/issues/63 +// TODO: add explore feature +// TODO: add compute feature diff --git a/src/sections/dataset/dataset-action-buttons/edit-dataset-menu/DeaccessionDatasetButton.tsx b/src/sections/dataset/dataset-action-buttons/edit-dataset-menu/DeaccessionDatasetButton.tsx new file mode 100644 index 000000000..98c25d869 --- /dev/null +++ b/src/sections/dataset/dataset-action-buttons/edit-dataset-menu/DeaccessionDatasetButton.tsx @@ -0,0 +1,20 @@ +import { Dataset } from '../../../../dataset/domain/models/Dataset' +import { DropdownButtonItem, DropdownSeparator } from '@iqss/dataverse-design-system' +import { useTranslation } from 'react-i18next' + +interface DeaccessionDatasetButtonProps { + dataset: Dataset +} +export function DeaccessionDatasetButton({ dataset }: DeaccessionDatasetButtonProps) { + if (!dataset.isReleased || !dataset.permissions.canPublishDataset) { + return <> + } + + const { t } = useTranslation('dataset') + return ( + <> + + {t('datasetActionButtons.editDataset.deaccession')} + + ) +} diff --git a/src/sections/dataset/dataset-action-buttons/edit-dataset-menu/DeleteDatasetButton.tsx b/src/sections/dataset/dataset-action-buttons/edit-dataset-menu/DeleteDatasetButton.tsx new file mode 100644 index 000000000..c7f4c25fe --- /dev/null +++ b/src/sections/dataset/dataset-action-buttons/edit-dataset-menu/DeleteDatasetButton.tsx @@ -0,0 +1,27 @@ +import { Dataset, DatasetPublishingStatus } from '../../../../dataset/domain/models/Dataset' +import { DropdownButtonItem, DropdownSeparator } from '@iqss/dataverse-design-system' +import { useTranslation } from 'react-i18next' + +interface DeleteDatasetButtonProps { + dataset: Dataset +} +export function DeleteDatasetButton({ dataset }: DeleteDatasetButtonProps) { + if ( + !dataset.permissions.canDeleteDataset || + dataset.version.latestVersionStatus !== DatasetPublishingStatus.DRAFT + ) { + return <> + } + + const { t } = useTranslation('dataset') + return ( + <> + + + {dataset.isReleased + ? t('datasetActionButtons.editDataset.delete.draft') + : t('datasetActionButtons.editDataset.delete.released')} + + + ) +} diff --git a/src/sections/dataset/dataset-action-buttons/edit-dataset-menu/EditDatasetMenu.tsx b/src/sections/dataset/dataset-action-buttons/edit-dataset-menu/EditDatasetMenu.tsx new file mode 100644 index 000000000..326518a5e --- /dev/null +++ b/src/sections/dataset/dataset-action-buttons/edit-dataset-menu/EditDatasetMenu.tsx @@ -0,0 +1,44 @@ +import { Dataset } from '../../../../dataset/domain/models/Dataset' +import { DropdownButton, DropdownButtonItem } from '@iqss/dataverse-design-system' +import { EditDatasetPermissionsMenu } from './EditDatasetPermissionsMenu' +import { DeleteDatasetButton } from './DeleteDatasetButton' +import { DeaccessionDatasetButton } from './DeaccessionDatasetButton' +import { useTranslation } from 'react-i18next' + +interface EditDatasetMenuProps { + dataset: Dataset +} + +export function EditDatasetMenu({ dataset }: EditDatasetMenuProps) { + if (!dataset.permissions.canUpdateDataset) { + return <> + } + + const { t } = useTranslation('dataset') + return ( + + + {t('datasetActionButtons.editDataset.filesUpload')} + + + {t('datasetActionButtons.editDataset.metadata')} + + {t('datasetActionButtons.editDataset.terms')} + + {(dataset.permissions.canManageDatasetPermissions || + dataset.permissions.canManageFilesPermissions) && ( + {t('datasetActionButtons.editDataset.privateUrl')} + )} + + {t('datasetActionButtons.editDataset.thumbnailsPlusWidgets')} + + + + + ) +} diff --git a/src/sections/dataset/dataset-action-buttons/edit-dataset-menu/EditDatasetPermissionsMenu.tsx b/src/sections/dataset/dataset-action-buttons/edit-dataset-menu/EditDatasetPermissionsMenu.tsx new file mode 100644 index 000000000..7ef7f3282 --- /dev/null +++ b/src/sections/dataset/dataset-action-buttons/edit-dataset-menu/EditDatasetPermissionsMenu.tsx @@ -0,0 +1,59 @@ +import { Dataset } from '../../../../dataset/domain/models/Dataset' +import { DropdownButton, DropdownButtonItem } from '@iqss/dataverse-design-system' +import { useSettings } from '../../../settings/SettingsContext' +import { useEffect, useState } from 'react' +import { SettingName } from '../../../../settings/domain/models/Setting' +import { HasPublicStore } from '../../../../settings/domain/models/HasPublicStore' +import { useTranslation } from 'react-i18next' + +interface EditDatasetPermissionsMenuProps { + dataset: Dataset +} +export function EditDatasetPermissionsMenu({ dataset }: EditDatasetPermissionsMenuProps) { + if ( + !dataset.permissions.canManageDatasetPermissions && + !dataset.permissions.canManageFilesPermissions + ) { + return <> + } + + const { t } = useTranslation('dataset') + const { getSettingByName } = useSettings() + const [hasPublicStore, setHasPublicStore] = useState(false) + + useEffect(() => { + getSettingByName(SettingName.HAS_PUBLIC_STORE) + .then((hasPublicStoreSetting) => { + setHasPublicStore(hasPublicStoreSetting.value) + }) + .catch((error) => { + console.error(error) + }) + }, [getSettingByName]) + + if (hasPublicStore) { + return ( + + {t('datasetActionButtons.editDataset.permissions.title')} + + ) + } + + return ( + + {dataset.permissions.canManageDatasetPermissions && ( + + {t('datasetActionButtons.editDataset.permissions.dataset')} + + )} + {dataset.permissions.canManageFilesPermissions && ( + + {t('datasetActionButtons.editDataset.permissions.file')} + + )} + + ) +} diff --git a/src/sections/dataset/dataset-action-buttons/link-dataset-button/LinkDatasetButton.tsx b/src/sections/dataset/dataset-action-buttons/link-dataset-button/LinkDatasetButton.tsx new file mode 100644 index 000000000..0a51341cd --- /dev/null +++ b/src/sections/dataset/dataset-action-buttons/link-dataset-button/LinkDatasetButton.tsx @@ -0,0 +1,25 @@ +import { Button, ButtonGroup } from '@iqss/dataverse-design-system' +import { Dataset, DatasetPublishingStatus } from '../../../../dataset/domain/models/Dataset' +import { useTranslation } from 'react-i18next' +import { useSession } from '../../../session/SessionContext' + +interface LinkDatasetButtonProps { + dataset: Dataset +} +export function LinkDatasetButton({ dataset }: LinkDatasetButtonProps) { + const { t } = useTranslation('dataset') + const { user } = useSession() + if ( + !user || + !dataset.isReleased || + dataset.version.publishingStatus === DatasetPublishingStatus.DEACCESSIONED + ) { + return <> + } + + return ( + + + + ) +} diff --git a/src/sections/dataset/dataset-action-buttons/publish-dataset-menu/ChangeCurationStatusMenu.tsx b/src/sections/dataset/dataset-action-buttons/publish-dataset-menu/ChangeCurationStatusMenu.tsx new file mode 100644 index 000000000..d5345fb16 --- /dev/null +++ b/src/sections/dataset/dataset-action-buttons/publish-dataset-menu/ChangeCurationStatusMenu.tsx @@ -0,0 +1,44 @@ +import { + DropdownButton, + DropdownButtonItem, + DropdownSeparator +} from '@iqss/dataverse-design-system' +import { useSettings } from '../../../settings/SettingsContext' +import { useEffect, useState } from 'react' +import { SettingName } from '../../../../settings/domain/models/Setting' +import { AllowedExternalStatuses } from '../../../../settings/domain/models/AllowedExternalStatuses' +import { useTranslation } from 'react-i18next' + +export function ChangeCurationStatusMenu() { + const { t } = useTranslation('dataset') + const { getSettingByName } = useSettings() + const [allowedExternalStatuses, setAllowedExternalStatuses] = useState([]) + useEffect(() => { + getSettingByName(SettingName.ALLOWED_EXTERNAL_STATUSES) + .then((allowedExternalStatuses) => { + setAllowedExternalStatuses(allowedExternalStatuses.value) + }) + .catch((error) => { + console.error(error) + }) + }, [getSettingByName]) + + if (allowedExternalStatuses.length === 0) { + return <> + } + + return ( + + {allowedExternalStatuses.map((status) => ( + {status} + ))} + + + {t('datasetActionButtons.publish.removeCurrentStatus')} + + + ) +} diff --git a/src/sections/dataset/dataset-action-buttons/publish-dataset-menu/PublishDatasetMenu.tsx b/src/sections/dataset/dataset-action-buttons/publish-dataset-menu/PublishDatasetMenu.tsx new file mode 100644 index 000000000..58ec23cd8 --- /dev/null +++ b/src/sections/dataset/dataset-action-buttons/publish-dataset-menu/PublishDatasetMenu.tsx @@ -0,0 +1,36 @@ +import { Dataset, DatasetPublishingStatus } from '../../../../dataset/domain/models/Dataset' +import { DropdownButton, DropdownButtonItem } from '@iqss/dataverse-design-system' +import { ChangeCurationStatusMenu } from './ChangeCurationStatusMenu' +import { useTranslation } from 'react-i18next' + +interface PublishDatasetMenuProps { + dataset: Dataset +} + +export function PublishDatasetMenu({ dataset }: PublishDatasetMenuProps) { + if ( + !dataset.version.isLatest || + dataset.version.publishingStatus !== DatasetPublishingStatus.DRAFT || + !dataset.permissions.canPublishDataset + ) { + return <> + } + + const { t } = useTranslation('dataset') + return ( + + {t('datasetActionButtons.publish.publish')} + {dataset.version.isInReview && ( + {t('datasetActionButtons.publish.returnToAuthor')} + )} + + + ) +} diff --git a/src/sections/dataset/dataset-action-buttons/submit-for-review-button/SubmitForReviewButton.tsx b/src/sections/dataset/dataset-action-buttons/submit-for-review-button/SubmitForReviewButton.tsx new file mode 100644 index 000000000..1f9c18a3a --- /dev/null +++ b/src/sections/dataset/dataset-action-buttons/submit-for-review-button/SubmitForReviewButton.tsx @@ -0,0 +1,32 @@ +import { Dataset, DatasetPublishingStatus } from '../../../../dataset/domain/models/Dataset' +import { Button } from '@iqss/dataverse-design-system' +import { useTranslation } from 'react-i18next' + +interface SubmitForReviewButtonProps { + dataset: Dataset +} + +export function SubmitForReviewButton({ dataset }: SubmitForReviewButtonProps) { + if ( + !dataset.version.isLatest || + dataset.version.publishingStatus !== DatasetPublishingStatus.DRAFT || + dataset.isLockedInWorkflow || + dataset.permissions.canPublishDataset || + !dataset.permissions.canUpdateDataset + ) { + return <> + } + + const { t } = useTranslation('dataset') + return ( + + ) +} diff --git a/src/sections/dataset/dataset-files/dataset-upload-files-button/DatasetUploadFilesButton.tsx b/src/sections/dataset/dataset-files/dataset-upload-files-button/DatasetUploadFilesButton.tsx index d7b6fac2a..3f33cc8fb 100644 --- a/src/sections/dataset/dataset-files/dataset-upload-files-button/DatasetUploadFilesButton.tsx +++ b/src/sections/dataset/dataset-files/dataset-upload-files-button/DatasetUploadFilesButton.tsx @@ -3,25 +3,26 @@ import { PlusLg } from 'react-bootstrap-icons' import { useSession } from '../../../session/SessionContext' import styles from './DatasetUploadFilesButton.module.scss' import { useTranslation } from 'react-i18next' +import { useDataset } from '../../DatasetContext' export function DatasetUploadFilesButton() { const { t } = useTranslation('dataset') const { user } = useSession() - const userHasDatasetUpdatePermissions = true // TODO - Implement permissions - const datasetLockedFromEdits = false // TODO - Ask Guillermo if this a dataset property coming from the api + const { dataset } = useDataset() const handleClick = () => { // TODO - Implement upload files } - if (!user || !userHasDatasetUpdatePermissions) { + if (!user || !dataset?.permissions.canUpdateDataset) { return <> } + return ( ) } diff --git a/src/sections/dataset/dataset-files/files-table/file-actions/edit-files-menu/EditFilesMenu.tsx b/src/sections/dataset/dataset-files/files-table/file-actions/edit-files-menu/EditFilesMenu.tsx index 2ab92b860..c255662df 100644 --- a/src/sections/dataset/dataset-files/files-table/file-actions/edit-files-menu/EditFilesMenu.tsx +++ b/src/sections/dataset/dataset-files/files-table/file-actions/edit-files-menu/EditFilesMenu.tsx @@ -5,7 +5,7 @@ import styles from './EditFilesMenu.module.scss' import { EditFilesOptions } from './EditFilesOptions' import { File } from '../../../../../../files/domain/models/File' import { useTranslation } from 'react-i18next' -import { useFileEditDatasetPermission } from '../../../../../file/file-permissions/useFileEditDatasetPermission' +import { useDataset } from '../../../../DatasetContext' interface EditFilesMenuProps { files: File[] @@ -14,14 +14,12 @@ const MINIMUM_FILES_COUNT_TO_SHOW_EDIT_FILES_BUTTON = 1 export function EditFilesMenu({ files }: EditFilesMenuProps) { const { t } = useTranslation('files') const { user } = useSession() - const { sessionUserHasEditDatasetPermission } = useFileEditDatasetPermission(files[0] || {}) - const datasetHasValidTermsOfAccess = true // TODO - Implement terms of access validation - const datasetLockedFromEdits = false // TODO - Ask Guillermo if this a dataset property coming from the api + const { dataset } = useDataset() if ( files.length < MINIMUM_FILES_COUNT_TO_SHOW_EDIT_FILES_BUTTON || !user || - !sessionUserHasEditDatasetPermission + !dataset?.permissions.canUpdateDataset ) { return <> } @@ -30,7 +28,7 @@ export function EditFilesMenu({ files }: EditFilesMenuProps) { variant="secondary" id="edit-files-menu" title={t('actions.editFilesMenu.title')} - disabled={datasetLockedFromEdits || !datasetHasValidTermsOfAccess} + disabled={dataset.isLockedFromEdits || !dataset.hasValidTermsOfAccess} icon={}> diff --git a/src/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/file-options-menu/FileOptionsMenu.tsx b/src/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/file-options-menu/FileOptionsMenu.tsx index 81d09f813..d1cdd06f7 100644 --- a/src/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/file-options-menu/FileOptionsMenu.tsx +++ b/src/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/file-options-menu/FileOptionsMenu.tsx @@ -4,19 +4,17 @@ import { PencilFill, ThreeDotsVertical } from 'react-bootstrap-icons' import { useSession } from '../../../../../../../session/SessionContext' import { EditFilesOptions } from '../../../edit-files-menu/EditFilesOptions' import { useTranslation } from 'react-i18next' -import { useFileEditDatasetPermission } from '../../../../../../../file/file-permissions/useFileEditDatasetPermission' import { useState } from 'react' import { FileAlreadyDeletedModal } from './FileAlreadyDeletedModal' +import { useDataset } from '../../../../../../DatasetContext' export function FileOptionsMenu({ file }: { file: File }) { const { t } = useTranslation('files') const { user } = useSession() - const { sessionUserHasEditDatasetPermission } = useFileEditDatasetPermission(file) - const datasetHasValidTermsOfAccess = true // TODO - Implement terms of access validation - const datasetLockedFromEdits = false // TODO - Ask Guillermo if this a dataset property coming from the api + const { dataset } = useDataset() const [showFileAlreadyDeletedModal, setShowFileAlreadyDeletedModal] = useState(false) - if (!user || !sessionUserHasEditDatasetPermission || !datasetHasValidTermsOfAccess) { + if (!user || !dataset?.permissions.canUpdateDataset || !dataset.hasValidTermsOfAccess) { return <> } @@ -26,7 +24,7 @@ export function FileOptionsMenu({ file }: { file: File }) { {t('actions.optionsMenu.title')}}> - {isLoading &&
Loading...
} - - ) - } + const mountWithDataset = ( + component: ReactNode, + dataset: DatasetModel | undefined, + anonymizedView = false + ) => { + const searchParams = anonymizedView + ? { privateUrlToken: 'some-private-url-token' } + : { persistentId: 'some-persistent-id', version: 'some-version' } + datasetRepository.getByPersistentId = cy.stub().resolves(dataset) + datasetRepository.getByPrivateUrlToken = cy.stub().resolves(dataset) cy.customMount( - - + + + {component} + + ) + } + + it('renders skeleton while loading', () => { + const testDataset = DatasetMother.create() - cy.findByText(buttonText).click() + mountWithDataset(, testDataset) cy.findByTestId('dataset-skeleton').should('exist') cy.findByText(testDataset.getTitle()).should('not.exist') @@ -45,54 +46,16 @@ describe('Dataset', () => { it('renders page not found when dataset is null', () => { const emptyDataset = DatasetMother.createEmpty() - const datasetRepository: DatasetRepository = {} as DatasetRepository - datasetRepository.getByPersistentId = cy.stub().resolves(emptyDataset) - cy.customMount( - - - - ) - - cy.findByText('Page Not Found').should('exist') - }) - - it('renders page not found when no searchParam is passed', () => { - const datasetRepository: DatasetRepository = {} as DatasetRepository - datasetRepository.getByPersistentId = cy.stub().resolves(testDataset) - - cy.customMount( - - - - ) + mountWithDataset(, emptyDataset) cy.findByText('Page Not Found').should('exist') }) it('renders the Dataset page title and labels', () => { - const datasetRepository: DatasetRepository = {} as DatasetRepository - datasetRepository.getByPersistentId = cy.stub().resolves(testDataset) + const testDataset = DatasetMother.create() - cy.customMount( - - - - ) - - cy.wrap(datasetRepository.getByPersistentId).should('be.calledWith', testDataset.persistentId) + mountWithDataset(, testDataset) cy.findAllByText(testDataset.getTitle()).should('exist') @@ -102,18 +65,9 @@ describe('Dataset', () => { }) it('renders the Dataset Metadata tab', () => { - const datasetRepository: DatasetRepository = {} as DatasetRepository - datasetRepository.getByPersistentId = cy.stub().resolves(testDataset) + const testDataset = DatasetMother.create() - cy.customMount( - - - - ) + mountWithDataset(, testDataset) cy.findAllByText(testDataset.getTitle()).should('exist') @@ -126,28 +80,20 @@ describe('Dataset', () => { }) it('renders the Dataset in anonymized view', () => { - const setAnonymizedView = () => {} const testDatasetAnonymized = DatasetMother.createAnonymized() - const datasetRepository: DatasetRepository = {} as DatasetRepository - datasetRepository.getByPrivateUrlToken = cy.stub().resolves(testDatasetAnonymized) - const privateUrlToken = 'some-token' - - cy.customMount( - - - - - - ) - cy.wrap(datasetRepository.getByPrivateUrlToken).should('be.calledWith', privateUrlToken) + mountWithDataset(, testDatasetAnonymized) cy.findByRole('tab', { name: 'Metadata' }).click() cy.findAllByText(ANONYMIZED_FIELD_VALUE).should('exist') }) + + it('renders the Dataset Action Buttons', () => { + const testDataset = DatasetMother.create() + + mountWithDataset(, testDataset) + + cy.findByRole('group', { name: 'Dataset Action Buttons' }).should('exist') + }) }) diff --git a/tests/component/sections/dataset/DatasetProvider.spec.tsx b/tests/component/sections/dataset/DatasetProvider.spec.tsx new file mode 100644 index 000000000..03684cf44 --- /dev/null +++ b/tests/component/sections/dataset/DatasetProvider.spec.tsx @@ -0,0 +1,117 @@ +import { DatasetProvider } from '../../../../src/sections/dataset/DatasetProvider' +import { DatasetRepository } from '../../../../src/dataset/domain/repositories/DatasetRepository' +import { DatasetMother } from '../../dataset/domain/models/DatasetMother' +import { useDataset } from '../../../../src/sections/dataset/DatasetContext' +import { LoadingProvider } from '../../../../src/sections/loading/LoadingProvider' + +function TestComponent() { + const { dataset, isLoading } = useDataset() + + return ( +
+ {dataset ? {dataset.getTitle()} : Dataset Not Found} + {isLoading &&
Loading...
} +
+ ) +} + +const datasetRepository: DatasetRepository = {} as DatasetRepository +const dataset = DatasetMother.create() + +describe('DatasetProvider', () => { + beforeEach(() => { + datasetRepository.getByPersistentId = cy + .stub() + .resolves(Cypress.Promise.resolve(dataset).delay(1000)) + datasetRepository.getByPrivateUrlToken = cy.stub().resolves(dataset) + }) + + it('gets the dataset by persistentId', () => { + cy.mount( + + + + + + ) + + cy.findByText('Loading...').should('exist') + cy.wrap(datasetRepository.getByPersistentId).should('be.calledOnceWith', dataset.persistentId) + cy.findByText(dataset.getTitle()).should('exist') + cy.findByText('Loading...').should('not.exist') + }) + + it('gets the dataset by persistentId and version', () => { + cy.mount( + + + + + + ) + + cy.findByText('Loading...').should('exist') + cy.wrap(datasetRepository.getByPersistentId).should( + 'be.calledOnceWith', + dataset.persistentId, + 'draft' + ) + cy.findByText(dataset.getTitle()).should('exist') + cy.findByText('Loading...').should('not.exist') + }) + + it('gets the dataset by privateUrlToken', () => { + cy.mount( + + + + + + ) + + cy.findByText('Loading...').should('exist') + cy.wrap(datasetRepository.getByPrivateUrlToken).should( + 'be.calledOnce', + 'some-private-url-token' + ) + cy.findByText(dataset.getTitle()).should('exist') + cy.findByText('Loading...').should('not.exist') + }) + + it('stops loading if searchParams not passed', () => { + cy.mount( + + + + + + ) + + cy.findByText('Loading...').should('exist') + cy.findByText('Dataset Not Found').should('exist') + cy.findByText('Loading...').should('not.exist') + }) + + it('stops loading if error happens', () => { + datasetRepository.getByPersistentId = cy.stub().rejects(new Error('some error')) + cy.mount( + + + + + + ) + + cy.findByText('Loading...').should('exist') + cy.findByText('Dataset Not Found').should('exist') + cy.findByText('Loading...').should('not.exist') + }) +}) diff --git a/tests/component/sections/dataset/dataset-action-buttons/DatasetActionButtons.spec.tsx b/tests/component/sections/dataset/dataset-action-buttons/DatasetActionButtons.spec.tsx new file mode 100644 index 000000000..493613a7c --- /dev/null +++ b/tests/component/sections/dataset/dataset-action-buttons/DatasetActionButtons.spec.tsx @@ -0,0 +1,44 @@ +import { DatasetActionButtons } from '../../../../../src/sections/dataset/dataset-action-buttons/DatasetActionButtons' +import { + DatasetMother, + DatasetPermissionsMother, + DatasetVersionMother +} from '../../../dataset/domain/models/DatasetMother' + +describe('DatasetActionButtons', () => { + it('renders the DatasetActionButtons with the Publish button', () => { + const dataset = DatasetMother.create({ + version: DatasetVersionMother.createDraftAsLatestVersion(), + permissions: DatasetPermissionsMother.createWithAllAllowed(), + isReleased: true + }) + + cy.mountAuthenticated() + + cy.findByRole('group', { name: 'Dataset Action Buttons' }).should('exist') + cy.findByRole('button', { name: 'Access Dataset' }).should('exist') + cy.findByRole('button', { name: 'Publish Dataset' }).should('exist') + cy.findByRole('button', { name: 'Edit Dataset' }).should('exist') + cy.findByRole('button', { name: 'Link Dataset' }).should('exist') + }) + + it('renders the DatasetActionButtons with the Submit for Review button', () => { + const dataset = DatasetMother.create({ + version: DatasetVersionMother.createDraftAsLatestVersion(), + permissions: DatasetPermissionsMother.create({ + canDownloadFiles: true, + canUpdateDataset: true, + canPublishDataset: false + }), + isReleased: true + }) + + cy.mountAuthenticated() + + cy.findByRole('group', { name: 'Dataset Action Buttons' }).should('exist') + cy.findByRole('button', { name: 'Access Dataset' }).should('exist') + cy.findByRole('button', { name: 'Submit for Review' }).should('exist') + cy.findByRole('button', { name: 'Edit Dataset' }).should('exist') + cy.findByRole('button', { name: 'Link Dataset' }).should('exist') + }) +}) diff --git a/tests/component/sections/dataset/dataset-action-buttons/access-dataset-menu/AccessDatasetMenu.spec.tsx b/tests/component/sections/dataset/dataset-action-buttons/access-dataset-menu/AccessDatasetMenu.spec.tsx new file mode 100644 index 000000000..c30dac356 --- /dev/null +++ b/tests/component/sections/dataset/dataset-action-buttons/access-dataset-menu/AccessDatasetMenu.spec.tsx @@ -0,0 +1,46 @@ +import { AccessDatasetMenu } from '../../../../../../src/sections/dataset/dataset-action-buttons/access-dataset-menu/AccessDatasetMenu' +import { + DatasetPermissionsMother, + DatasetVersionMother +} from '../../../../dataset/domain/models/DatasetMother' + +describe('AccessDatasetMenu', () => { + it('renders the AccessDatasetMenu if the user has download files permissions and the dataset is not deaccessioned', () => { + const version = DatasetVersionMother.createReleased() + const permissions = DatasetPermissionsMother.createWithFilesDownloadAllowed() + + cy.customMount() + + cy.findByRole('button', { name: 'Access Dataset' }).should('exist') + }) + + it('renders the AccessDatasetMenu if the user has download files permissions and the dataset is deaccessioned with update dataset permissions', () => { + const version = DatasetVersionMother.createDeaccessioned() + const permissions = DatasetPermissionsMother.create({ + canUpdateDataset: true, + canDownloadFiles: true + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Access Dataset' }).should('exist') + }) + + it('does not render the AccessDatasetMenu if the user do not have download files permissions', () => { + const version = DatasetVersionMother.create() + const permissions = DatasetPermissionsMother.createWithFilesDownloadNotAllowed() + + cy.customMount() + + cy.findByRole('button', { name: 'Access Dataset' }).should('not.exist') + }) + + it('does not render the AccessDatasetMenu if the dataset is deaccessioned and the user does not have update dataset permissions', () => { + const version = DatasetVersionMother.createDeaccessioned() + const permissions = DatasetPermissionsMother.createWithUpdateDatasetNotAllowed() + + cy.customMount() + + cy.findByRole('button', { name: 'Access Dataset' }).should('not.exist') + }) +}) diff --git a/tests/component/sections/dataset/dataset-action-buttons/edit-dataset-menu/DeaccessionDatasetButton.spec.tsx b/tests/component/sections/dataset/dataset-action-buttons/edit-dataset-menu/DeaccessionDatasetButton.spec.tsx new file mode 100644 index 000000000..2730a2432 --- /dev/null +++ b/tests/component/sections/dataset/dataset-action-buttons/edit-dataset-menu/DeaccessionDatasetButton.spec.tsx @@ -0,0 +1,41 @@ +import { + DatasetMother, + DatasetPermissionsMother +} from '../../../../dataset/domain/models/DatasetMother' +import { DeaccessionDatasetButton } from '../../../../../../src/sections/dataset/dataset-action-buttons/edit-dataset-menu/DeaccessionDatasetButton' + +describe('DeaccessionDatasetButton', () => { + it('renders the DeaccessionDatasetButton if the user has publish dataset permissions and the dataset is released', () => { + const dataset = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithPublishingDatasetAllowed(), + isReleased: true + }) + + cy.customMount() + + cy.findByRole('separator').should('exist') + cy.findByRole('button', { name: 'Deaccession Dataset' }).should('exist') + }) + + it('does not render the DeaccessionDatasetButton if the user does not have publish dataset permissions', () => { + const dataset = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithPublishingDatasetNotAllowed(), + isReleased: true + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Deaccession Dataset' }).should('not.exist') + }) + + it('does not render the DeaccessionDatasetButton if the dataset is not released', () => { + const dataset = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithPublishingDatasetAllowed(), + isReleased: false + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Deaccession Dataset' }).should('not.exist') + }) +}) diff --git a/tests/component/sections/dataset/dataset-action-buttons/edit-dataset-menu/DeleteDatasetButton.spec.tsx b/tests/component/sections/dataset/dataset-action-buttons/edit-dataset-menu/DeleteDatasetButton.spec.tsx new file mode 100644 index 000000000..7f353c19b --- /dev/null +++ b/tests/component/sections/dataset/dataset-action-buttons/edit-dataset-menu/DeleteDatasetButton.spec.tsx @@ -0,0 +1,71 @@ +import { DeleteDatasetButton } from '../../../../../../src/sections/dataset/dataset-action-buttons/edit-dataset-menu/DeleteDatasetButton' +import { + DatasetMother, + DatasetPermissionsMother, + DatasetVersionMother +} from '../../../../dataset/domain/models/DatasetMother' + +describe('DeleteDatasetButton', () => { + it('renders the DeleteDatasetButton if the user has delete dataset permissions and the latest version is a draft', () => { + const dataset = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithDeleteDatasetAllowed(), + locks: [], + version: DatasetVersionMother.createReleasedWithLatestVersionIsADraft() + }) + + cy.customMount() + + cy.findByRole('separator').should('exist') + cy.findByRole('button', { name: /Delete/ }).should('exist') + }) + + it('renders the Delete Dataset button if the dataset is not released', () => { + const dataset = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithDeleteDatasetAllowed(), + locks: [], + version: DatasetVersionMother.createDraftWithLatestVersionIsADraft(), + isReleased: false + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Delete Dataset' }).should('exist') + }) + + it('renders the Delete Draft Version if the dataset is released', () => { + const dataset = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithDeleteDatasetAllowed(), + locks: [], + version: DatasetVersionMother.createReleasedWithLatestVersionIsADraft(), + isReleased: true + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Delete Draft Version' }).should('exist') + }) + + it('does not render the DeleteDatasetButton if the user does not have delete dataset permissions', () => { + const dataset = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithDeleteDatasetNotAllowed(), + locks: [], + version: DatasetVersionMother.createReleasedWithLatestVersionIsADraft() + }) + + cy.customMount() + + cy.findByRole('button', { name: /Delete/ }).should('not.exist') + }) + + it('does not render the DeleteDatasetButton if the latest version is not a draft', () => { + const dataset = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithDeleteDatasetAllowed(), + locks: [], + version: DatasetVersionMother.createWithLatestVersionIsNotADraft() + }) + + cy.customMount() + + cy.findByRole('button', { name: /Delete/ }).should('not.exist') + }) +}) diff --git a/tests/component/sections/dataset/dataset-action-buttons/edit-dataset-menu/EditDatasetMenu.spec.tsx b/tests/component/sections/dataset/dataset-action-buttons/edit-dataset-menu/EditDatasetMenu.spec.tsx new file mode 100644 index 000000000..52ec1060f --- /dev/null +++ b/tests/component/sections/dataset/dataset-action-buttons/edit-dataset-menu/EditDatasetMenu.spec.tsx @@ -0,0 +1,88 @@ +import { + DatasetLockMother, + DatasetMother, + DatasetPermissionsMother, + DatasetVersionMother +} from '../../../../dataset/domain/models/DatasetMother' +import { EditDatasetMenu } from '../../../../../../src/sections/dataset/dataset-action-buttons/edit-dataset-menu/EditDatasetMenu' + +describe('EditDatasetMenu', () => { + it('renders the EditDatasetMenu if the user has update dataset permissions', () => { + const dataset = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithAllAllowed(), + locks: [], + hasValidTermsOfAccess: true, + version: DatasetVersionMother.createReleasedWithLatestVersionIsADraft(), + isReleased: true + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Edit Dataset' }).should('exist').should('be.enabled').click() + + cy.findByRole('button', { name: 'Files (Upload)' }).should('exist') + cy.findByRole('button', { name: 'Metadata' }).should('exist') + cy.findByRole('button', { name: 'Terms' }).should('exist') + cy.findByRole('button', { name: 'Thumbnails + Widgets' }).should('exist') + cy.findByRole('button', { name: /Delete/ }).should('exist') + cy.findByRole('button', { name: 'Permissions' }).should('exist') + cy.findByRole('button', { name: 'Private URL' }).should('exist') + cy.findByRole('button', { name: 'Deaccession Dataset' }).should('exist') + }) + + it('does not render the EditDatasetMenu if the user does not have update dataset permissions', () => { + const dataset = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithUpdateDatasetNotAllowed(), + locks: [] + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Edit Dataset' }).should('not.exist') + }) + + it('renders the button disabled if the dataset is locked from edits', () => { + const dataset = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithUpdateDatasetAllowed(), + locks: [DatasetLockMother.createLockedInEditInProgress()] + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Edit Dataset' }).should('exist').should('be.disabled') + }) + + it('renders some options enabled if the dataset has valid terms of access', () => { + const dataset = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithUpdateDatasetAllowed(), + locks: [], + hasValidTermsOfAccess: true + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Edit Dataset' }).click() + cy.findByRole('button', { name: 'Files (Upload)' }) + .should('exist') + .should('not.have.class', 'disabled') + cy.findByRole('button', { name: 'Metadata' }) + .should('exist') + .should('not.have.class', 'disabled') + }) + + it('renders some options disabled if the dataset does not have valid terms of access', () => { + const dataset = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithUpdateDatasetAllowed(), + locks: [], + hasValidTermsOfAccess: false + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Edit Dataset' }).click() + cy.findByRole('button', { name: 'Files (Upload)' }) + .should('exist') + .should('have.class', 'disabled') + cy.findByRole('button', { name: 'Metadata' }).should('exist').should('have.class', 'disabled') + }) +}) diff --git a/tests/component/sections/dataset/dataset-action-buttons/edit-dataset-menu/EditDatasetPermissionsMenu.spec.tsx b/tests/component/sections/dataset/dataset-action-buttons/edit-dataset-menu/EditDatasetPermissionsMenu.spec.tsx new file mode 100644 index 000000000..b43d3d3ac --- /dev/null +++ b/tests/component/sections/dataset/dataset-action-buttons/edit-dataset-menu/EditDatasetPermissionsMenu.spec.tsx @@ -0,0 +1,67 @@ +import { EditDatasetPermissionsMenu } from '../../../../../../src/sections/dataset/dataset-action-buttons/edit-dataset-menu/EditDatasetPermissionsMenu' +import { + DatasetMother, + DatasetPermissionsMother +} from '../../../../dataset/domain/models/DatasetMother' +import { SettingRepository } from '../../../../../../src/settings/domain/repositories/SettingRepository' +import { SettingMother } from '../../../../settings/domain/models/SettingMother' +import { SettingsProvider } from '../../../../../../src/sections/settings/SettingsProvider' + +describe('EditDatasetPermissionsMenu', () => { + it('renders the EditDatasetPermissionsMenu if the user has manage dataset permissions', () => { + const dataset = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithManageDatasetPermissionsAllowed(), + locks: [] + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Permissions' }).should('exist').click() + cy.findByRole('button', { name: 'Dataset' }).should('exist') + }) + + it('renders the EditDatasetPermissionsMenu if the user has manage files permissions', () => { + const dataset = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithManageFilesPermissionsAllowed(), + locks: [] + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Permissions' }).should('exist').click() + cy.findByRole('button', { name: 'File' }).should('exist') + }) + + it('renders the Permissions button with no options if there is public store', () => { + const dataset = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithManageFilesPermissionsAllowed(), + locks: [] + }) + + const settingRepository = {} as SettingRepository + settingRepository.getByName = cy.stub().resolves(SettingMother.createHasPublicStore(true)) + + cy.customMount( + + + + ) + + cy.wait(1000) // Wait for the settings to be loaded + + cy.findByRole('button', { name: 'Permissions' }).should('exist').click() + cy.findByRole('button', { name: 'File' }).should('not.exist') + cy.findByRole('button', { name: 'Dataset' }).should('not.exist') + }) + + it('does not render the EditDatasetPermissionsMenu if the user does not have manage dataset permissions or manage files permissions', () => { + const dataset = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithManagePermissionsNotAllowed(), + locks: [] + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Permissions' }).should('not.exist') + }) +}) diff --git a/tests/component/sections/dataset/dataset-action-buttons/link-dataset-button/LinkDatasetButton.spec.tsx b/tests/component/sections/dataset/dataset-action-buttons/link-dataset-button/LinkDatasetButton.spec.tsx new file mode 100644 index 000000000..f6318c4d1 --- /dev/null +++ b/tests/component/sections/dataset/dataset-action-buttons/link-dataset-button/LinkDatasetButton.spec.tsx @@ -0,0 +1,51 @@ +import { + DatasetMother, + DatasetVersionMother +} from '../../../../dataset/domain/models/DatasetMother' +import { LinkDatasetButton } from '../../../../../../src/sections/dataset/dataset-action-buttons/link-dataset-button/LinkDatasetButton' + +describe('LinkDatasetButton', () => { + it('renders the LinkDatasetButton if the user is authenticated and the dataset version is not deaccessioned and the dataset is released', () => { + const dataset = DatasetMother.create({ + version: DatasetVersionMother.createDraft(), + isReleased: true + }) + + cy.mountAuthenticated() + + cy.findByRole('button', { name: 'Link Dataset' }).should('exist') + }) + + it('does not render the LinkDatasetButton if the user is not authenticated', () => { + const dataset = DatasetMother.create({ + version: DatasetVersionMother.createDraft(), + isReleased: true + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Link Dataset' }).should('not.exist') + }) + + it('does not render the LinkDatasetButton if the dataset version is deaccessioned', () => { + const dataset = DatasetMother.create({ + version: DatasetVersionMother.createDeaccessioned(), + isReleased: true + }) + + cy.mountAuthenticated() + + cy.findByRole('button', { name: 'Link Dataset' }).should('not.exist') + }) + + it('does not render the LinkDatasetButton if the dataset is not released', () => { + const dataset = DatasetMother.create({ + version: DatasetVersionMother.createDraft(), + isReleased: false + }) + + cy.mountAuthenticated() + + cy.findByRole('button', { name: 'Link Dataset' }).should('not.exist') + }) +}) diff --git a/tests/component/sections/dataset/dataset-action-buttons/publish-dataset-menu/ChangeCurationStatusMenu.spec.tsx b/tests/component/sections/dataset/dataset-action-buttons/publish-dataset-menu/ChangeCurationStatusMenu.spec.tsx new file mode 100644 index 000000000..7e8c81ff8 --- /dev/null +++ b/tests/component/sections/dataset/dataset-action-buttons/publish-dataset-menu/ChangeCurationStatusMenu.spec.tsx @@ -0,0 +1,35 @@ +import { ChangeCurationStatusMenu } from '../../../../../../src/sections/dataset/dataset-action-buttons/publish-dataset-menu/ChangeCurationStatusMenu' + +import { SettingMother } from '../../../../settings/domain/models/SettingMother' +import { SettingsProvider } from '../../../../../../src/sections/settings/SettingsProvider' +import { SettingRepository } from '../../../../../../src/settings/domain/repositories/SettingRepository' + +describe('ChangeCurationStatusMenu', () => { + it('renders the ChangeCurationStatusMenu if external statuses are allowed and the user has update dataset permissions', () => { + const settingRepository = {} as SettingRepository + settingRepository.getByName = cy + .stub() + .resolves(SettingMother.createExternalStatusesAllowed(['Author Contacted', 'Privacy Review'])) + + cy.customMount( + + + + ) + + cy.findByRole('button', { name: 'Change Curation Status' }) + .should('exist') + .should('be.enabled') + .click() + + cy.findByRole('button', { name: 'Author Contacted' }).should('exist') + cy.findByRole('button', { name: 'Privacy Review' }).should('exist') + cy.findByRole('button', { name: 'Remove Current Status' }).should('exist') + }) + + it('does not render the ChangeCurationStatusMenu if external statuses are not allowed', () => { + cy.customMount() + + cy.findByRole('button', { name: 'Change Curation Status' }).should('not.exist') + }) +}) diff --git a/tests/component/sections/dataset/dataset-action-buttons/publish-dataset-menu/PublishDatasetMenu.spec.tsx b/tests/component/sections/dataset/dataset-action-buttons/publish-dataset-menu/PublishDatasetMenu.spec.tsx new file mode 100644 index 000000000..9960f2655 --- /dev/null +++ b/tests/component/sections/dataset/dataset-action-buttons/publish-dataset-menu/PublishDatasetMenu.spec.tsx @@ -0,0 +1,173 @@ +import { PublishDatasetMenu } from '../../../../../../src/sections/dataset/dataset-action-buttons/publish-dataset-menu/PublishDatasetMenu' +import { + DatasetLockMother, + DatasetMother, + DatasetPermissionsMother, + DatasetVersionMother +} from '../../../../dataset/domain/models/DatasetMother' +import { DatasetLockReason } from '../../../../../../src/dataset/domain/models/Dataset' +import { SettingRepository } from '../../../../../../src/settings/domain/repositories/SettingRepository' +import { SettingMother } from '../../../../settings/domain/models/SettingMother' +import { SettingsProvider } from '../../../../../../src/sections/settings/SettingsProvider' + +describe('PublishDatasetMenu', () => { + it('renders the PublishDatasetMenu if is dataset latest version and it is a draft and publishing is allowed', () => { + const dataset = DatasetMother.create({ + version: DatasetVersionMother.createDraftAsLatestVersion(), + permissions: DatasetPermissionsMother.createWithPublishingDatasetAllowed(), + locks: [], + hasValidTermsOfAccess: true, + isValid: true + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Publish Dataset' }) + .should('exist') + .click() + .should('be.enabled') + + cy.findByRole('button', { name: 'Publish' }).should('exist') + }) + + it('renders the PublishDatasetMenu with the Change Curation Status sub menu', () => { + const dataset = DatasetMother.create({ + version: DatasetVersionMother.createDraftAsLatestVersion(), + permissions: DatasetPermissionsMother.createWithPublishingDatasetAllowed(), + locks: [], + hasValidTermsOfAccess: true, + isValid: true + }) + + const settingRepository = {} as SettingRepository + settingRepository.getByName = cy + .stub() + .resolves(SettingMother.createExternalStatusesAllowed(['Author Contacted', 'Privacy Review'])) + + cy.customMount( + + + + ) + + cy.findByRole('button', { name: 'Publish Dataset' }).click() + + cy.findByRole('button', { name: 'Change Curation Status' }).should('exist') + }) + + it('does not render the PublishDatasetMenu if publishing is not allowed', () => { + const dataset = DatasetMother.create({ + version: DatasetVersionMother.createDraftAsLatestVersion(), + permissions: DatasetPermissionsMother.createWithPublishingDatasetNotAllowed(), + locks: [] + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Publish Dataset' }).should('not.exist') + }) + + it('does not render the PublishDatasetMenu if it is not a draft', () => { + const dataset = DatasetMother.create({ + version: DatasetVersionMother.createReleased(), + permissions: DatasetPermissionsMother.createWithPublishingDatasetAllowed(), + locks: [] + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Publish Dataset' }).should('not.exist') + }) + + it('does not render the PublishDatasetMenu if it is not the latest version', () => { + const dataset = DatasetMother.create({ + version: DatasetVersionMother.createDraft(), + permissions: DatasetPermissionsMother.createWithPublishingDatasetAllowed(), + locks: [] + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Publish Dataset' }).should('not.exist') + }) + + it('renders the button enabled if the dataset publishing is locked and the reason is in review and the user has dataset update permissions', () => { + const dataset = DatasetMother.create({ + version: DatasetVersionMother.createDraftAsLatestVersion(), + permissions: DatasetPermissionsMother.createWithPublishingDatasetAllowed(), + locks: [DatasetLockMother.createLockedInReview()], + hasValidTermsOfAccess: true, + isValid: true + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Publish Dataset' }).should('be.enabled') + }) + + it('renders the button disabled if the dataset publishing is locked', () => { + const dataset = DatasetMother.create({ + version: DatasetVersionMother.createDraftAsLatestVersion(), + permissions: DatasetPermissionsMother.createWithPublishingDatasetAllowed(), + locks: [ + { + id: 1, + reason: DatasetLockReason.EDIT_IN_PROGRESS + } + ], + hasValidTermsOfAccess: true, + isValid: true + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Publish Dataset' }).should('be.disabled') + }) + + it('renders the button disabled if the dataset does not have valid terms of access', () => { + const dataset = DatasetMother.create({ + version: DatasetVersionMother.createDraftAsLatestVersion(), + permissions: DatasetPermissionsMother.createWithPublishingDatasetAllowed(), + locks: [], + hasValidTermsOfAccess: false, + isValid: true + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Publish Dataset' }).should('be.disabled') + }) + + it('renders the button disabled if the dataset is not valid', () => { + const dataset = DatasetMother.create({ + version: DatasetVersionMother.createDraftAsLatestVersion(), + permissions: DatasetPermissionsMother.createWithPublishingDatasetAllowed(), + locks: [], + hasValidTermsOfAccess: true, + isValid: false + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Publish Dataset' }).should('be.disabled') + }) + + it('renders the Return to Author option if the dataset is in review', () => { + const dataset = DatasetMother.create({ + version: DatasetVersionMother.createDraftAsLatestVersionInReview(), + permissions: DatasetPermissionsMother.createWithPublishingDatasetAllowed(), + locks: [], + hasValidTermsOfAccess: true, + isValid: true + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Publish Dataset' }) + .should('exist') + .click() + .should('be.enabled') + + cy.findByRole('button', { name: 'Return to Author' }).should('exist') + }) +}) diff --git a/tests/component/sections/dataset/dataset-action-buttons/submit-for-review-button/SubmitForReviewButton.spec.tsx b/tests/component/sections/dataset/dataset-action-buttons/submit-for-review-button/SubmitForReviewButton.spec.tsx new file mode 100644 index 000000000..a41edda9f --- /dev/null +++ b/tests/component/sections/dataset/dataset-action-buttons/submit-for-review-button/SubmitForReviewButton.spec.tsx @@ -0,0 +1,173 @@ +import { SubmitForReviewButton } from '../../../../../../src/sections/dataset/dataset-action-buttons/submit-for-review-button/SubmitForReviewButton' +import { + DatasetLockMother, + DatasetMother, + DatasetPermissionsMother, + DatasetVersionMother +} from '../../../../dataset/domain/models/DatasetMother' +import { DatasetLockReason } from '../../../../../../src/dataset/domain/models/Dataset' + +describe('SubmitForReviewButton', () => { + it('renders the SubmitForReviewButton if is dataset latest version and it is a draft and the dataset is not locked in workflow and the user has dataset update permissions and the user do not have publish dataset permissions', () => { + const dataset = DatasetMother.create({ + version: DatasetVersionMother.createDraftAsLatestVersion(), + permissions: DatasetPermissionsMother.create({ + canUpdateDataset: true, + canPublishDataset: false + }), + locks: [], + hasValidTermsOfAccess: true, + isValid: true + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Submit for Review' }).should('exist').should('be.enabled') + }) + + it('does not render the SubmitForReviewButton if is not dataset latest version', () => { + const dataset = DatasetMother.create({ + version: DatasetVersionMother.createDraft(), + permissions: DatasetPermissionsMother.create({ + canUpdateDataset: true, + canPublishDataset: false + }), + locks: [DatasetLockMother.createLockedInWorkflow()] + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Submit for Review' }).should('not.exist') + }) + + it('does not render the SubmitForReviewButton if is not draft version', () => { + const dataset = DatasetMother.create({ + version: DatasetVersionMother.createReleased(), + permissions: DatasetPermissionsMother.create({ + canUpdateDataset: true, + canPublishDataset: false + }), + locks: [DatasetLockMother.createLockedInWorkflow()] + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Submit for Review' }).should('not.exist') + }) + + it('does not render the SubmitForReviewButton if is locked in workflow', () => { + const dataset = DatasetMother.create({ + version: DatasetVersionMother.createDraftAsLatestVersion(), + permissions: DatasetPermissionsMother.create({ + canUpdateDataset: true, + canPublishDataset: false + }), + locks: [DatasetLockMother.createLockedInWorkflow()] + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Submit for Review' }).should('not.exist') + }) + + it('does not render the SubmitForReviewButton if the user do not have dataset update permissions', () => { + const dataset = DatasetMother.create({ + version: DatasetVersionMother.createDraftAsLatestVersion(), + permissions: DatasetPermissionsMother.create({ + canUpdateDataset: false, + canPublishDataset: false + }), + locks: [] + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Submit for Review' }).should('not.exist') + }) + + it('does not render the SubmitForReviewButton if the user has dataset publish permissions', () => { + const dataset = DatasetMother.create({ + version: DatasetVersionMother.createDraftAsLatestVersion(), + permissions: DatasetPermissionsMother.create({ + canUpdateDataset: true, + canPublishDataset: true + }), + locks: [] + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Submit for Review' }).should('not.exist') + }) + + it('renders the button disabled if the dataset publishing is locked', () => { + const dataset = DatasetMother.create({ + version: DatasetVersionMother.createDraftAsLatestVersion(), + permissions: DatasetPermissionsMother.create({ + canUpdateDataset: true, + canPublishDataset: false + }), + locks: [ + { + id: 1, + reason: DatasetLockReason.EDIT_IN_PROGRESS + } + ], + hasValidTermsOfAccess: true, + isValid: true + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Submit for Review' }).should('be.disabled') + }) + + it('renders the button disabled if the dataset does not have valid terms of access', () => { + const dataset = DatasetMother.create({ + version: DatasetVersionMother.createDraftAsLatestVersion(), + permissions: DatasetPermissionsMother.create({ + canUpdateDataset: true, + canPublishDataset: false + }), + locks: [], + hasValidTermsOfAccess: false, + isValid: true + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Submit for Review' }).should('be.disabled') + }) + + it('renders the button disabled if the dataset is not valid', () => { + const dataset = DatasetMother.create({ + version: DatasetVersionMother.createDraftAsLatestVersion(), + permissions: DatasetPermissionsMother.create({ + canUpdateDataset: true, + canPublishDataset: false + }), + locks: [], + hasValidTermsOfAccess: true, + isValid: false + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Submit for Review' }).should('be.disabled') + }) + + it('renders the Submitted for Review button disabled if the latest version is in review', () => { + const dataset = DatasetMother.create({ + version: DatasetVersionMother.createDraftAsLatestVersionInReview(), + permissions: DatasetPermissionsMother.create({ + canUpdateDataset: true, + canPublishDataset: false + }), + locks: [DatasetLockMother.createLockedInReview()] + }) + + cy.customMount() + + cy.findByRole('button', { name: 'Submitted for Review' }).should('be.disabled') + }) +}) diff --git a/tests/component/sections/dataset/dataset-citation/DatasetCitation.spec.tsx b/tests/component/sections/dataset/dataset-citation/DatasetCitation.spec.tsx index 2d4e9ab28..313c197b1 100644 --- a/tests/component/sections/dataset/dataset-citation/DatasetCitation.spec.tsx +++ b/tests/component/sections/dataset/dataset-citation/DatasetCitation.spec.tsx @@ -24,7 +24,13 @@ describe('DatasetCitation', () => { it('shows the draft tooltip when version is draft', () => { const dataset = DatasetMother.create({ - version: new DatasetVersion(1, DatasetPublishingStatus.DRAFT, 1, 0) + version: new DatasetVersion( + 1, + DatasetPublishingStatus.DRAFT, + true, + false, + DatasetPublishingStatus.DRAFT + ) }) cy.customMount() @@ -36,7 +42,15 @@ describe('DatasetCitation', () => { it('shows the deaccessioned tooltip when version is deaccessioned', () => { const dataset = DatasetMother.create({ - version: new DatasetVersion(1, DatasetPublishingStatus.DEACCESSIONED, 1, 0) + version: new DatasetVersion( + 1, + DatasetPublishingStatus.DEACCESSIONED, + true, + false, + DatasetPublishingStatus.DEACCESSIONED, + 1, + 0 + ) }) cy.customMount() diff --git a/tests/component/sections/dataset/dataset-files/dataset-upload-files-button/DatasetUploadFilesButton.spec.tsx b/tests/component/sections/dataset/dataset-files/dataset-upload-files-button/DatasetUploadFilesButton.spec.tsx index be60e0283..24c3ff587 100644 --- a/tests/component/sections/dataset/dataset-files/dataset-upload-files-button/DatasetUploadFilesButton.spec.tsx +++ b/tests/component/sections/dataset/dataset-files/dataset-upload-files-button/DatasetUploadFilesButton.spec.tsx @@ -1,38 +1,59 @@ import { DatasetUploadFilesButton } from '../../../../../../src/sections/dataset/dataset-files/dataset-upload-files-button/DatasetUploadFilesButton' -import { UserMother } from '../../../../users/domain/models/UserMother' -import { UserRepository } from '../../../../../../src/users/domain/repositories/UserRepository' -import { SessionProvider } from '../../../../../../src/sections/session/SessionProvider' - -const user = UserMother.create() -const userRepository = {} as UserRepository +import { ReactNode } from 'react' +import { DatasetProvider } from '../../../../../../src/sections/dataset/DatasetProvider' +import { + DatasetLockMother, + DatasetMother, + DatasetPermissionsMother +} from '../../../../dataset/domain/models/DatasetMother' +import { DatasetRepository } from '../../../../../../src/dataset/domain/repositories/DatasetRepository' +import { Dataset as DatasetModel } from '../../../../../../src/dataset/domain/models/Dataset' + +const datasetRepository: DatasetRepository = {} as DatasetRepository +const datasetWithUpdatePermissions = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithUpdateDatasetAllowed() +}) describe('DatasetUploadFilesButton', () => { - beforeEach(() => { - userRepository.getAuthenticated = cy.stub().resolves(user) - userRepository.removeAuthenticated = cy.stub().resolves() - }) + const withDataset = (component: ReactNode, dataset: DatasetModel | undefined) => { + datasetRepository.getByPersistentId = cy.stub().resolves(dataset) + datasetRepository.getByPrivateUrlToken = cy.stub().resolves(dataset) + + return ( + + {component} + + ) + } it('renders the upload files button', () => { - cy.customMount( - - - - ) + cy.mountAuthenticated(withDataset(, datasetWithUpdatePermissions)) cy.findByRole('button', { name: 'Upload Files' }).should('exist') }) it('does not render the upload files button when user is not logged in', () => { - cy.customMount() + cy.customMount(withDataset(, datasetWithUpdatePermissions)) cy.findByRole('button', { name: 'Upload Files' }).should('not.exist') }) - it.skip('does not render the upload files button when user do not have dataset update permissions', () => { - // TODO - Implement permissions + it('does not render the upload files button when user do not have dataset update permissions', () => { + cy.mountAuthenticated() + + cy.findByRole('button', { name: 'Upload Files' }).should('not.exist') }) - it.skip('renders the button disabled when dataset is locked from edits', () => { - // TODO - Ask Guillermo if this a dataset property coming from the api + it('renders the button disabled when dataset is locked from edits', () => { + const datasetWithUpdatePermissions = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithUpdateDatasetAllowed(), + locks: [DatasetLockMother.createLockedInEditInProgress()] + }) + + cy.mountAuthenticated(withDataset(, datasetWithUpdatePermissions)) + + cy.findByRole('button', { name: 'Upload Files' }).should('exist').should('be.disabled') }) it.skip('calls upload files use case when button is clicked', () => { diff --git a/tests/component/sections/dataset/dataset-files/file-criteria-form/FileCriteriaForm.spec.tsx b/tests/component/sections/dataset/dataset-files/file-criteria-form/FileCriteriaForm.spec.tsx index 6cf8aa96a..bd0fb0294 100644 --- a/tests/component/sections/dataset/dataset-files/file-criteria-form/FileCriteriaForm.spec.tsx +++ b/tests/component/sections/dataset/dataset-files/file-criteria-form/FileCriteriaForm.spec.tsx @@ -7,9 +7,12 @@ import { } from '../../../../../../src/files/domain/models/FileCriteria' import { FilesCountInfoMother } from '../../../../files/domain/models/FilesCountInfoMother' import { FileType } from '../../../../../../src/files/domain/models/File' -import { UserMother } from '../../../../users/domain/models/UserMother' -import { UserRepository } from '../../../../../../src/users/domain/repositories/UserRepository' -import { SessionProvider } from '../../../../../../src/sections/session/SessionProvider' +import { DatasetRepository } from '../../../../../../src/dataset/domain/repositories/DatasetRepository' +import { + DatasetMother, + DatasetPermissionsMother +} from '../../../../dataset/domain/models/DatasetMother' +import { DatasetProvider } from '../../../../../../src/sections/dataset/DatasetProvider' let onCriteriaChange = () => {} const filesCountInfo = FilesCountInfoMother.create({ @@ -242,19 +245,23 @@ describe('FileCriteriaForm', () => { }) it('renders the Upload Files button', () => { - const user = UserMother.create() - const userRepository = {} as UserRepository - userRepository.getAuthenticated = cy.stub().resolves(user) - userRepository.removeAuthenticated = cy.stub().resolves() - - cy.customMount( - + const datasetRepository: DatasetRepository = {} as DatasetRepository + const datasetWithUpdatePermissions = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithUpdateDatasetAllowed() + }) + datasetRepository.getByPersistentId = cy.stub().resolves(datasetWithUpdatePermissions) + datasetRepository.getByPrivateUrlToken = cy.stub().resolves(datasetWithUpdatePermissions) + + cy.mountAuthenticated( + - + ) cy.findByRole('button', { name: 'Upload Files' }).should('exist') diff --git a/tests/component/sections/dataset/dataset-files/files-table/FilesTable.spec.tsx b/tests/component/sections/dataset/dataset-files/files-table/FilesTable.spec.tsx index 41ef01068..620b3c887 100644 --- a/tests/component/sections/dataset/dataset-files/files-table/FilesTable.spec.tsx +++ b/tests/component/sections/dataset/dataset-files/files-table/FilesTable.spec.tsx @@ -56,7 +56,7 @@ describe('FilesTable', () => { cy.findByRole('button', { name: 'Select all 200 files in this dataset.' }).should('exist') }) - it.only('clears row selection for the current page when the header checkbox is clicked', () => { + it('clears row selection for the current page when the header checkbox is clicked', () => { cy.customMount( ) diff --git a/tests/component/sections/dataset/dataset-files/files-table/file-actions/FileActionsHeader.spec.tsx b/tests/component/sections/dataset/dataset-files/files-table/file-actions/FileActionsHeader.spec.tsx index 335b16c43..acb8f6f79 100644 --- a/tests/component/sections/dataset/dataset-files/files-table/file-actions/FileActionsHeader.spec.tsx +++ b/tests/component/sections/dataset/dataset-files/files-table/file-actions/FileActionsHeader.spec.tsx @@ -1,33 +1,27 @@ import { FileActionsHeader } from '../../../../../../../src/sections/dataset/dataset-files/files-table/file-actions/FileActionsHeader' -import { UserMother } from '../../../../../users/domain/models/UserMother' -import { UserRepository } from '../../../../../../../src/users/domain/repositories/UserRepository' -import { SessionProvider } from '../../../../../../../src/sections/session/SessionProvider' import { FileMother } from '../../../../../files/domain/models/FileMother' -import { FileRepository } from '../../../../../../../src/files/domain/repositories/FileRepository' -import { FileUserPermissionsMother } from '../../../../../files/domain/models/FileUserPermissionsMother' -import { FilePermissionsProvider } from '../../../../../../../src/sections/file/file-permissions/FilePermissionsProvider' +import { DatasetProvider } from '../../../../../../../src/sections/dataset/DatasetProvider' +import { DatasetRepository } from '../../../../../../../src/dataset/domain/repositories/DatasetRepository' +import { + DatasetMother, + DatasetPermissionsMother +} from '../../../../../dataset/domain/models/DatasetMother' describe('FileActionsHeader', () => { it('renders the file actions header', () => { - const user = UserMother.create() - const userRepository = {} as UserRepository - userRepository.getAuthenticated = cy.stub().resolves(user) - userRepository.removeAuthenticated = cy.stub().resolves() + const datasetRepository: DatasetRepository = {} as DatasetRepository + const datasetWithUpdatePermissions = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithUpdateDatasetAllowed(), + hasValidTermsOfAccess: true + }) + datasetRepository.getByPersistentId = cy.stub().resolves(datasetWithUpdatePermissions) const files = FileMother.createMany(2) - const fileRepository: FileRepository = {} as FileRepository - fileRepository.getUserPermissionsById = cy.stub().resolves( - FileUserPermissionsMother.create({ - fileId: files[0].id, - canEditDataset: true - }) - ) - - cy.customMount( - - - - - + cy.mountAuthenticated( + + + ) cy.findByRole('button', { name: 'Edit Files' }).should('exist') diff --git a/tests/component/sections/dataset/dataset-files/files-table/file-actions/edit-files-menu/EditFilesMenu.spec.tsx b/tests/component/sections/dataset/dataset-files/files-table/file-actions/edit-files-menu/EditFilesMenu.spec.tsx index db841720a..eaa400bd2 100644 --- a/tests/component/sections/dataset/dataset-files/files-table/file-actions/edit-files-menu/EditFilesMenu.spec.tsx +++ b/tests/component/sections/dataset/dataset-files/files-table/file-actions/edit-files-menu/EditFilesMenu.spec.tsx @@ -1,102 +1,99 @@ import { EditFilesMenu } from '../../../../../../../../src/sections/dataset/dataset-files/files-table/file-actions/edit-files-menu/EditFilesMenu' -import { UserMother } from '../../../../../../users/domain/models/UserMother' -import { UserRepository } from '../../../../../../../../src/users/domain/repositories/UserRepository' -import { SessionProvider } from '../../../../../../../../src/sections/session/SessionProvider' import { FileMother } from '../../../../../../files/domain/models/FileMother' -import { FileRepository } from '../../../../../../../../src/files/domain/repositories/FileRepository' -import { FileUserPermissionsMother } from '../../../../../../files/domain/models/FileUserPermissionsMother' -import { FilePermissionsProvider } from '../../../../../../../../src/sections/file/file-permissions/FilePermissionsProvider' +import { ReactNode } from 'react' +import { Dataset as DatasetModel } from '../../../../../../../../src/dataset/domain/models/Dataset' +import { DatasetProvider } from '../../../../../../../../src/sections/dataset/DatasetProvider' +import { DatasetRepository } from '../../../../../../../../src/dataset/domain/repositories/DatasetRepository' +import { + DatasetLockMother, + DatasetMother, + DatasetPermissionsMother +} from '../../../../../../dataset/domain/models/DatasetMother' -const user = UserMother.create() -const userRepository = {} as UserRepository +const datasetRepository: DatasetRepository = {} as DatasetRepository +const datasetWithUpdatePermissions = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithUpdateDatasetAllowed(), + hasValidTermsOfAccess: true +}) const files = FileMother.createMany(2) -const fileRepository: FileRepository = {} as FileRepository describe('EditFilesMenu', () => { - beforeEach(() => { - userRepository.getAuthenticated = cy.stub().resolves(user) - userRepository.removeAuthenticated = cy.stub().resolves() - fileRepository.getUserPermissionsById = cy.stub().resolves( - FileUserPermissionsMother.create({ - fileId: files[0].id, - canEditDataset: true - }) + const withDataset = (component: ReactNode, dataset: DatasetModel | undefined) => { + datasetRepository.getByPersistentId = cy.stub().resolves(dataset) + datasetRepository.getByPrivateUrlToken = cy.stub().resolves(dataset) + + return ( + + {component} + ) - }) + } + it('renders the Edit Files menu', () => { - cy.customMount( - - - - - + cy.mountAuthenticated( + withDataset(, datasetWithUpdatePermissions) ) cy.findByRole('button', { name: 'Edit Files' }).should('exist') }) it('does not render the Edit Files menu when the user is not authenticated', () => { - userRepository.getAuthenticated = cy.stub().resolves(null) - - cy.customMount( - - - - - - ) + cy.customMount(withDataset(, datasetWithUpdatePermissions)) cy.findByRole('button', { name: 'Edit Files' }).should('not.exist') }) it('does not render the Edit Files menu when there are no files in the dataset', () => { - cy.customMount( - - - - - - ) + cy.mountAuthenticated(withDataset(, datasetWithUpdatePermissions)) cy.findByRole('button', { name: 'Edit Files' }).should('not.exist') }) it('renders the Edit Files options', () => { - cy.customMount( - - - - - + cy.mountAuthenticated( + withDataset(, datasetWithUpdatePermissions) ) cy.findByRole('button', { name: 'Edit Files' }).click() cy.findByRole('button', { name: 'Metadata' }).should('exist') }) - it.skip('does not render the Edit Files menu when the user does not have update dataset permissions', () => { - fileRepository.getUserPermissionsById = cy.stub().resolves( - FileUserPermissionsMother.create({ - fileId: files[0].id, - canEditDataset: false - }) - ) + it('does not render the Edit Files menu when the user does not have update dataset permissions', () => { + const datasetWithNoUpdatePermissions = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithUpdateDatasetNotAllowed() + }) - cy.customMount( - - - - - + cy.mountAuthenticated( + withDataset(, datasetWithNoUpdatePermissions) ) cy.findByRole('button', { name: 'Edit Files' }).should('not.exist') }) - it.skip('renders the disabled Edit Files menu when the dataset is locked from edits', () => { - // TODO: Implement this test + it('renders the disabled Edit Files menu when the dataset is locked from edits', () => { + const datasetWithUpdatePermissions = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithUpdateDatasetAllowed(), + locks: [DatasetLockMother.createLockedInEditInProgress()] + }) + + cy.mountAuthenticated( + withDataset(, datasetWithUpdatePermissions) + ) + + cy.findByRole('button', { name: 'Edit Files' }).should('be.disabled') }) - it.skip('renders the disabled Edit Files menu when the dataset does not have valid terms of access', () => { - // TODO: Implement this test + it('renders the disabled Edit Files menu when the dataset does not have valid terms of access', () => { + const datasetWithUpdatePermissions = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithUpdateDatasetAllowed(), + hasValidTermsOfAccess: false + }) + + cy.mountAuthenticated( + withDataset(, datasetWithUpdatePermissions) + ) + + cy.findByRole('button', { name: 'Edit Files' }).should('be.disabled') }) }) diff --git a/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/FileActionButtons.spec.tsx b/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/FileActionButtons.spec.tsx index 3451e1151..bef0f5345 100644 --- a/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/FileActionButtons.spec.tsx +++ b/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/FileActionButtons.spec.tsx @@ -1,11 +1,11 @@ import { FileActionButtons } from '../../../../../../../../../src/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/FileActionButtons' import { FileMother } from '../../../../../../../files/domain/models/FileMother' -import { UserMother } from '../../../../../../../users/domain/models/UserMother' -import { UserRepository } from '../../../../../../../../../src/users/domain/repositories/UserRepository' -import { SessionProvider } from '../../../../../../../../../src/sections/session/SessionProvider' -import { FileRepository } from '../../../../../../../../../src/files/domain/repositories/FileRepository' -import { FileUserPermissionsMother } from '../../../../../../../files/domain/models/FileUserPermissionsMother' -import { FilePermissionsProvider } from '../../../../../../../../../src/sections/file/file-permissions/FilePermissionsProvider' +import { DatasetRepository } from '../../../../../../../../../src/dataset/domain/repositories/DatasetRepository' +import { + DatasetMother, + DatasetPermissionsMother +} from '../../../../../../../dataset/domain/models/DatasetMother' +import { DatasetProvider } from '../../../../../../../../../src/sections/dataset/DatasetProvider' const file = FileMother.createDefault() describe('FileActionButtons', () => { @@ -17,24 +17,20 @@ describe('FileActionButtons', () => { }) it('renders the file action buttons with user logged in and edit dataset permissions', () => { - const user = UserMother.create() - const userRepository = {} as UserRepository - userRepository.getAuthenticated = cy.stub().resolves(user) - userRepository.removeAuthenticated = cy.stub().resolves() - const fileRepository: FileRepository = {} as FileRepository - fileRepository.getUserPermissionsById = cy.stub().resolves( - FileUserPermissionsMother.create({ - fileId: file.id, - canEditDataset: true - }) - ) + const datasetRepository: DatasetRepository = {} as DatasetRepository + const datasetWithUpdatePermissions = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithUpdateDatasetAllowed(), + hasValidTermsOfAccess: true + }) + datasetRepository.getByPersistentId = cy.stub().resolves(datasetWithUpdatePermissions) + datasetRepository.getByPrivateUrlToken = cy.stub().resolves(datasetWithUpdatePermissions) - cy.customMount( - - - - - + cy.mountAuthenticated( + + + ) cy.findByRole('group', { name: 'File Action Buttons' }).should('exist') diff --git a/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/file-options-menu/FileOptionsMenu.spec.tsx b/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/file-options-menu/FileOptionsMenu.spec.tsx index efcac3355..e39c6dafb 100644 --- a/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/file-options-menu/FileOptionsMenu.spec.tsx +++ b/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/file-options-menu/FileOptionsMenu.spec.tsx @@ -1,46 +1,45 @@ import { FileOptionsMenu } from '../../../../../../../../../../src/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/file-options-menu/FileOptionsMenu' import { FileMother } from '../../../../../../../../files/domain/models/FileMother' -import { UserMother } from '../../../../../../../../users/domain/models/UserMother' -import { UserRepository } from '../../../../../../../../../../src/users/domain/repositories/UserRepository' -import { SessionProvider } from '../../../../../../../../../../src/sections/session/SessionProvider' -import { FileRepository } from '../../../../../../../../../../src/files/domain/repositories/FileRepository' -import { FileUserPermissionsMother } from '../../../../../../../../files/domain/models/FileUserPermissionsMother' -import { FilePermissionsProvider } from '../../../../../../../../../../src/sections/file/file-permissions/FilePermissionsProvider' +import { ReactNode } from 'react' +import { Dataset as DatasetModel } from '../../../../../../../../../../src/dataset/domain/models/Dataset' +import { DatasetProvider } from '../../../../../../../../../../src/sections/dataset/DatasetProvider' +import { DatasetRepository } from '../../../../../../../../../../src/dataset/domain/repositories/DatasetRepository' +import { + DatasetLockMother, + DatasetMother, + DatasetPermissionsMother +} from '../../../../../../../../dataset/domain/models/DatasetMother' const file = FileMother.createDefault() -const user = UserMother.create() -const userRepository = {} as UserRepository -const fileRepository: FileRepository = {} as FileRepository +const datasetRepository: DatasetRepository = {} as DatasetRepository +const datasetWithUpdatePermissions = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithUpdateDatasetAllowed(), + hasValidTermsOfAccess: true +}) describe('FileOptionsMenu', () => { - beforeEach(() => { - userRepository.getAuthenticated = cy.stub().resolves(user) - userRepository.removeAuthenticated = cy.stub().resolves() - fileRepository.getUserPermissionsById = cy.stub().resolves( - FileUserPermissionsMother.create({ - fileId: file.id, - canEditDataset: true - }) + const withDataset = (component: ReactNode, dataset: DatasetModel | undefined) => { + datasetRepository.getByPersistentId = cy.stub().resolves(dataset) + datasetRepository.getByPrivateUrlToken = cy.stub().resolves(dataset) + + return ( + + {component} + ) - }) + } it('renders the FileOptionsMenu', () => { - cy.customMount( - - - - - + cy.mountAuthenticated( + withDataset(, datasetWithUpdatePermissions) ) cy.findByRole('button', { name: 'File Options' }).should('exist') }) it('renders the file options menu with tooltip', () => { - cy.customMount( - - - - - + cy.mountAuthenticated( + withDataset(, datasetWithUpdatePermissions) ) cy.findByRole('button', { name: 'File Options' }).trigger('mouseover') @@ -48,12 +47,8 @@ describe('FileOptionsMenu', () => { }) it('renders the dropdown header', () => { - cy.customMount( - - - - - + cy.mountAuthenticated( + withDataset(, datasetWithUpdatePermissions) ) cy.findByRole('button', { name: 'File Options' }).should('exist').click() @@ -61,52 +56,45 @@ describe('FileOptionsMenu', () => { }) it('does not render is the user is not authenticated', () => { - cy.customMount( - - - - ) + cy.customMount(withDataset(, datasetWithUpdatePermissions)) cy.findByRole('button', { name: 'File Options' }).should('not.exist') }) it('does not render is the user do not have permissions to update the dataset', () => { - fileRepository.getUserPermissionsById = cy.stub().resolves( - FileUserPermissionsMother.create({ - fileId: file.id, - canEditDataset: false - }) - ) - cy.customMount( - - - - - + const datasetWithNoUpdatePermissions = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithUpdateDatasetNotAllowed() + }) + cy.mountAuthenticated( + withDataset(, datasetWithNoUpdatePermissions) ) cy.findByRole('button', { name: 'File Options' }).should('not.exist') }) - it.skip('does not render if there are not valid terms of access', () => { - // TODO: Implement this test + it('does not render if there are not valid terms of access', () => { + const datasetWithNoTermsOfAccess = DatasetMother.create({ + hasValidTermsOfAccess: false + }) + cy.mountAuthenticated(withDataset(, datasetWithNoTermsOfAccess)) + cy.findByRole('button', { name: 'File Options' }).should('not.exist') }) - it.skip('renders disabled menu if dataset is locked from edits', () => { - // TODO: Implement this test + it('renders disabled menu if dataset is locked from edits', () => { + const datasetLockedFromEdits = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithUpdateDatasetAllowed(), + locks: [DatasetLockMother.createLockedInEditInProgress()], + hasValidTermsOfAccess: true + }) + cy.mountAuthenticated(withDataset(, datasetLockedFromEdits)) + + cy.findByRole('button', { name: 'File Options' }).should('exist').should('be.disabled') }) it('opens fileAlreadyDeletedPrevious modal if file is already deleted', () => { - userRepository.getAuthenticated = cy.stub().resolves(user) - userRepository.removeAuthenticated = cy.stub().resolves() - const file = FileMother.createDeleted() - cy.customMount( - - - - - + cy.mountAuthenticated( + withDataset(, datasetWithUpdatePermissions) ) cy.findByRole('button', { name: 'File Options' }).should('exist').click() @@ -118,14 +106,9 @@ describe('FileOptionsMenu', () => { }) it('renders the menu options', () => { - cy.customMount( - - - - - + cy.mountAuthenticated( + withDataset(, datasetWithUpdatePermissions) ) - cy.findByRole('button', { name: 'File Options' }).click() cy.findByRole('button', { name: 'Metadata' }).should('exist') }) diff --git a/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-info-messages/IngestInfoMessage.spec.tsx b/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-info-messages/IngestInfoMessage.spec.tsx index 30506db98..ada6d3be3 100644 --- a/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-info-messages/IngestInfoMessage.spec.tsx +++ b/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-info-messages/IngestInfoMessage.spec.tsx @@ -1,7 +1,32 @@ import { IngestInfoMessage } from '../../../../../../../../../src/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-info-messages/IngestInfoMessage' import { FileIngestMother } from '../../../../../../../files/domain/models/FileMother' +import { ReactNode } from 'react' +import { Dataset as DatasetModel } from '../../../../../../../../../src/dataset/domain/models/Dataset' +import { DatasetProvider } from '../../../../../../../../../src/sections/dataset/DatasetProvider' +import { DatasetRepository } from '../../../../../../../../../src/dataset/domain/repositories/DatasetRepository' +import { + DatasetMother, + DatasetPermissionsMother +} from '../../../../../../../dataset/domain/models/DatasetMother' +const datasetRepository: DatasetRepository = {} as DatasetRepository +const datasetWithUpdatePermissions = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithUpdateDatasetAllowed() +}) describe('IngestInfoMessage', () => { + const withDataset = (component: ReactNode, dataset: DatasetModel | undefined) => { + datasetRepository.getByPersistentId = cy.stub().resolves(dataset) + datasetRepository.getByPrivateUrlToken = cy.stub().resolves(dataset) + + return ( + + {component} + + ) + } + it('renders the ingest in progress message', () => { cy.customMount() @@ -11,9 +36,12 @@ describe('IngestInfoMessage', () => { it('renders the ingest problem when there is an error and the user has update dataset permissions with no report message ', () => { cy.customMount( -
- -
+ withDataset( +
+ +
, + datasetWithUpdatePermissions + ) ) cy.findByText('Ingest in progress...').should('not.exist') @@ -29,9 +57,12 @@ describe('IngestInfoMessage', () => { it('renders the ingest problem when there is an error and the user has update dataset permissions with a report message', () => { cy.customMount( -
- -
+ withDataset( +
+ +
, + datasetWithUpdatePermissions + ) ) cy.findByText('Ingest in progress...').should('not.exist') @@ -42,4 +73,35 @@ describe('IngestInfoMessage', () => { cy.findByRole('link', { name: 'Tabular ingest' }).should('exist') cy.findByText(/was unsuccessful. Some message./).should('exist') }) + + it('does not render the ingest problem when there is an error and the user does not have update dataset permissions', () => { + const datasetWithoutUpdatePermissions = DatasetMother.create({ + permissions: DatasetPermissionsMother.createWithUpdateDatasetNotAllowed() + }) + cy.customMount( + withDataset( +
+ +
, + datasetWithoutUpdatePermissions + ) + ) + + cy.findByText('Ingest in progress...').should('not.exist') + cy.findByText('File available in original format only').should('not.exist') + }) + + it('does not render any message when there is no ingest status', () => { + cy.customMount( + withDataset( +
+ +
, + datasetWithUpdatePermissions + ) + ) + + cy.findByText('Ingest in progress...').should('not.exist') + cy.findByText('File available in original format only').should('not.exist') + }) }) diff --git a/tests/component/sections/file/file-permissions/useFileEditDatasetPermission.spec.tsx b/tests/component/sections/file/file-permissions/useFileEditDatasetPermission.spec.tsx deleted file mode 100644 index cebdd7865..000000000 --- a/tests/component/sections/file/file-permissions/useFileEditDatasetPermission.spec.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import { FileMother } from '../../../files/domain/models/FileMother' -import { FilePermissionsProvider } from '../../../../../src/sections/file/file-permissions/FilePermissionsProvider' -import { FileRepository } from '../../../../../src/files/domain/repositories/FileRepository' -import { File } from '../../../../../src/files/domain/models/File' -import { FileUserPermissionsMother } from '../../../files/domain/models/FileUserPermissionsMother' -import { FilesCountInfoMother } from '../../../files/domain/models/FilesCountInfoMother' -import { useFileEditDatasetPermission } from '../../../../../src/sections/file/file-permissions/useFileEditDatasetPermission' - -const fileRepository: FileRepository = {} as FileRepository -function TestComponent({ file }: { file: File }) { - const { sessionUserHasEditDatasetPermission } = useFileEditDatasetPermission(file) - - return ( -
- {sessionUserHasEditDatasetPermission ? ( - Has edit dataset permission - ) : ( - Does not have edit dataset permission - )} -
- ) -} - -describe('useFileEditDatasetPermission', () => { - beforeEach(() => { - fileRepository.getAllByDatasetPersistentId = cy.stub().resolves([]) - fileRepository.getFilesCountInfoByDatasetPersistentId = cy - .stub() - .resolves(FilesCountInfoMother.create()) - }) - - it('should return edit dataset permission', () => { - const file = FileMother.createDefault() - fileRepository.getUserPermissionsById = cy - .stub() - .resolves(FileUserPermissionsMother.create({ fileId: file.id, canEditDataset: true })) - - cy.mount( - - - - ) - - cy.wrap(fileRepository.getUserPermissionsById).should('be.calledWith', file.id) - cy.findByText('Has edit dataset permission').should('exist') - }) - - it('should return false for edit dataset permission if there is an error', () => { - const file = FileMother.createDefault() - fileRepository.getUserPermissionsById = cy - .stub() - .rejects(new Error('Error getting file user permissions')) - - cy.mount( - - - - ) - - cy.wrap(fileRepository.getUserPermissionsById).should('be.calledWith', file.id) - cy.findByText('Does not have edit dataset permission').should('exist') - }) -}) diff --git a/tests/component/sections/layout/top-bar-progress-indicator/TopBarProgressIndicator.spec.tsx b/tests/component/sections/layout/top-bar-progress-indicator/TopBarProgressIndicator.spec.tsx index 72eba22d2..9a15b7051 100644 --- a/tests/component/sections/layout/top-bar-progress-indicator/TopBarProgressIndicator.spec.tsx +++ b/tests/component/sections/layout/top-bar-progress-indicator/TopBarProgressIndicator.spec.tsx @@ -5,7 +5,7 @@ describe('TopBarProgressIndicator', () => { it('should render without errors', () => { cy.mount() - cy.get('canvas').should('not.exist') + cy.get('canvas').should('exist') }) it('should render the TopBarProgress when loading is true', () => { diff --git a/tests/component/sections/loading/LoadingProvider.spec.tsx b/tests/component/sections/loading/LoadingProvider.spec.tsx index a47817ebb..189ed9a89 100644 --- a/tests/component/sections/loading/LoadingProvider.spec.tsx +++ b/tests/component/sections/loading/LoadingProvider.spec.tsx @@ -12,13 +12,13 @@ describe('LoadingProvider', () => { cy.findByText('Hello, world!').should('exist') }) - it('should set isLoading to true when setIsLoading is called', () => { + it('should set isLoading to false when setIsLoading is called', () => { const buttonText = 'Toggle Loading' const TestComponent = () => { const { isLoading, setIsLoading } = useLoading() return ( <> - + {isLoading &&
Loading...
} ) @@ -32,10 +32,10 @@ describe('LoadingProvider', () => { cy.findByText(buttonText).should('exist') - cy.findByText('Loading...').should('not.exist') + cy.findByText('Loading...').should('exist') cy.findByText(buttonText).click() - cy.findByText('Loading...').should('exist') + cy.findByText('Loading...').should('not.exist') }) }) diff --git a/tests/component/settings/domain/models/SettingMother.ts b/tests/component/settings/domain/models/SettingMother.ts index 73f9593ee..59574ba60 100644 --- a/tests/component/settings/domain/models/SettingMother.ts +++ b/tests/component/settings/domain/models/SettingMother.ts @@ -15,4 +15,18 @@ export class SettingMother { ) } } + + static createExternalStatusesAllowed(value?: string[]): Setting { + return { + name: SettingName.ALLOWED_EXTERNAL_STATUSES, + value: value ? value : [faker.datatype.string(), faker.datatype.string()] + } + } + + static createHasPublicStore(value?: boolean): Setting { + return { + name: SettingName.HAS_PUBLIC_STORE, + value: value ? value : faker.datatype.boolean() + } + } } diff --git a/tests/e2e-integration/e2e/sections/dataset/Dataset.spec.tsx b/tests/e2e-integration/e2e/sections/dataset/Dataset.spec.tsx index 1dadda464..30d80621a 100644 --- a/tests/e2e-integration/e2e/sections/dataset/Dataset.spec.tsx +++ b/tests/e2e-integration/e2e/sections/dataset/Dataset.spec.tsx @@ -28,7 +28,7 @@ describe('Dataset', () => { name: dataset.datasetVersion.metadataBlocks.citation.fields[0].value }).should('exist') cy.findByText(DatasetLabelValue.DRAFT).should('exist') - cy.findByText(DatasetLabelValue.UNPUBLISHED).should('exist') + // cy.findByText(DatasetLabelValue.UNPUBLISHED).should('exist') TODO - Implemnent isReleased property in js-dataverse to get the Unpublished label cy.findByText('Metadata').should('exist') cy.findByText('Files').should('exist') @@ -59,7 +59,7 @@ describe('Dataset', () => { name: dataset.datasetVersion.metadataBlocks.citation.fields[0].value }).should('exist') cy.findByText(DatasetLabelValue.DRAFT).should('not.exist') - cy.findByText(DatasetLabelValue.UNPUBLISHED).should('not.exist') + // cy.findByText(DatasetLabelValue.UNPUBLISHED).should('not.exist') TODO - Implemnent isReleased property in js-dataverse to get the Unpublished label cy.findByText('Version 1.0').should('exist') }) }) @@ -99,7 +99,7 @@ describe('Dataset', () => { name: dataset.datasetVersion.metadataBlocks.citation.fields[0].value }).should('exist') cy.findByText(DatasetLabelValue.DRAFT).should('exist') - cy.findByText(DatasetLabelValue.UNPUBLISHED).should('exist') + // cy.findByText(DatasetLabelValue.UNPUBLISHED).should('exist') TODO - Implemnent isReleased property in js-dataverse to get the Unpublished label }) }) }) @@ -119,7 +119,7 @@ describe('Dataset', () => { name: dataset.datasetVersion.metadataBlocks.citation.fields[0].value }).should('exist') cy.findByText(DatasetLabelValue.DRAFT).should('exist') - cy.findByText(DatasetLabelValue.UNPUBLISHED).should('exist') + // cy.findByText(DatasetLabelValue.UNPUBLISHED).should('exist') TODO - Implemnent isReleased property in js-dataverse to get the Unpublished label cy.findAllByText('withheld').should('exist') }) @@ -132,7 +132,7 @@ describe('Dataset', () => { }) describe('Visualizing the Files Tab', () => { - it.only('successfully loads the files tab', () => { + it('successfully loads the files tab', () => { cy.wrap(DatasetHelper.create()) .its('persistentId') .then((persistentId: string) => { @@ -160,7 +160,7 @@ describe('Dataset', () => { }) it('navigates to the next page of files', () => { - cy.wrap(DatasetHelper.createWithFiles(FileHelper.createMany(30)), { timeout: 10000 }) + cy.wrap(DatasetHelper.createWithFiles(FileHelper.createMany(30)), { timeout: 20000 }) .its('persistentId') .then((persistentId: string) => { cy.visit(`/spa/datasets?persistentId=${persistentId}`) @@ -258,6 +258,8 @@ describe('Dataset', () => { cy.visit(`/spa/datasets?persistentId=${persistentId}`) + cy.wait(1500) // Wait for the files to be loaded + cy.findByText('Files').should('exist') cy.findByText('Restricted with access Icon').should('not.exist') @@ -284,11 +286,15 @@ describe('Dataset', () => { cy.visit(`/spa/datasets?persistentId=${persistentId}`) + cy.wait(1500) // Wait for the files to be loaded + cy.findByText('Files').should('exist') cy.findByText(/Deposited/).should('exist') cy.findByText('Draft: will be embargoed until Oct 20, 2100').should('exist') + cy.findByText('Edit Files').should('exist') + cy.findByRole('button', { name: 'Access File' }).should('exist').click() cy.findByText('Embargoed').should('exist') }) diff --git a/tests/e2e-integration/integration/datasets/DatasetJSDataverseRepository.spec.ts b/tests/e2e-integration/integration/datasets/DatasetJSDataverseRepository.spec.ts index a548c5e4b..480456aeb 100644 --- a/tests/e2e-integration/integration/datasets/DatasetJSDataverseRepository.spec.ts +++ b/tests/e2e-integration/integration/datasets/DatasetJSDataverseRepository.spec.ts @@ -75,7 +75,10 @@ const datasetData = (persistentId: string, versionId: number) => { id: versionId, majorNumber: undefined, minorNumber: undefined, - publishingStatus: 'draft' + publishingStatus: 'draft', + latestVersionStatus: 'draft', + isLatest: true, + isInReview: false } } } @@ -96,7 +99,7 @@ describe('Dataset JSDataverse Repository', () => { expect(dataset.getTitle()).to.deep.equal(datasetExpected.title) expect(dataset.citation).to.deep.equal(datasetExpected.citation) - expect(dataset.labels).to.deep.equal(datasetExpected.labels) + // expect(dataset.labels).to.deep.equal(datasetExpected.labels) TODO - Implemnent isReleased property in js-dataverse to get the Unpublished label expect(dataset.license).to.deep.equal(datasetExpected.license) expect(dataset.metadataBlocks).to.deep.equal(datasetExpected.metadataBlocks) expect(dataset.summaryFields).to.deep.equal(datasetExpected.summaryFields) @@ -122,6 +125,9 @@ describe('Dataset JSDataverse Repository', () => { const newVersion = new DatasetVersion( dataset.version.id, DatasetPublishingStatus.RELEASED, + true, + false, + DatasetPublishingStatus.RELEASED, 1, 0 ) diff --git a/tests/e2e-integration/integration/files/FileJSDataverseRepository.spec.ts b/tests/e2e-integration/integration/files/FileJSDataverseRepository.spec.ts index 844b61ed1..18f6c842f 100644 --- a/tests/e2e-integration/integration/files/FileJSDataverseRepository.spec.ts +++ b/tests/e2e-integration/integration/files/FileJSDataverseRepository.spec.ts @@ -134,7 +134,15 @@ describe('File JSDataverse Repository', () => { await fileRepository .getAllByDatasetPersistentId( dataset.persistentId, - new DatasetVersion(dataset.version.id, DatasetPublishingStatus.RELEASED, 1, 0) + new DatasetVersion( + dataset.version.id, + DatasetPublishingStatus.RELEASED, + true, + false, + DatasetPublishingStatus.RELEASED, + 1, + 0 + ) ) .then((files) => { const expectedPublishedFile = expectedFile @@ -166,7 +174,15 @@ describe('File JSDataverse Repository', () => { await fileRepository .getAllByDatasetPersistentId( dataset.persistentId, - new DatasetVersion(dataset.version.id, DatasetPublishingStatus.DEACCESSIONED, 1, 0) + new DatasetVersion( + dataset.version.id, + DatasetPublishingStatus.DEACCESSIONED, + true, + false, + DatasetPublishingStatus.DEACCESSIONED, + 1, + 0 + ) ) .then((files) => { const expectedDeaccessionedFile = expectedFile @@ -474,11 +490,11 @@ describe('File JSDataverse Repository', () => { total: 6, perAccess: [ { - access: FileAccessOption.PUBLIC, + access: FileAccessOption.RESTRICTED, count: 3 }, { - access: FileAccessOption.RESTRICTED, + access: FileAccessOption.PUBLIC, count: 3 } ], diff --git a/tests/support/commands.tsx b/tests/support/commands.tsx index c0da8c8fd..7ea7bcc74 100644 --- a/tests/support/commands.tsx +++ b/tests/support/commands.tsx @@ -1,3 +1,5 @@ +import { UserMother } from '../component/users/domain/models/UserMother' + export {} /// // *********************************************** @@ -41,6 +43,8 @@ import { ThemeProvider } from '@iqss/dataverse-design-system' import { ReactNode } from 'react' import { I18nextProvider } from 'react-i18next' import i18next from '../../src/i18n' +import { UserRepository } from '../../src/users/domain/repositories/UserRepository' +import { SessionProvider } from '../../src/sections/session/SessionProvider' // Define your custom mount function @@ -52,6 +56,15 @@ Cypress.Commands.add('customMount', (component: ReactNode) => { ) }) +Cypress.Commands.add('mountAuthenticated', (component: ReactNode) => { + const user = UserMother.create() + const userRepository = {} as UserRepository + userRepository.getAuthenticated = cy.stub().resolves(user) + userRepository.removeAuthenticated = cy.stub().resolves() + + return cy.customMount({component}) +}) + Cypress.Commands.add('loginAsAdmin', (go?: string) => { cy.visit('/') cy.get('#topNavBar').then((navbar) => { diff --git a/tests/support/component.ts b/tests/support/component.ts index a2a7d1b06..e366de486 100644 --- a/tests/support/component.ts +++ b/tests/support/component.ts @@ -33,6 +33,7 @@ declare global { interface Chainable { mount: typeof mount customMount: typeof mount + mountAuthenticated: typeof mount loginAsAdmin(go?: string): Chainable> getApiToken(): Chainable }