diff --git a/public/locales/en/files.json b/public/locales/en/files.json index 3e8938625..98fc2b0bb 100644 --- a/public/locales/en/files.json +++ b/public/locales/en/files.json @@ -12,6 +12,7 @@ "pageSize": "Files per page" }, "tabularData": { + "name": "Tabular Data", "variables": "Variables", "observations": "Observations" }, @@ -112,6 +113,14 @@ "title": "Access File", "headers": { "fileAccess": "File Access" + }, + "downloadOptions": { + "title": "Download Options", + "options": { + "original": "Original File Format", + "RData": "R Data", + "tabular": "Tab-Delimited" + } } }, "editFilesMenu": { diff --git a/src/dataset/domain/models/Dataset.ts b/src/dataset/domain/models/Dataset.ts index 373bb1b71..0eb6fe534 100644 --- a/src/dataset/domain/models/Dataset.ts +++ b/src/dataset/domain/models/Dataset.ts @@ -315,6 +315,36 @@ export class Dataset { return this.isLocked && !(lockedReasonIsInReview && this.permissions.canPublishDataset) } + public get isLockedFromFileDownload(): boolean { + if (!this.isLocked) { + return false + } + + if ( + this.locks.some((lock) => + [ + DatasetLockReason.FINALIZE_PUBLICATION, + DatasetLockReason.DCM_UPLOAD, + DatasetLockReason.INGEST + ].includes(lock.reason) + ) + ) { + return true + } + + if ( + this.locks.some((lock) => lock.reason === DatasetLockReason.IN_REVIEW) && + !this.permissions.canUpdateDataset + ) { + return true + } + + // If the lock reason is workflow and the workflow userId is different than the current user, then is locked + // TODO - Ask how we want to manage pending workflows + + return false + } + static Builder = class { public readonly labels: DatasetLabel[] = [] public readonly alerts: Alert[] = [] diff --git a/src/files/domain/models/File.ts b/src/files/domain/models/File.ts index d4255cda8..b6f685c75 100644 --- a/src/files/domain/models/File.ts +++ b/src/files/domain/models/File.ts @@ -1,3 +1,5 @@ +import FileTypeToFriendlyTypeMap from './FileTypeToFriendlyTypeMap' + export enum FileSizeUnit { BYTES = 'B', KILOBYTES = 'KB', @@ -119,15 +121,10 @@ export interface FileLabel { } export class FileType { - constructor(readonly value: string) {} + constructor(readonly value: string, readonly original?: string) {} toDisplayFormat(): string { - const words = this.value.split(' ') - return words - .map((word) => { - return word[0].toUpperCase() + word.substring(1) - }) - .join(' ') + return FileTypeToFriendlyTypeMap[this.value] || FileTypeToFriendlyTypeMap.unknown } } diff --git a/src/files/domain/models/FileTypeToFriendlyTypeMap.ts b/src/files/domain/models/FileTypeToFriendlyTypeMap.ts new file mode 100644 index 000000000..6f40517aa --- /dev/null +++ b/src/files/domain/models/FileTypeToFriendlyTypeMap.ts @@ -0,0 +1,228 @@ +const MimeTypeDisplay: Record = { + // Documentation + 'application/pdf': 'Adobe PDF', + 'image/pdf': 'Adobe PDF', + 'text/pdf': 'Adobe PDF', + 'application/x-pdf': 'Adobe PDF', + 'application/cnt': 'Windows Help Contents File', + 'application/msword': 'MS Word', + 'application/vnd.ms-excel': 'MS Excel Spreadsheet', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'MS Excel Spreadsheet', + 'application/vnd.ms-powerpoint': 'MS Powerpoint', + 'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'MS Powerpoint', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'MS Word', + 'application/vnd.oasis.opendocument.spreadsheet': 'OpenOffice Spreadsheet', + 'application/vnd.ms-excel.sheet.macroenabled.12': 'MS Excel Spreadsheet', + // Text + 'text/plain': 'Plain Text', + 'text/x-log': 'Application Log', + 'text/html': 'HTML', + 'application/x-tex': 'LaTeX', + 'text/x-tex': 'LaTeX', + 'text/markdown': 'Markdown Text', + 'text/x-markdown': 'Markdown Text', + 'text/x-r-markdown': 'R Markdown Text', + 'application/rtf': 'Rich Text Format', + 'text/x-rst': 'reStructuredText', + 'text/rtf': 'Rich Text Format', + 'text/richtext': 'Rich Text Format', + 'text/turtle': 'Turtle RDF', + 'application/xml': 'XML', + 'text/xml': 'XML', + // Code + 'text/x-c': 'C++ Source', + 'text/x-c++src': 'C++ Source', + 'text/css': 'Cascading Style Sheet', + 'text/x-fortran': 'Fortran Source Code', + 'application/java-vm': 'Java Class', + 'text/x-java-source': 'Java Source Code', + 'text/javascript': 'Javascript Code', + 'application/javascript': 'Javascript Code', + 'application/x-javascript': 'Javascript Code', + 'text/x-matlab': 'MATLAB Source Code', + 'text/x-mathematica': 'Mathematica Input', + 'text/x-objcsrc': 'Objective-C Source Code', + 'text/x-pascal': 'Pascal Source Code', + 'text/x-perl': 'Perl Script', + 'text/x-perl-script': 'Perl Script', + 'text/php': 'PHP Source Code', + 'application/postscript': 'Postscript', + 'text/x-python': 'Python Source Code', + 'text/x-python-script': 'Python Source Code', + 'text/x-r-source': 'R Source Code', + 'text/x-sh': 'Shell Script', + 'application/x-sh': 'Shell Script', + 'application/x-shellscript': 'Shell Script', + 'application/x-sql': 'SQL Code', + 'text/x-sql': 'SQL Code', + 'application/x-swc': 'Shockwave Flash Component', + 'application/x-msdownload': 'Windows Executable', + 'application/x-ipynb+json': 'Jupyter Notebook', + 'application/x-stata-ado': 'Stata Ado Script', + 'application/x-stata-do': 'Stata Do Script', + 'application/x-stata-dta': 'Stata Data Script', + 'application/x-stata-smcl': 'Stata Markup and Control Language', + 'text/x-stata-syntax': 'Stata Syntax', + 'application/x-stata-syntax': 'Stata Syntax', + 'text/x-spss-syntax': 'SPSS Syntax', + 'application/x-spss-syntax': 'SPSS Syntax', + 'application/x-spss-sps': 'SPSS Script Syntax', + 'text/x-sas-syntax': 'SAS Syntax', + 'application/x-sas-syntax': 'SAS Syntax', + 'type/x-r-syntax': 'R Syntax', + 'application/vnd.wolfram.mathematica.package': 'Wolfram Mathematica Code', + 'application/vnd.wolfram.mathematica': 'Wolfram Mathematica Code', + 'text/x-workflow-description-language': 'Workflow Description Language', + 'text/x-computational-workflow-language': 'Computational Workflow Language', + 'text/x-nextflow': 'Nextflow Script', + 'text/x-r-notebook': 'R Notebook', + 'text/x-ruby-script': 'Ruby Source Code', + 'text/x-dagman': 'DAGMan Workflow', + 'text/x-makefile': 'Makefile Script', + 'text/x-snakemake': 'Snakemake Workflow', + // Ingested Tabular Data + 'text/tab-separated-values': 'Tab-Delimited', + 'text/tsv': 'Tab-Separated Values', + 'text/comma-separated-values': 'Comma Separated Values', + 'text/x-comma-separated-values': 'Comma Separated Values', + 'text/csv': 'Comma Separated Values', + 'text/x-fixed-field': 'Fixed Field Text Data', + 'application/vnd.flographit': 'FloGraphIt Media', + 'application/x-r-data': 'R Data', + 'application/x-rlang-transport': 'R Data', + 'application/x-R-2': 'R Binary', + 'application/x-stata': 'Stata Binary', + 'application/x-stata-6': 'Stata Binary', + 'application/x-stata-13': 'Stata 13 Binary', + 'application/x-stata-14': 'Stata 14 Binary', + 'application/x-stata-15': 'Stata 15 Binary', + 'application/x-spss-por': 'SPSS Portable', + 'application/x-spss-portable': 'SPSS Portable', + 'application/x-spss-sav': 'SPSS Binary', + 'application/x-sas': 'SAS', + 'application/x-sas-transport': 'SAS Transport', + 'application/x-sas-system': 'SAS System', + 'application/x-sas-data': 'SAS Data', + 'application/x-sas-catalog': 'SAS Catalog', + 'application/x-sas-log': 'SAS Log', + 'application/x-sas-output': 'SAS Output', + 'application/softgrid-do': 'Softgrid DTA Script', + 'application/x-dvn-csvspss-zip': 'CSV (w/SPSS card)', + 'application/x-dvn-tabddi-zip': 'TAB (w/DDI)', + 'application/x-emf': 'Extended Metafile', + 'application/x-h5': 'Hierarchical Data Format', + 'application/x-hdf': 'Hierarchical Data Format', + 'application/x-hdf5': 'Hierarchical Data Format', + 'application/geo+json': 'GeoJSON', + 'application/json': 'JSON', + 'application/mathematica': 'Mathematica', + 'application/matlab-mat': 'MATLAB Data', + 'application/x-matlab-data': 'MATLAB Data', + 'application/x-matlab-figure': 'MATLAB Figure', + 'application/x-matlab-workspace': 'MATLAB Workspace', + 'text/x-vcard': 'Virtual Contact File', + 'application/x-xfig': 'MATLAB Figure', + 'application/x-msaccess': 'MS Access', + 'application/netcdf': 'Network Common Data Form', + 'application/x-netcdf': 'Network Common Data Form', + 'application/vnd.lotus-notes': 'Notes Storage Facility', + 'application/x-nsdstat': 'NSDstat', + 'application/vnd.realvnc.bed': 'PLINK Binary', + 'application/vnd.ms-pki.stl': 'STL Format', + 'application/vnd.isac.fcs': 'FCS Data', + 'application/java-serialized-object': 'Java Serialized Object', + 'chemical/x-xyz': 'Co-Ordinate Animation', + // FITS + 'image/fits': 'FITS', + 'application/fits': 'FITS', + // Shape + 'application/dbf': 'dBASE Table for ESRI Shapefile', + 'application/dbase': 'dBASE Table for ESRI Shapefile', + 'application/prj': 'ESRI Shapefile', + 'application/sbn': 'ESRI Spatial Index', + 'application/sbx': 'ESRI Spatial Index', + 'application/shp': 'Shape', + 'application/shx': 'Shape', + 'application/x-esri-shape': 'ESRI Shapefile', + 'application/vnd.google-earth.kml+xml': 'Keyhole Markup Language', + 'application/zipped-shapefile': 'Zipped Shapefiles', + // Archive + 'application/zip': 'ZIP Archive', + 'application/x-zip-compressed': 'ZIP Archive', + 'application/vnd.antix.game-component': 'ATX Archive', + 'application/x-bzip': 'Bzip Archive', + 'application/x-bzip2': 'Bzip Archive', + 'application/vnd.google-earth.kmz': 'Google Earth Archive', + 'application/gzip': 'Gzip Archive', + 'application/x-gzip': 'Gzip Archive', + 'application/x-gzip-compressed': 'Gzip Archive', + 'application/rar': 'RAR Archive', + 'application/x-rar': 'RAR Archive', + 'application/x-rar-compressed': 'RAR Archive', + 'application/tar': 'TAR Archive', + 'application/x-tar': 'TAR Archive', + 'application/x-compressed': 'Compressed Archive', + 'application/x-compressed-tar': 'TAR Archive', + 'application/x-7z-compressed': '7Z Archive', + 'application/x-xz': 'XZ Archive', + 'application/warc': 'Web Archive', + 'application/x-iso9660-image': 'Optical Disc Image', + 'application/vnd.eln+zip': 'ELN Archive', + // Image + 'image/gif': 'GIF Image', + 'image/jpeg': 'JPEG Image', + 'image/jp2': 'JPEG-2000 Image', + 'image/x-portable-bitmap': 'Bitmap Image', + 'image/x-portable-graymap': 'Graymap Image', + 'image/png': 'PNG Image', + 'image/x-portable-anymap': 'Anymap Image', + 'image/x-portable-pixmap': 'Pixmap Image', + 'application/x-msmetafile': 'Enhanced Metafile', + 'application/dicom': 'DICOM Image', + 'image/dicom-rle': 'DICOM Image', + 'image/nii': 'NIfTI Image', + 'image/cmu-raster': 'Raster Image', + 'image/x-rgb': 'RGB Image', + 'image/svg+xml': 'SVG Image', + 'image/tiff': 'TIFF Image', + 'image/bmp': 'Bitmap Image', + 'image/x-xbitmap': 'Bitmap Image', + 'image/RAW': 'Bitmap Image', + 'image/raw': 'Bitmap Image', + 'application/x-tgif': 'TGIF File', + 'image/x-xpixmap': 'Pixmap Image', + 'image/x-xwindowdump': 'X Windows Dump', + 'application/photoshop': 'Photoshop Image', + 'image/vnd.adobe.photoshop': 'Photoshop Image', + 'application/x-photoshop': 'Photoshop Image', + // Audio + 'audio/x-aiff': 'AIFF Audio', + 'audio/mp3': 'MP3 Audio', + 'audio/mpeg': 'MP3 Audio', + 'audio/mp4': 'MPEG-4 Audio', + 'audio/x-m4a': 'MPEG-4 Audio', + 'audio/ogg': 'OGG Audio', + 'audio/wav': 'Waveform Audio', + 'audio/x-wav': 'Waveform Audio', + 'audio/x-wave': 'Waveform Audio', + // Video + 'video/avi': 'AVI Video', + 'video/x-msvideo': 'AVI Video', + 'video/mpeg': 'MPEG Video', + 'video/mp4': 'MPEG-4 Video', + 'video/x-m4v': 'MPEG-4 Video', + 'video/ogg': 'OGG Video', + 'video/quicktime': 'Quicktime Video', + 'video/webm': 'WebM Video', + // Network Data + 'text/xml-graphml': 'GraphML Network Data', + // Other + 'application/octet-stream': 'Unknown', + 'application/x-docker-file': 'Docker Image File', + 'application/x-vagrant-file': 'Vagrant Image File', + // Dataverse-specific + 'application/vnd.dataverse.file-package': 'Dataverse Package', + unknown: 'Unknown' +} + +export default MimeTypeDisplay diff --git a/src/files/infrastructure/mappers/JSFileMapper.ts b/src/files/infrastructure/mappers/JSFileMapper.ts index 316c5019c..3956b6d25 100644 --- a/src/files/infrastructure/mappers/JSFileMapper.ts +++ b/src/files/infrastructure/mappers/JSFileMapper.ts @@ -41,7 +41,7 @@ export class JSFileMapper { this.toFileVersion(jsFile.version, datasetVersion, jsFile.publicationDate), this.toFileName(jsFile.name), this.toFileAccess(jsFile.restricted), - this.toFileType(jsFile.contentType), + this.toFileType(jsFile.contentType, jsFile.originalFormatLabel), this.toFileSize(jsFile.sizeBytes), this.toFileDate(jsFile.creationDate, jsFile.publicationDate, jsFile.embargo), this.toFileDownloads(), @@ -107,8 +107,8 @@ export class JSFileMapper { } } - static toFileType(jsFileContentType: string): FileType { - return new FileType(jsFileContentType) + static toFileType(jsFileContentType: string, jsOriginalFormatLabel?: string): FileType { + return new FileType(jsFileContentType, jsOriginalFormatLabel) } static toFileSize(jsFileSize: number): FileSize { diff --git a/src/sections/dataset/dataset-files/file-criteria-form/FileCriteriaFilterByType.tsx b/src/sections/dataset/dataset-files/file-criteria-form/FileCriteriaFilterByType.tsx index 53f20b7f0..ff1bd0d61 100644 --- a/src/sections/dataset/dataset-files/file-criteria-form/FileCriteriaFilterByType.tsx +++ b/src/sections/dataset/dataset-files/file-criteria-form/FileCriteriaFilterByType.tsx @@ -23,13 +23,13 @@ export function FileCriteriaFilterByType({ }: FileCriteriaFilterByTypeProps) { const { t } = useTranslation('files') const [selectedType, setSelectedType] = useState( - criteria.filterByType ?? new FileType('all') + criteria.filterByType ?? new FileType('All') ) const handleTypeChange = (eventKey: string | null) => { if (selectedType.value !== eventKey) { setSelectedType(new FileType(eventKey as string)) onCriteriaChange( - criteria.withFilterByType(eventKey === 'all' ? undefined : (eventKey as string)) + criteria.withFilterByType(eventKey === 'All' ? undefined : (eventKey as string)) ) } } @@ -41,13 +41,15 @@ export function FileCriteriaFilterByType({ return ( + eventKey="All" + className={selectedType.value === 'All' ? styles['selected-option'] : ''}> All diff --git a/src/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/AccessFileMenu.tsx b/src/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/AccessFileMenu.tsx index 72a53597a..98f157ef9 100644 --- a/src/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/AccessFileMenu.tsx +++ b/src/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/AccessFileMenu.tsx @@ -4,6 +4,7 @@ import { AccessStatus } from './AccessStatus' import { RequestAccessOption } from './RequestAccessOption' import { DropdownButton, DropdownHeader, Tooltip } from '@iqss/dataverse-design-system' import { useTranslation } from 'react-i18next' +import { FileDownloadOptions } from './FileDownloadOptions' interface FileActionButtonAccessFileProps { file: File @@ -23,6 +24,7 @@ export function AccessFileMenu({ file }: FileActionButtonAccessFileProps) { + ) diff --git a/src/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileDownloadOptions.tsx b/src/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileDownloadOptions.tsx new file mode 100644 index 000000000..61f0e8400 --- /dev/null +++ b/src/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileDownloadOptions.tsx @@ -0,0 +1,30 @@ +import { DropdownHeader } from '@iqss/dataverse-design-system' +import { Download } from 'react-bootstrap-icons' +import { File } from '../../../../../../../../files/domain/models/File' +import { FileTabularDownloadOptions } from './FileTabularDownloadOptions' +import { FileNonTabularDownloadOptions } from './FileNonTabularDownloadOptions' +import { useTranslation } from 'react-i18next' + +interface FileDownloadOptionsProps { + file: File +} + +export function FileDownloadOptions({ file }: FileDownloadOptionsProps) { + const { t } = useTranslation('files') + return ( + <> + + {t('actions.accessFileMenu.downloadOptions.title')} + + + {file.tabularData ? ( + + ) : ( + + )} + + ) +} + +// TODO: Add guestbook support +// TODO: Add file package support diff --git a/src/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileNonTabularDownloadOptions.tsx b/src/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileNonTabularDownloadOptions.tsx new file mode 100644 index 000000000..e7306abb0 --- /dev/null +++ b/src/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileNonTabularDownloadOptions.tsx @@ -0,0 +1,32 @@ +import { File, FileIngestStatus } from '../../../../../../../../files/domain/models/File' +import FileTypeToFriendlyTypeMap from '../../../../../../../../files/domain/models/FileTypeToFriendlyTypeMap' +import { DropdownButtonItem } from '@iqss/dataverse-design-system' +import { useDataset } from '../../../../../../DatasetContext' +import { useTranslation } from 'react-i18next' + +interface FileNonTabularDownloadOptionsProps { + file: File +} + +export function FileNonTabularDownloadOptions({ file }: FileNonTabularDownloadOptionsProps) { + const { t } = useTranslation('files') + const { dataset } = useDataset() + const originalFileFormatIsKnown = + file.type.toDisplayFormat() !== FileTypeToFriendlyTypeMap.unknown + + if (file.tabularData) { + return <> + } + + return ( + + {originalFileFormatIsKnown + ? file.type.toDisplayFormat() + : t('actions.accessFileMenu.downloadOptions.options.original')} + + ) +} diff --git a/src/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileTabularDownloadOptions.tsx b/src/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileTabularDownloadOptions.tsx new file mode 100644 index 000000000..c4e76fbd1 --- /dev/null +++ b/src/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileTabularDownloadOptions.tsx @@ -0,0 +1,39 @@ +import { File, FileIngestStatus } from '../../../../../../../../files/domain/models/File' +import { DropdownButtonItem } from '@iqss/dataverse-design-system' +import { useDataset } from '../../../../../../DatasetContext' +import { useTranslation } from 'react-i18next' + +interface FileTabularDownloadOptionsProps { + file: File +} + +export function FileTabularDownloadOptions({ file }: FileTabularDownloadOptionsProps) { + const { t } = useTranslation('files') + const { dataset } = useDataset() + const originalFileFormatIsKnown = file.type.original && file.type.original !== 'Unknown' + const downloadDisabled = + file.ingest.status === FileIngestStatus.IN_PROGRESS || + (dataset && dataset.isLockedFromFileDownload) + + if (!file.tabularData) { + return <> + } + + return ( + <> + {originalFileFormatIsKnown && ( + {`${file.type.original} (${t( + 'actions.accessFileMenu.downloadOptions.options.original' + )})`} + )} + + {t('actions.accessFileMenu.downloadOptions.options.tabular')} + + {file.type.original !== 'R Data' && ( + + {t('actions.accessFileMenu.downloadOptions.options.RData')} + + )} + + ) +} diff --git a/src/sections/dataset/dataset-files/files-table/file-info/file-info-cell/file-info-data/FileType.tsx b/src/sections/dataset/dataset-files/files-table/file-info/file-info-cell/file-info-data/FileType.tsx index e34f0dbfb..e7fb9725b 100644 --- a/src/sections/dataset/dataset-files/files-table/file-info/file-info-cell/file-info-data/FileType.tsx +++ b/src/sections/dataset/dataset-files/files-table/file-info/file-info-cell/file-info-data/FileType.tsx @@ -1,4 +1,5 @@ import { FileSize, FileType as FileTypeModel } from '../../../../../../../files/domain/models/File' +import { useTranslation } from 'react-i18next' interface FileTypeProps { type: FileTypeModel @@ -6,10 +7,14 @@ interface FileTypeProps { } export function FileType({ type, size }: FileTypeProps) { + const { t } = useTranslation('files') return (
- {type.toDisplayFormat()} - {size.toString()} + {type.value === 'text/tab-separated-values' + ? t('table.tabularData.name') + : type.toDisplayFormat()}{' '} + - {size.toString()}
) diff --git a/src/stories/dataset/dataset-files/files-table/file-actions/file-action-buttons/access-file-menu/AccessFileMenu.stories.tsx b/src/stories/dataset/dataset-files/files-table/file-actions/file-action-buttons/access-file-menu/AccessFileMenu.stories.tsx index 030cb0609..a3a80a32d 100644 --- a/src/stories/dataset/dataset-files/files-table/file-actions/file-action-buttons/access-file-menu/AccessFileMenu.stories.tsx +++ b/src/stories/dataset/dataset-files/files-table/file-actions/file-action-buttons/access-file-menu/AccessFileMenu.stories.tsx @@ -20,6 +20,14 @@ export const Default: Story = { render: () => } +export const NonTabularFiles: Story = { + render: () => +} + +export const TabularFiles: Story = { + render: () => +} + export const Restricted: Story = { render: () => } diff --git a/tests/component/dataset/domain/models/DatasetMother.ts b/tests/component/dataset/domain/models/DatasetMother.ts index 6f0522a33..85bc9fee3 100644 --- a/tests/component/dataset/domain/models/DatasetMother.ts +++ b/tests/component/dataset/domain/models/DatasetMother.ts @@ -183,6 +183,10 @@ export class DatasetLockMother { static createLockedInEditInProgress(): DatasetLock { return this.create({ reason: DatasetLockReason.EDIT_IN_PROGRESS }) } + + static createLockedFromFileDownload(): DatasetLock { + return this.create({ reason: DatasetLockReason.INGEST }) + } } export class DatasetMother { diff --git a/tests/component/files/domain/models/FileMother.ts b/tests/component/files/domain/models/FileMother.ts index 7b238d98d..99dc36332 100644 --- a/tests/component/files/domain/models/FileMother.ts +++ b/tests/component/files/domain/models/FileMother.ts @@ -13,6 +13,7 @@ import { FileType, FileChecksum } from '../../../../../src/files/domain/models/File' +import FileTypeToFriendlyTypeMap from '../../../../../src/files/domain/models/FileTypeToFriendlyTypeMap' const valueOrUndefined: (value: T) => T | undefined = (value) => { const shouldShowValue = faker.datatype.boolean() @@ -72,7 +73,7 @@ export class FileChecksumMother { export class FileMother { static create(props?: Partial): File { const thumbnail = valueOrUndefined(faker.image.imageUrl()) - const fileType = faker.helpers.arrayElement(['tabular data', faker.system.fileType()]) + const fileType = faker.helpers.arrayElement(Object.keys(FileTypeToFriendlyTypeMap)) const checksum = valueOrUndefined(faker.datatype.uuid()) const fileMockedData = { id: faker.datatype.number(), @@ -87,7 +88,10 @@ export class FileMother { number: faker.datatype.number(), publishingStatus: faker.helpers.arrayElement(Object.values(FilePublishingStatus)) }, - type: new FileType(thumbnail ? 'image' : fileType), + type: + fileType === 'text/tab-separated-values' + ? new FileType('text/tab-separated-values', 'Comma Separated Values') + : new FileType(thumbnail ? 'image' : fileType), size: { value: faker.datatype.number({ max: 1024, precision: 2 }), unit: faker.helpers.arrayElement(Object.values(FileSizeUnit)) @@ -110,7 +114,7 @@ export class FileMother { directory: valueOrUndefined(faker.system.directoryPath()), embargo: valueOrUndefined(FileEmbargoMother.create()), tabularData: - fileType === 'tabular data' && !checksum + fileType === 'text/tab-separated-values' && !checksum ? { variablesCount: faker.datatype.number(100), observationsCount: faker.datatype.number(100), @@ -150,7 +154,7 @@ export class FileMother { static createDefault(props?: Partial): File { const defaultFile = { - type: new FileType('file'), + type: new FileType('text/plain'), version: { number: 1, publishingStatus: FilePublishingStatus.RELEASED @@ -208,14 +212,15 @@ export class FileMother { }) } - static createWithTabularData(): File { + static createWithTabularData(props?: Partial): File { return this.createDefault({ - type: new FileType('tabular data'), + type: new FileType('text/tab-separated-values', 'Comma Separated Values'), tabularData: { variablesCount: faker.datatype.number(100), observationsCount: faker.datatype.number(100), unf: `UNF:${faker.datatype.uuid()}==` - } + }, + ...props }) } diff --git a/tests/component/files/domain/models/FilesCountInfoMother.tsx b/tests/component/files/domain/models/FilesCountInfoMother.tsx index 9be971256..43122d743 100644 --- a/tests/component/files/domain/models/FilesCountInfoMother.tsx +++ b/tests/component/files/domain/models/FilesCountInfoMother.tsx @@ -2,6 +2,7 @@ import { FileType } from '../../../../../src/files/domain/models/File' import { faker } from '@faker-js/faker' import { FilesCountInfo } from '../../../../../src/files/domain/models/FilesCountInfo' import { FileAccessOption, FileTag } from '../../../../../src/files/domain/models/FileCriteria' +import FileTypeToFriendlyTypeMap from '../../../../../src/files/domain/models/FileTypeToFriendlyTypeMap' export class FilesCountInfoMother { static create(props?: Partial): FilesCountInfo { @@ -10,11 +11,11 @@ export class FilesCountInfoMother { total: faker.datatype.number(), perFileType: [ { - type: new FileType(faker.system.fileType()), + type: new FileType(faker.helpers.arrayElement(Object.keys(FileTypeToFriendlyTypeMap))), count: faker.datatype.number({ max: total }) }, { - type: new FileType(faker.system.fileType()), + type: new FileType(faker.helpers.arrayElement(Object.keys(FileTypeToFriendlyTypeMap))), count: faker.datatype.number({ max: total }) } ], diff --git a/tests/component/sections/dataset/dataset-files/DatasetFiles.spec.tsx b/tests/component/sections/dataset/dataset-files/DatasetFiles.spec.tsx index f6ac50b7c..32cd4f0fe 100644 --- a/tests/component/sections/dataset/dataset-files/DatasetFiles.spec.tsx +++ b/tests/component/sections/dataset/dataset-files/DatasetFiles.spec.tsx @@ -25,11 +25,11 @@ const testFilesCountInfo = FilesCountInfoMother.create({ total: 200, perFileType: [ { - type: new FileType('text'), + type: new FileType('text/plain'), count: 5 }, { - type: new FileType('image'), + type: new FileType('image/png'), count: 485 } ], @@ -188,7 +188,7 @@ describe('DatasetFiles', () => { cy.findByText('1 file is currently selected.').should('exist') cy.findByRole('button', { name: 'File Type: All' }).click() - cy.findByText('Image (485)').should('exist').click() + cy.findByText('PNG Image (485)').should('exist').click() cy.findByText('1 file is currently selected.').should('not.exist') }) @@ -357,13 +357,13 @@ describe('DatasetFiles', () => { ) cy.findByRole('button', { name: 'File Type: All' }).click() - cy.findByText('Image (485)').should('exist').click() + cy.findByText('PNG Image (485)').should('exist').click() cy.wrap(fileRepository.getAllByDatasetPersistentId).should( 'be.calledWith', datasetPersistentId, datasetVersion, filePaginationInfo, - new FileCriteria().withFilterByType('image') + new FileCriteria().withFilterByType('image/png') ) }) @@ -456,7 +456,7 @@ describe('DatasetFiles', () => { ) cy.findByRole('button', { name: 'File Type: All' }).click() - cy.findByText('Image (485)').should('exist').click() + cy.findByText('PNG Image (485)').should('exist').click() cy.get('table > thead > tr > th > input[type=checkbox]').click() cy.findByRole('button', { name: 'Select all 200 files in this dataset.' }).click() cy.findByText( @@ -467,7 +467,7 @@ describe('DatasetFiles', () => { 'be.calledWith', datasetPersistentId, datasetVersion, - new FileCriteria().withFilterByType('image') + new FileCriteria().withFilterByType('image/png') ) }) }) diff --git a/tests/component/sections/dataset/dataset-files/file-criteria-form/FileCriteriaFilterByTag.spec.tsx b/tests/component/sections/dataset/dataset-files/file-criteria-form/FileCriteriaFilterByTag.spec.tsx index d2acad803..66c28929f 100644 --- a/tests/component/sections/dataset/dataset-files/file-criteria-form/FileCriteriaFilterByTag.spec.tsx +++ b/tests/component/sections/dataset/dataset-files/file-criteria-form/FileCriteriaFilterByTag.spec.tsx @@ -1,6 +1,5 @@ import { FileCriteria, FileTag } from '../../../../../../src/files/domain/models/FileCriteria' import { FilesCountInfoMother } from '../../../../files/domain/models/FilesCountInfoMother' -import { FileType } from '../../../../../../src/files/domain/models/File' import styles from '../../../../../../src/sections/dataset/dataset-files/file-criteria-form/FileCriteriaForm.module.scss' import { FileCriteriaFilterByTag } from '../../../../../../src/sections/dataset/dataset-files/file-criteria-form/FileCriteriaFilterByTag' @@ -12,7 +11,7 @@ const filesCountInfo = FilesCountInfoMother.create({ count: 5 }, { - tag: new FileType('data'), + tag: new FileTag('data'), count: 10 } ] diff --git a/tests/component/sections/dataset/dataset-files/file-criteria-form/FileCriteriaFilterByType.spec.tsx b/tests/component/sections/dataset/dataset-files/file-criteria-form/FileCriteriaFilterByType.spec.tsx index e6c72496f..20a5a4435 100644 --- a/tests/component/sections/dataset/dataset-files/file-criteria-form/FileCriteriaFilterByType.spec.tsx +++ b/tests/component/sections/dataset/dataset-files/file-criteria-form/FileCriteriaFilterByType.spec.tsx @@ -8,11 +8,11 @@ const defaultCriteria = new FileCriteria() const filesCountInfo = FilesCountInfoMother.create({ perFileType: [ { - type: new FileType('image'), + type: new FileType('image/png'), count: 5 }, { - type: new FileType('text'), + type: new FileType('text/plain'), count: 10 } ] @@ -33,8 +33,8 @@ describe('FilesCriteriaFilterByType', () => { cy.findByRole('button', { name: 'File Type: All' }).click() cy.findByText('All').should('exist') - cy.findByText('Image (5)').should('exist') - cy.findByText('Text (10)').should('exist') + cy.findByText('PNG Image (5)').should('exist') + cy.findByText('Plain Text (10)').should('exist') }) it('calls onCriteriaChange with the selected filter by type value', () => { @@ -49,17 +49,20 @@ describe('FilesCriteriaFilterByType', () => { ) cy.findByRole('button', { name: 'File Type: All' }).click() - cy.findByText('Image (5)').click() - cy.wrap(onCriteriaChange).should('be.calledWith', defaultCriteria.withFilterByType('image')) - - cy.findByRole('button', { name: 'File Type: Image' }).click() - cy.findByText('Text (10)').click() - cy.wrap(onCriteriaChange).should('be.calledWith', defaultCriteria.withFilterByType('text')) + cy.findByText('PNG Image (5)').click() + cy.wrap(onCriteriaChange).should('be.calledWith', defaultCriteria.withFilterByType('image/png')) + + cy.findByRole('button', { name: 'File Type: PNG Image' }).click() + cy.findByText('Plain Text (10)').click() + cy.wrap(onCriteriaChange).should( + 'be.calledWith', + defaultCriteria.withFilterByType('text/plain') + ) }) it('shows the selected filter in the dropdown title', () => { const onCriteriaChange = cy.stub().as('onCriteriaChange') - const criteria = defaultCriteria.withFilterByType('image') + const criteria = defaultCriteria.withFilterByType('image/png') cy.customMount( { /> ) - cy.findByRole('button', { name: 'File Type: Image' }).click() + cy.findByRole('button', { name: 'File Type: PNG Image' }).click() cy.findByText('All').should('exist').click() cy.wrap(onCriteriaChange).should('be.calledWith', defaultCriteria.withFilterByType(undefined)) }) @@ -88,13 +91,13 @@ describe('FilesCriteriaFilterByType', () => { cy.findByRole('button', { name: 'File Type: All' }).click() cy.findByText('All').should('have.class', styles['selected-option']) - cy.findByRole('button', { name: 'Image (5)' }).click() - cy.findByRole('button', { name: 'File Type: Image' }).click() - cy.findByText('Image (5)').should('have.class', styles['selected-option']) + cy.findByRole('button', { name: 'PNG Image (5)' }).click() + cy.findByRole('button', { name: 'File Type: PNG Image' }).click() + cy.findByText('PNG Image (5)').should('have.class', styles['selected-option']) - cy.findByRole('button', { name: 'Text (10)' }).click() - cy.findByRole('button', { name: 'File Type: Text' }).click() - cy.findByText('Text (10)').should('have.class', styles['selected-option']) + cy.findByRole('button', { name: 'Plain Text (10)' }).click() + cy.findByRole('button', { name: 'File Type: Plain Text' }).click() + cy.findByText('Plain Text (10)').should('have.class', styles['selected-option']) }) it('does not render the filter by type dropdown if there are no filter options', () => { @@ -109,6 +112,6 @@ describe('FilesCriteriaFilterByType', () => { /> ) - cy.findByRole('button', { name: 'File Type: Image' }).should('not.exist') + cy.findByRole('button', { name: 'File Type: PNG Image' }).should('not.exist') }) }) 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 bd0fb0294..8322b7a71 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 @@ -18,11 +18,11 @@ let onCriteriaChange = () => {} const filesCountInfo = FilesCountInfoMother.create({ perFileType: [ { - type: new FileType('image'), + type: new FileType('image/png'), count: 5 }, { - type: new FileType('text'), + type: new FileType('text/plain'), count: 10 } ], @@ -42,7 +42,7 @@ const filesCountInfo = FilesCountInfoMother.create({ count: 5 }, { - tag: new FileType('data'), + tag: new FileTag('data'), count: 10 } ] @@ -112,7 +112,7 @@ describe('FileCriteriaForm', () => { const criteria = new FileCriteria() .withFilterByTag('document') .withFilterByAccess(FileAccessOption.PUBLIC) - .withFilterByType('image') + .withFilterByType('image/png') .withSearchText('search text') cy.customMount( @@ -128,7 +128,7 @@ describe('FileCriteriaForm', () => { cy.wrap(onCriteriaChange).should('be.calledWith', criteria.withSortBy(FileSortByOption.OLDEST)) - cy.findByRole('button', { name: 'File Type: Image' }).should('exist') + cy.findByRole('button', { name: 'File Type: PNG Image' }).should('exist') cy.findByRole('button', { name: 'Access: Public' }).should('exist') cy.findByRole('button', { name: 'File Tags: Document' }).should('exist') cy.findByLabelText('Search').should('have.value', 'search text') @@ -139,7 +139,7 @@ describe('FileCriteriaForm', () => { const criteria = new FileCriteria() .withFilterByTag('document') .withFilterByAccess(FileAccessOption.PUBLIC) - .withFilterByType('image') + .withFilterByType('image/png') .withSearchText('search text') cy.customMount( @@ -150,12 +150,12 @@ describe('FileCriteriaForm', () => { /> ) - cy.findByRole('button', { name: 'File Type: Image' }).click() - cy.findByText('Text (10)').click() + cy.findByRole('button', { name: 'File Type: PNG Image' }).click() + cy.findByText('Plain Text (10)').click() - cy.wrap(onCriteriaChange).should('be.calledWith', criteria.withFilterByType('text')) + cy.wrap(onCriteriaChange).should('be.calledWith', criteria.withFilterByType('text/plain')) - cy.findByRole('button', { name: 'File Type: Text' }).should('exist') + cy.findByRole('button', { name: 'File Type: Plain Text' }).should('exist') cy.findByRole('button', { name: 'Access: Public' }).should('exist') cy.findByRole('button', { name: 'File Tags: Document' }).should('exist') cy.findByLabelText('Search').should('have.value', 'search text') @@ -166,7 +166,7 @@ describe('FileCriteriaForm', () => { const criteria = new FileCriteria() .withFilterByTag('document') .withFilterByAccess(FileAccessOption.PUBLIC) - .withFilterByType('image') + .withFilterByType('image/png') .withSearchText('search text') cy.customMount( @@ -185,7 +185,7 @@ describe('FileCriteriaForm', () => { criteria.withFilterByAccess(FileAccessOption.RESTRICTED) ) - cy.findByRole('button', { name: 'File Type: Image' }).should('exist') + cy.findByRole('button', { name: 'File Type: PNG Image' }).should('exist') cy.findByRole('button', { name: 'Access: Restricted' }).should('exist') cy.findByRole('button', { name: 'File Tags: Document' }).should('exist') cy.findByLabelText('Search').should('have.value', 'search text') @@ -196,7 +196,7 @@ describe('FileCriteriaForm', () => { const criteria = new FileCriteria() .withFilterByTag('document') .withFilterByAccess(FileAccessOption.PUBLIC) - .withFilterByType('image') + .withFilterByType('image/png') .withSearchText('search text') cy.customMount( @@ -212,7 +212,7 @@ describe('FileCriteriaForm', () => { cy.wrap(onCriteriaChange).should('be.calledWith', criteria.withFilterByTag('data')) - cy.findByRole('button', { name: 'File Type: Image' }).should('exist') + cy.findByRole('button', { name: 'File Type: PNG Image' }).should('exist') cy.findByRole('button', { name: 'Access: Public' }).should('exist') cy.findByRole('button', { name: 'File Tags: Data' }).should('exist') cy.findByLabelText('Search').should('have.value', 'search text') @@ -223,7 +223,7 @@ describe('FileCriteriaForm', () => { const criteria = new FileCriteria() .withFilterByTag('document') .withFilterByAccess(FileAccessOption.PUBLIC) - .withFilterByType('image') + .withFilterByType('image/png') .withSearchText('search text') cy.customMount( @@ -238,7 +238,7 @@ describe('FileCriteriaForm', () => { cy.wrap(onCriteriaChange).should('be.calledWith', criteria.withSearchText('new search')) - cy.findByRole('button', { name: 'File Type: Image' }).should('exist') + cy.findByRole('button', { name: 'File Type: PNG Image' }).should('exist') cy.findByRole('button', { name: 'Access: Public' }).should('exist') cy.findByRole('button', { name: 'File Tags: Document' }).should('exist') cy.findByLabelText('Search').should('have.value', 'new search') @@ -272,7 +272,7 @@ describe('FileCriteriaForm', () => { const criteria = new FileCriteria() .withFilterByTag('document') .withFilterByAccess(FileAccessOption.PUBLIC) - .withFilterByType('image') + .withFilterByType('image/png') cy.customMount( { cy.findByRole('button', { name: 'Access File' }).click() cy.findByRole('button', { name: 'Request Access' }).should('exist') }) + + it('renders the download options header', () => { + cy.customMount( + + + + ) + + cy.findByRole('button', { name: 'Access File' }).click() + cy.findByRole('heading', { name: 'Download Options' }).should('exist') + }) }) diff --git a/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileDownloadOptions.spec.tsx b/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileDownloadOptions.spec.tsx new file mode 100644 index 000000000..0c8d299cb --- /dev/null +++ b/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileDownloadOptions.spec.tsx @@ -0,0 +1,30 @@ +import { FileDownloadOptions } from '../../../../../../../../../../src/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileDownloadOptions' +import { FileMother } from '../../../../../../../../files/domain/models/FileMother' +import { FileType } from '../../../../../../../../../../src/files/domain/models/File' + +const fileNonTabular = FileMother.create({ + tabularData: undefined, + type: new FileType('text/plain') +}) +const fileTabular = FileMother.createWithTabularData() +describe('FileDownloadOptions', () => { + it('renders the download options header', () => { + cy.customMount() + + cy.findByRole('heading', { name: 'Download Options' }).should('exist') + }) + + it('renders the download options for a non-tabular file', () => { + cy.customMount() + + cy.findByRole('button', { name: 'Plain Text' }).should('exist') + }) + + it('renders the download options for a tabular file', () => { + cy.customMount() + + cy.findByRole('button', { name: 'Comma Separated Values (Original File Format)' }).should( + 'exist' + ) + }) +}) diff --git a/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileNonTabularDownloadOptions.spec.tsx b/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileNonTabularDownloadOptions.spec.tsx new file mode 100644 index 000000000..da32a5321 --- /dev/null +++ b/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileNonTabularDownloadOptions.spec.tsx @@ -0,0 +1,77 @@ +import { FileMother } from '../../../../../../../../files/domain/models/FileMother' +import { + FileIngestStatus, + FileType +} from '../../../../../../../../../../src/files/domain/models/File' +import { FileNonTabularDownloadOptions } from '../../../../../../../../../../src/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileNonTabularDownloadOptions' +import { DatasetProvider } from '../../../../../../../../../../src/sections/dataset/DatasetProvider' +import { DatasetRepository } from '../../../../../../../../../../src/dataset/domain/repositories/DatasetRepository' +import { + DatasetLockMother, + DatasetMother +} from '../../../../../../../../dataset/domain/models/DatasetMother' + +const fileNonTabular = FileMother.create({ + tabularData: undefined, + type: new FileType('text/plain') +}) +describe('FileNonTabularDownloadOptions', () => { + it('renders the download options for a non-tabular file of unknown type', () => { + const fileNonTabularUnknown = FileMother.create({ + tabularData: undefined, + type: new FileType('unknown') + }) + cy.customMount() + + cy.findByRole('button', { name: 'Original File Format' }) + .should('exist') + .should('not.have.class', 'disabled') + }) + + it('renders the download options for a non-tabular file', () => { + cy.customMount() + + cy.findByRole('button', { name: 'Plain Text' }) + .should('exist') + .should('not.have.class', 'disabled') + }) + + it('does not render the download options for a tabular file', () => { + const fileTabular = FileMother.createWithTabularData() + cy.customMount() + + cy.findByRole('button', { name: 'Original File Format' }).should('not.exist') + cy.findByRole('button', { name: 'Tab-Delimited' }).should('not.exist') + }) + + it('renders the options as disabled when the file ingest is in progress', () => { + const fileNonTabularInProgress = FileMother.create({ + tabularData: undefined, + type: new FileType('text/plain'), + ingest: { + status: FileIngestStatus.IN_PROGRESS + } + }) + cy.customMount() + + cy.findByRole('button', { name: 'Plain Text' }).should('have.class', 'disabled') + }) + + it('renders the options as disabled when the dataset is locked from file download', () => { + const datasetRepository: DatasetRepository = {} as DatasetRepository + const datasetLockedFromFileDownload = DatasetMother.create({ + locks: [DatasetLockMother.createLockedFromFileDownload()] + }) + datasetRepository.getByPersistentId = cy.stub().resolves(datasetLockedFromFileDownload) + + cy.customMount( + + + + ) + + cy.findByRole('button', { name: 'Plain Text' }).should('have.class', 'disabled') + }) +}) diff --git a/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileTabularDownloadOptions.spec.tsx b/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileTabularDownloadOptions.spec.tsx new file mode 100644 index 000000000..d54605ab2 --- /dev/null +++ b/tests/component/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileTabularDownloadOptions.spec.tsx @@ -0,0 +1,109 @@ +import { FileDownloadOptions } from '../../../../../../../../../../src/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileDownloadOptions' +import { FileMother } from '../../../../../../../../files/domain/models/FileMother' +import { + FileIngestStatus, + FileType +} from '../../../../../../../../../../src/files/domain/models/File' +import { FileTabularDownloadOptions } from '../../../../../../../../../../src/sections/dataset/dataset-files/files-table/file-actions/file-actions-cell/file-action-buttons/access-file-menu/FileTabularDownloadOptions' +import { DatasetRepository } from '../../../../../../../../../../src/dataset/domain/repositories/DatasetRepository' +import { + DatasetLockMother, + DatasetMother +} from '../../../../../../../../dataset/domain/models/DatasetMother' +import { DatasetProvider } from '../../../../../../../../../../src/sections/dataset/DatasetProvider' + +const fileNonTabular = FileMother.create({ + tabularData: undefined, + type: new FileType('text/plain') +}) +const fileTabular = FileMother.createWithTabularData() +const fileTabularUnknown = FileMother.createWithTabularData({ + type: new FileType('text/tab-separated-values', 'Unknown') +}) +describe('FileTabularDownloadOptions', () => { + it('renders the download options for a tabular file', () => { + cy.customMount() + + cy.findByRole('button', { name: 'Comma Separated Values (Original File Format)' }).should( + 'exist' + ) + cy.findByRole('button', { name: 'Tab-Delimited' }) + .should('exist') + .should('not.have.class', 'disabled') + cy.findByRole('button', { name: 'R Data' }).should('exist').should('not.have.class', 'disabled') + }) + + it('renders the download options for a tabular file of unknown original type', () => { + cy.customMount() + + cy.findByRole('button', { name: /(Original File Format)/ }).should('not.exist') + cy.findByRole('button', { name: 'Tab-Delimited' }) + .should('exist') + .should('not.have.class', 'disabled') + cy.findByRole('button', { name: 'R Data' }).should('exist').should('not.have.class', 'disabled') + }) + + it('does not render the download options for a non-tabular file', () => { + cy.customMount() + + cy.findByRole('button', { name: /(Original File Format)/ }).should('not.exist') + cy.findByRole('button', { name: 'Tab-Delimited' }).should('not.exist') + cy.findByRole('button', { name: 'R Data' }).should('not.exist') + }) + + it('renders the options as disabled when the file ingest is in progress', () => { + const fileTabularInProgress = FileMother.createWithTabularData({ + ingest: { + status: FileIngestStatus.IN_PROGRESS + } + }) + cy.customMount() + + cy.findByRole('button', { name: 'Comma Separated Values (Original File Format)' }) + .should('exist') + .should('have.class', 'disabled') + cy.findByRole('button', { name: 'Tab-Delimited' }) + .should('exist') + .should('have.class', 'disabled') + cy.findByRole('button', { name: 'R Data' }).should('exist').should('have.class', 'disabled') + }) + + it('renders the options as disabled when the dataset is locked from file download', () => { + const datasetRepository: DatasetRepository = {} as DatasetRepository + const datasetLockedFromFileDownload = DatasetMother.create({ + locks: [DatasetLockMother.createLockedFromFileDownload()] + }) + datasetRepository.getByPersistentId = cy.stub().resolves(datasetLockedFromFileDownload) + + cy.customMount( + + + + ) + + cy.findByRole('button', { name: 'Comma Separated Values (Original File Format)' }) + .should('exist') + .should('have.class', 'disabled') + cy.findByRole('button', { name: 'Tab-Delimited' }) + .should('exist') + .should('have.class', 'disabled') + cy.findByRole('button', { name: 'R Data' }).should('exist').should('have.class', 'disabled') + }) + + it('does not render the RData option if the file type is already R Data', () => { + const fileTabularRData = FileMother.createWithTabularData({ + type: new FileType('text/tab-separated-values', 'R Data') + }) + cy.customMount() + + cy.findByRole('button', { name: 'R Data (Original File Format)' }) + .should('exist') + .should('not.have.class', 'disabled') + cy.findByRole('button', { name: 'Tab-Delimited' }) + .should('exist') + .should('not.have.class', 'disabled') + cy.findByRole('button', { name: 'R Data' }).should('not.exist') + }) +}) diff --git a/tests/component/sections/dataset/dataset-files/files-table/files-info/file-info-cell/file-info-data/FileType.spec.tsx b/tests/component/sections/dataset/dataset-files/files-table/files-info/file-info-cell/file-info-data/FileType.spec.tsx index aaa1d6730..db176f339 100644 --- a/tests/component/sections/dataset/dataset-files/files-table/files-info/file-info-cell/file-info-data/FileType.spec.tsx +++ b/tests/component/sections/dataset/dataset-files/files-table/files-info/file-info-cell/file-info-data/FileType.spec.tsx @@ -14,7 +14,7 @@ describe('FileType', () => { }) cy.customMount() - cy.findByText(`Text/plain - 123 B`).should('exist') + cy.findByText(`Plain Text - 123 B`).should('exist') }) it('renders the type and size correctly when there are decimals', () => { @@ -24,6 +24,16 @@ describe('FileType', () => { }) cy.customMount() - cy.findByText(`Text/plain - 123.9 MB`).should('exist') + cy.findByText(`Plain Text - 123.9 MB`).should('exist') + }) + + it('renders the type correctly when is a tabular file', () => { + const file = FileMother.createWithTabularData({ + size: new FileSize(123.03932894722, FileSizeUnit.BYTES) + }) + + cy.customMount() + + cy.findByText(`Tabular Data - 123 B`).should('exist') }) }) diff --git a/tests/component/sections/dataset/dataset-files/files-table/files-info/file-info-cell/file-info-data/file-thumbnail/FileThumbnail.spec.tsx b/tests/component/sections/dataset/dataset-files/files-table/files-info/file-info-cell/file-info-data/file-thumbnail/FileThumbnail.spec.tsx index 9689efb80..48eadf5d1 100644 --- a/tests/component/sections/dataset/dataset-files/files-table/files-info/file-info-cell/file-info-data/file-thumbnail/FileThumbnail.spec.tsx +++ b/tests/component/sections/dataset/dataset-files/files-table/files-info/file-info-cell/file-info-data/file-thumbnail/FileThumbnail.spec.tsx @@ -92,7 +92,7 @@ describe('FileThumbnail', () => { cy.customMount() - cy.findByText('icon-other').should('exist') + cy.findByText('icon-document').should('exist') cy.findByText('Restricted File Icon').should('exist') cy.findByText('Restricted File Icon').should('exist').parent().trigger('mouseover') @@ -115,7 +115,7 @@ describe('FileThumbnail', () => { ) - cy.findByText('icon-other').should('exist') + cy.findByText('icon-document').should('exist') cy.findByText('Restricted File Icon').should('not.exist') cy.findByText('Restricted with access Icon').should('exist').parent().trigger('mouseover') diff --git a/tests/e2e-integration/e2e/sections/dataset/Dataset.spec.tsx b/tests/e2e-integration/e2e/sections/dataset/Dataset.spec.tsx index 4d963130f..bcaa94aad 100644 --- a/tests/e2e-integration/e2e/sections/dataset/Dataset.spec.tsx +++ b/tests/e2e-integration/e2e/sections/dataset/Dataset.spec.tsx @@ -410,7 +410,7 @@ describe('Dataset', () => { cy.findByText('blob-5').should('exist') cy.findByRole('button', { name: 'File Type: All' }).click({ force: true }) - cy.findByText('Text/csv (2)').should('exist').click({ force: true }) + cy.findByText('Comma Separated Values (2)').should('exist').click({ force: true }) cy.findByText('1 to 2 of 2 Files').should('exist') cy.findByText('blob').should('not.exist')