Skip to content

Commit

Permalink
Merge pull request #254 from IQSS/feature/221-integration-files-table…
Browse files Browse the repository at this point in the history
…-row-selection-download

221 - Integration multiple files download
  • Loading branch information
GPortas authored Dec 15, 2023
2 parents 14a74ae + 66f2331 commit c3c00ce
Show file tree
Hide file tree
Showing 22 changed files with 426 additions and 184 deletions.
8 changes: 8 additions & 0 deletions src/dataset/domain/models/Dataset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,11 @@ export interface PrivateUrl {
urlSnippet: string
}

export interface DatasetDownloadUrls {
original: string
archival: string
}

export class Dataset {
constructor(
public readonly persistentId: string,
Expand All @@ -280,6 +285,7 @@ export class Dataset {
public readonly hasOneTabularFileAtLeast: boolean,
public readonly isValid: boolean,
public readonly isReleased: boolean,
public readonly downloadUrls: DatasetDownloadUrls,
public readonly thumbnail?: string,
public readonly privateUrl?: PrivateUrl,
public readonly fileDownloadSizes?: FileDownloadSize[]
Expand Down Expand Up @@ -365,6 +371,7 @@ export class Dataset {
public readonly hasOneTabularFileAtLeast: boolean,
public readonly isValid: boolean,
public readonly isReleased: boolean,
public readonly downloadUrls: DatasetDownloadUrls,
public readonly thumbnail?: string,
public readonly privateUrl?: PrivateUrl,
public readonly fileDownloadSizes?: FileDownloadSize[]
Expand Down Expand Up @@ -475,6 +482,7 @@ export class Dataset {
this.hasOneTabularFileAtLeast,
this.isValid,
this.isReleased,
this.downloadUrls,
this.thumbnail,
this.privateUrl,
this.fileDownloadSizes
Expand Down
22 changes: 19 additions & 3 deletions src/dataset/infrastructure/mappers/JSDatasetMapper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,11 @@ import {
DatasetMetadataFields,
DatasetVersion,
MetadataBlockName,
PrivateUrl,
DatasetDownloadUrls,
DatasetPermissions,
DatasetLock,
DatasetLockReason,
PrivateUrl
DatasetLockReason
} from '../../domain/models/Dataset'

export class JSDatasetMapper {
Expand All @@ -32,9 +33,14 @@ export class JSDatasetMapper {
requestedVersion?: string,
privateUrl?: PrivateUrl
): Dataset {
const version = JSDatasetMapper.toVersion(
jsDataset.versionId,
jsDataset.versionInfo,
requestedVersion
)
return new Dataset.Builder(
jsDataset.persistentId,
JSDatasetMapper.toVersion(jsDataset.versionId, jsDataset.versionInfo, requestedVersion),
version,
citation,
JSDatasetMapper.toSummaryFields(jsDataset.metadataBlocks, summaryFieldsNames),
jsDataset.license,
Expand All @@ -50,6 +56,7 @@ export class JSDatasetMapper {
true, // TODO Connect with dataset hasOneTabularFileAtLeast
true, // TODO Connect with dataset isValid
JSDatasetMapper.toIsReleased(jsDataset.versionInfo),
JSDatasetMapper.toDownloadUrls(jsDataset.persistentId, version),
undefined, // TODO: get dataset thumbnail from Dataverse https://github.com/IQSS/dataverse-frontend/issues/203
privateUrl,
[] // TODO: Connect with file download use case
Expand Down Expand Up @@ -187,6 +194,15 @@ export class JSDatasetMapper {
return extraFields
}

static toDownloadUrls(
jsDatasetPersistentId: string,
version: DatasetVersion
): DatasetDownloadUrls {
return {
original: `/api/access/dataset/:persistentId/versions/${version.toString()}?persistentId=${jsDatasetPersistentId}&format=original`,
archival: `/api/access/dataset/:persistentId/versions/${version.toString()}?persistentId=${jsDatasetPersistentId}`
}
}
static toIsReleased(jsDatasetVersionInfo: JSDatasetVersionInfo): boolean {
return (
jsDatasetVersionInfo.releaseTime !== undefined &&
Expand Down
13 changes: 6 additions & 7 deletions src/files/domain/models/File.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,17 +63,11 @@ export class FileSize {
}
}

export enum FileDownloadSizeMode {
ALL = 'All',
ORIGINAL = 'Original',
ARCHIVAL = 'Archival'
}

export class FileDownloadSize extends FileSize {
constructor(
readonly value: number,
readonly unit: FileSizeUnit,
readonly mode: FileDownloadSizeMode
readonly mode: FileDownloadMode
) {
super(value, unit)
}
Expand Down Expand Up @@ -127,6 +121,11 @@ export interface FileTabularData {
unf?: string
}

export enum FileDownloadMode {
ARCHIVAL = 'archival',
ORIGINAL = 'original'
}

export enum FileLabelType {
CATEGORY = 'category',
TAG = 'tag'
Expand Down
4 changes: 3 additions & 1 deletion src/files/domain/repositories/FileRepository.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { File } from '../models/File'
import { File, FileDownloadMode } from '../models/File'
import { FileCriteria } from '../models/FileCriteria'
import { FilesCountInfo } from '../models/FilesCountInfo'
import { FilePaginationInfo } from '../models/FilePaginationInfo'
Expand All @@ -23,4 +23,6 @@ export interface FileRepository {
criteria?: FileCriteria
) => Promise<number>
getUserPermissionsById: (id: number) => Promise<FileUserPermissions>
getMultipleFileDownloadUrl: (ids: number[], downloadMode: FileDownloadMode) => string
getFileDownloadUrl: (id: number, downloadMode: FileDownloadMode) => string
}
15 changes: 15 additions & 0 deletions src/files/domain/useCases/getMultipleFileDownloadUrl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { FileRepository } from '../repositories/FileRepository'
import { FileDownloadMode } from '../models/File'

const ONLY_ONE_FILE = 1
export function getMultipleFileDownloadUrl(
fileRepository: FileRepository,
ids: number[],
downloadMode: FileDownloadMode
): string {
if (ids.length === ONLY_ONE_FILE) {
return fileRepository.getFileDownloadUrl(ids[0], downloadMode)
}

return fileRepository.getMultipleFileDownloadUrl(ids, downloadMode)
}
21 changes: 16 additions & 5 deletions src/files/infrastructure/FileJSDataverseRepository.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { FileRepository } from '../domain/repositories/FileRepository'
import { File } from '../domain/models/File'
import { File, FileDownloadMode } from '../domain/models/File'
import { FilesCountInfo } from '../domain/models/FilesCountInfo'
import { FilePaginationInfo } from '../domain/models/FilePaginationInfo'
import { FileUserPermissions } from '../domain/models/FileUserPermissions'
import {
File as JSFile,
FileDataTable as JSFileTabularData,
FileDownloadSizeMode,
getDatasetFileCounts,
getDatasetFiles,
getDatasetFilesTotalDownloadSize,
getFileDataTables,
getFileDownloadCount,
getFileUserPermissions,
ReadError,
File as JSFile,
getFileDataTables,
FileDataTable as JSFileTabularData
ReadError
} from '@iqss/dataverse-client-javascript'
import { FileCriteria } from '../domain/models/FileCriteria'
import { DomainFileMapper } from './mappers/DomainFileMapper'
Expand Down Expand Up @@ -155,4 +155,15 @@ export class FileJSDataverseRepository implements FileRepository {
throw new Error(error.message)
})
}

getMultipleFileDownloadUrl(ids: number[], downloadMode: FileDownloadMode): string {
return `/api/access/datafiles/${ids.join(',')}?format=${downloadMode}`
}

getFileDownloadUrl(id: number, downloadMode: FileDownloadMode): string {
if (downloadMode === FileDownloadMode.ORIGINAL) {
return `/api/access/datafile/${id}?format=${downloadMode}`
}
return `/api/access/datafile/${id}`
}
}
29 changes: 16 additions & 13 deletions src/sections/dataset/DatasetFactory.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { SettingJSDataverseRepository } from '../../settings/infrastructure/Sett
import { FilePermissionsProvider } from '../file/file-permissions/FilePermissionsProvider'
import { SettingsProvider } from '../settings/SettingsProvider'
import { DatasetProvider } from './DatasetProvider'
import { MultipleFileDownloadProvider } from '../file/multiple-file-download/MultipleFileDownloadProvider'
import { NotImplementedModalProvider } from '../not-implemented/NotImplementedModalProvider'
import { AlertProvider } from '../alerts/AlertProvider'

Expand All @@ -22,19 +23,21 @@ const settingRepository = new SettingJSDataverseRepository()
export class DatasetFactory {
static create(): ReactElement {
return (
<FilePermissionsProvider repository={fileRepository}>
<SettingsProvider repository={settingRepository}>
<NotImplementedModalProvider>
<MetadataBlockInfoProvider repository={metadataBlockInfoRepository}>
<AnonymizedProvider>
<AlertProvider>
<DatasetWithSearchParams />
</AlertProvider>
</AnonymizedProvider>
</MetadataBlockInfoProvider>
</NotImplementedModalProvider>
</SettingsProvider>
</FilePermissionsProvider>
<MultipleFileDownloadProvider repository={fileRepository}>
<FilePermissionsProvider repository={fileRepository}>
<SettingsProvider repository={settingRepository}>
<NotImplementedModalProvider>
<MetadataBlockInfoProvider repository={metadataBlockInfoRepository}>
<AnonymizedProvider>
<AlertProvider>
<DatasetWithSearchParams />
</AlertProvider>
</AnonymizedProvider>
</MetadataBlockInfoProvider>
</NotImplementedModalProvider>
</SettingsProvider>
</FilePermissionsProvider>
</MultipleFileDownloadProvider>
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
import { DropdownButton, DropdownButtonItem, DropdownHeader } from '@iqss/dataverse-design-system'
import { useTranslation } from 'react-i18next'

import { FileDownloadSize, FileDownloadSizeMode } from '../../../../files/domain/models/File'
import { FileDownloadMode, FileDownloadSize } from '../../../../files/domain/models/File'
import { Download } from 'react-bootstrap-icons'

interface AccessDatasetMenuProps {
Expand All @@ -30,12 +30,12 @@ export function AccessDatasetMenu({
return <></>
}

function getFormattedFileSize(mode: FileDownloadSizeMode): string {
function getFormattedFileSize(mode: FileDownloadMode): string {
const foundSize = fileDownloadSizes && fileDownloadSizes.find((size) => size.mode === mode)
return foundSize ? foundSize.toString() : ''
}

const handleDownload = (type: FileDownloadSizeMode) => {
const handleDownload = (type: FileDownloadMode) => {
//TODO: implement download feature
console.log('downloading file ' + type)
}
Expand All @@ -47,19 +47,19 @@ export function AccessDatasetMenu({
const DatasetDownloadOptions = ({ datasetContainsTabularFiles }: DatasetDownloadOptionsProps) => {
return datasetContainsTabularFiles ? (
<>
<DropdownButtonItem onClick={() => handleDownload(FileDownloadSizeMode.ORIGINAL)}>
<DropdownButtonItem onClick={() => handleDownload(FileDownloadMode.ORIGINAL)}>
{t('datasetActionButtons.accessDataset.downloadOriginalZip')} (
{getFormattedFileSize(FileDownloadSizeMode.ORIGINAL)})
{getFormattedFileSize(FileDownloadMode.ORIGINAL)})
</DropdownButtonItem>
<DropdownButtonItem onClick={() => handleDownload(FileDownloadSizeMode.ARCHIVAL)}>
<DropdownButtonItem onClick={() => handleDownload(FileDownloadMode.ARCHIVAL)}>
{t('datasetActionButtons.accessDataset.downloadArchiveZip')} (
{getFormattedFileSize(FileDownloadSizeMode.ARCHIVAL)})
{getFormattedFileSize(FileDownloadMode.ARCHIVAL)})
</DropdownButtonItem>
</>
) : (
<DropdownButtonItem onClick={() => handleDownload(FileDownloadSizeMode.ORIGINAL)}>
<DropdownButtonItem onClick={() => handleDownload(FileDownloadMode.ORIGINAL)}>
{t('datasetActionButtons.accessDataset.downloadZip')} (
{getFormattedFileSize(FileDownloadSizeMode.ORIGINAL)})
{getFormattedFileSize(FileDownloadMode.ORIGINAL)})
</DropdownButtonItem>
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { File } from '../../../../../../files/domain/models/File'
import { File, FileDownloadMode } from '../../../../../../files/domain/models/File'
import { useDataset } from '../../../../DatasetContext'
import { Button, DropdownButton, DropdownButtonItem } from '@iqss/dataverse-design-system'
import { Download } from 'react-bootstrap-icons'
import styles from './DownloadFilesButton.module.scss'
import { useTranslation } from 'react-i18next'
import { FileSelection } from '../../row-selection/useFileSelection'
import { NoSelectedFilesModal } from '../no-selected-files-modal/NoSelectedFilesModal'
import { useState } from 'react'
import { useNotImplementedModal } from '../../../../../not-implemented/NotImplementedModalContext'
import { MouseEvent, useState } from 'react'
import { useMultipleFileDownload } from '../../../../../file/multiple-file-download/MultipleFileDownloadContext'

interface DownloadFilesButtonProps {
files: File[]
Expand All @@ -21,27 +21,31 @@ export function DownloadFilesButton({ files, fileSelection }: DownloadFilesButto
const { t } = useTranslation('files')
const { dataset } = useDataset()
const [showNoFilesSelectedModal, setShowNoFilesSelectedModal] = useState(false)
const handleClick = () => {
// TODO - Implement upload files
showModal()
const { getMultipleFileDownloadUrl } = useMultipleFileDownload()
const fileSelectionCount = Object.keys(fileSelection).length
const onClick = (event: MouseEvent<HTMLButtonElement>) => {
if (fileSelectionCount === SELECTED_FILES_EMPTY) {
event.preventDefault()
setShowNoFilesSelectedModal(true)
}
}
const { showModal } = useNotImplementedModal()
const getDownloadUrl = (downloadMode: FileDownloadMode): string => {
const allFilesSelected = Object.values(fileSelection).some((file) => file === undefined)
if (allFilesSelected) {
return dataset ? dataset.downloadUrls[downloadMode] : ''
}

return getMultipleFileDownloadUrl(getFileIdsFromSelection(fileSelection), downloadMode)
}

if (
files.length < MINIMUM_FILES_COUNT_TO_SHOW_DOWNLOAD_FILES_BUTTON ||
!dataset?.permissions.canDownloadFiles
) {
return <></>
}

const onClick = () => {
if (Object.keys(fileSelection).length === SELECTED_FILES_EMPTY) {
setShowNoFilesSelectedModal(true)
} else {
handleClick()
}
}

if (files.some((file) => file.isTabularData)) {
if (dataset.hasOneTabularFileAtLeast) {
return (
<>
<DropdownButton
Expand All @@ -50,10 +54,10 @@ export function DownloadFilesButton({ files, fileSelection }: DownloadFilesButto
title={t('actions.downloadFiles.title')}
variant="secondary"
withSpacing>
<DropdownButtonItem onClick={onClick}>
<DropdownButtonItem onClick={onClick} href={getDownloadUrl(FileDownloadMode.ORIGINAL)}>
{t('actions.downloadFiles.options.original')}
</DropdownButtonItem>
<DropdownButtonItem onClick={onClick}>
<DropdownButtonItem onClick={onClick} href={getDownloadUrl(FileDownloadMode.ARCHIVAL)}>
{t('actions.downloadFiles.options.archival')}
</DropdownButtonItem>
</DropdownButton>
Expand All @@ -67,17 +71,25 @@ export function DownloadFilesButton({ files, fileSelection }: DownloadFilesButto

return (
<>
<Button
variant="secondary"
icon={<Download className={styles.icon} />}
withSpacing
onClick={onClick}>
{t('actions.downloadFiles.title')}
</Button>
<a href={getDownloadUrl(FileDownloadMode.ORIGINAL)}>
<Button
variant="secondary"
icon={<Download className={styles.icon} />}
withSpacing
onClick={onClick}>
{t('actions.downloadFiles.title')}
</Button>
</a>
<NoSelectedFilesModal
show={showNoFilesSelectedModal}
handleClose={() => setShowNoFilesSelectedModal(false)}
/>
</>
)
}

const getFileIdsFromSelection = (fileSelection: FileSelection): number[] => {
return Object.values(fileSelection)
.filter((file): file is File => file !== undefined)
.map((file) => file.id)
}
Loading

0 comments on commit c3c00ce

Please sign in to comment.