Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/417 File upload integration #464

Merged
merged 33 commits into from
Sep 4, 2024
Merged
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
797f2c7
dataset files upload factory fix
ErykKul Aug 16, 2024
cee8a89
merged s3 config
ErykKul Aug 16, 2024
b9085f7
initial integration with the upload files use case
ErykKul Aug 16, 2024
c4737b4
md5 calculate
ErykKul Aug 16, 2024
aa35354
added crypto-browserify dependency
ErykKul Aug 19, 2024
6e66b3d
changed dependency from crypto-browserify to js-md5
ErykKul Aug 19, 2024
b8560e8
streaming md5 implementation
ErykKul Aug 19, 2024
3af826a
fixed md5 calculation
ErykKul Aug 19, 2024
16ffdba
merged develop
ErykKul Aug 20, 2024
5196d69
integration test preparation
ErykKul Aug 22, 2024
5b0379a
merged develop
ErykKul Aug 22, 2024
2647715
integration tests
ErykKul Aug 22, 2024
485671c
upload multiple files test case
ErykKul Aug 23, 2024
fb85e80
navigate to dataset after upload finished
ErykKul Aug 23, 2024
5566efa
navigate to dataset after upload finished
ErykKul Aug 23, 2024
be77c15
uploaded files DTO refactoring
ErykKul Aug 26, 2024
6f88ff1
moved external libraries imports higher up
ErykKul Aug 26, 2024
288407a
'then' i.s.o. 'finally' in addUploadedFiles
ErykKul Aug 26, 2024
c4efe45
fixed select checkbox problem
ErykKul Aug 27, 2024
9f958d9
merged develop
ErykKul Aug 27, 2024
c2a2726
command timeout set to 10 seconds for integration tests
ErykKul Aug 28, 2024
c150ebf
e2e upload file test fix after uploaded file DTO refactoring
ErykKul Aug 28, 2024
5794c42
hardcoded mime-type to prevent file upload problems
ErykKul Aug 30, 2024
bbcc170
replaced the semaphore with the one from async-mutex package and impr…
ErykKul Aug 30, 2024
c9fc268
hardcoded mime type only if browser did not detect it correctly (empt…
ErykKul Aug 30, 2024
3aad2bc
removed flaky test
ErykKul Aug 30, 2024
ad60ab2
reverted to useEffect i.s.o. effect with deep compare
ErykKul Aug 30, 2024
76f5972
rename: newFiles -> currentFiles, x -> file
ErykKul Aug 30, 2024
a30f0fd
added comment on fileType possibly being an empty string in specific …
ErykKul Aug 30, 2024
5813f9a
merged develop
ErykKul Sep 3, 2024
1b7eb46
added a gap between the drop zone and the file list
ErykKul Sep 3, 2024
cc6da55
updated dv js client dependency with PR version fixing the progress b…
ErykKul Sep 4, 2024
f1ff52d
updated dv js client dependency
ErykKul Sep 4, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion cypress.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ export default defineConfig({
supportFile: 'tests/support/e2e.ts',
setupNodeEvents(on) {
on('file:preprocessor', vitePreprocessor(path.resolve(__dirname, './vite.config.ts')))
}
},
defaultCommandTimeout: 10_000 // https://docs.cypress.io/guides/references/configuration#Timeouts
},
component: {
indexHtmlFile: 'tests/support/component-index.html',
Expand Down
30 changes: 26 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
},
"dependencies": {
"@faker-js/faker": "7.6.0",
"@iqss/dataverse-client-javascript": "2.0.0-pr169.aa49f06",
"@iqss/dataverse-client-javascript": "2.0.0-pr187.a9d8e72",
"@iqss/dataverse-design-system": "*",
"@istanbuljs/nyc-config-typescript": "1.0.2",
"@tanstack/react-table": "8.9.2",
Expand Down Expand Up @@ -44,7 +44,9 @@
"typescript": "4.9.5",
"use-deep-compare": "1.2.1",
"vite-plugin-istanbul": "4.0.1",
"web-vitals": "2.1.4"
"web-vitals": "2.1.4",
"js-md5": "0.8.3",
"async-mutex": "0.5.0"
},
"scripts": {
"start": "vite --base=/spa",
Expand Down
30 changes: 30 additions & 0 deletions src/files/domain/models/FileUploadState.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { UploadedFileDTO } from '@iqss/dataverse-client-javascript'
import { FileSize, FileSizeUnit } from './FileMetadata'
import { UploadedFileDTOMapper } from '../../infrastructure/mappers/UploadedFileDTOMapper'

export interface FileUploadState {
progress: number
Expand All @@ -17,6 +19,7 @@ export interface FileUploadState {
description?: string
tags: string[]
restricted: boolean
checksumValue?: string
}

export interface FileUploaderState {
Expand Down Expand Up @@ -94,6 +97,18 @@ export class FileUploadTools {
return { state: oldState.state, uploaded: this.toUploaded(oldState.state) }
}

static checksum(
file: File,
checksumValue: string,
oldState: FileUploaderState
): FileUploaderState {
const fileUploadState = oldState.state.get(this.key(file))
if (fileUploadState) {
fileUploadState.checksumValue = checksumValue
}
return { state: oldState.state, uploaded: this.toUploaded(oldState.state) }
}

static failed(file: File, oldState: FileUploaderState): FileUploaderState {
const fileUploadState = oldState.state.get(this.key(file))
if (fileUploadState) {
Expand Down Expand Up @@ -127,6 +142,21 @@ export class FileUploadTools {
return { state: oldState.state, uploaded: this.toUploaded(oldState.state) }
}

static mapToUploadedFilesDTOs(state: FileUploadState[]): UploadedFileDTO[] {
return state.map((uploadedFile) =>
UploadedFileDTOMapper.toUploadedFileDTO(
uploadedFile.fileName,
uploadedFile.description,
uploadedFile.fileDir,
uploadedFile.tags,
uploadedFile.restricted,
uploadedFile.storageId as string,
uploadedFile.checksumValue as string,
uploadedFile.fileType === '' ? 'application/octet-stream' : uploadedFile.fileType // some browsers (e.g., chromium for .java files) fail to detect the mime type for some files and leave the fileType as an empty string, we use the default value 'application/octet-stream' in that case
)
)
}

private static toNewState(
file: File,
oldState: FileUploaderState
Expand Down
9 changes: 2 additions & 7 deletions src/files/domain/repositories/FileRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { FilePaginationInfo } from '../models/FilePaginationInfo'
import { FilePreview } from '../models/FilePreview'
import { FilesWithCount } from '../models/FilesWithCount'
import { FileHolder } from '../models/FileHolder'
import { FileUploadState } from '../models/FileUploadState'
import { UploadedFileDTO } from '@iqss/dataverse-client-javascript'

export interface FileRepository {
getAllByDatasetPersistentId: (
Expand Down Expand Up @@ -42,10 +42,5 @@ export interface FileRepository {
abortController: AbortController,
storageIdSetter: (storageId: string) => void
) => Promise<void>
addUploadedFiles: (datasetId: number | string, files: FileUploadState[]) => Promise<void>
addUploadedFile: (
datasetId: number | string,
file: FileHolder,
storageId: string
) => Promise<void>
addUploadedFiles: (datasetId: number | string, files: UploadedFileDTO[]) => Promise<void>
}
21 changes: 3 additions & 18 deletions src/files/domain/useCases/addUploadedFiles.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,16 @@
import { FileUploadState } from '../models/FileUploadState'
import { UploadedFileDTO } from '@iqss/dataverse-client-javascript'
import { FileRepository } from '../repositories/FileRepository'

export function addUploadedFiles(
fileRepository: FileRepository,
datasetId: number | string,
files: FileUploadState[],
files: UploadedFileDTO[],
done: () => void
): void {
fileRepository
.addUploadedFiles(datasetId, files)
.then(done)
.catch((error: Error) => {
throw new Error(error.message)
})
.finally(done)
}

export function addUploadedFile(
fileRepository: FileRepository,
datasetId: number | string,
file: File,
storageId: string,
done: () => void
): void {
fileRepository
.addUploadedFile(datasetId, { file: file }, storageId)
.catch((error: Error) => {
throw new Error(error.message)
})
.finally(done)
}
13 changes: 4 additions & 9 deletions src/files/infrastructure/FileJSDataverseRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import {
getFileDownloadCount,
getFileUserPermissions,
uploadFile as jsUploadFile,
addUploadedFilesToDataset,
UploadedFileDTO,
ReadError
} from '@iqss/dataverse-client-javascript'
import { FileCriteria } from '../domain/models/FileCriteria'
Expand All @@ -31,7 +33,6 @@ import { FilePermissions } from '../domain/models/FilePermissions'
import { JSFilePermissionsMapper } from './mappers/JSFilePermissionsMapper'
import { FilesWithCount } from '../domain/models/FilesWithCount'
import { FileHolder } from '../domain/models/FileHolder'
import { FileUploadState } from '../domain/models/FileUploadState'

const includeDeaccessioned = true

Expand Down Expand Up @@ -300,13 +301,7 @@ export class FileJSDataverseRepository implements FileRepository {
})
}

addUploadedFiles(_datasetId: number | string, _files: FileUploadState[]): Promise<void> {
// TODO: not yet implemented
return new Promise<void>(() => {})
}

addUploadedFile(datasetId: number | string, file: FileHolder, storageId: string): Promise<void> {
return new Promise<void>(() => {})
// return addUploadedFilesToDataset.execute(datasetId, file.file)
addUploadedFiles(datasetId: number | string, uploadedFiles: UploadedFileDTO[]): Promise<void> {
return addUploadedFilesToDataset.execute(datasetId, uploadedFiles)
}
}
26 changes: 26 additions & 0 deletions src/files/infrastructure/mappers/UploadedFileDTOMapper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { UploadedFileDTO } from '@iqss/dataverse-client-javascript'

export class UploadedFileDTOMapper {
static toUploadedFileDTO(
fileName: string,
description: string | undefined,
fileDir: string,
tags: string[],
restricted: boolean,
storageId: string,
checksumValue: string,
fileType: string
): UploadedFileDTO {
return {
fileName: fileName,
description: description,
directoryLabel: fileDir,
categories: tags,
restrict: restricted,
storageId: storageId,
checksumValue: checksumValue,
checksumType: 'md5',
mimeType: fileType
}
}
}
25 changes: 7 additions & 18 deletions src/sections/upload-dataset-files/FileUploader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { FileUploadTools, FileUploaderState } from '../../files/domain/models/Fi
import styles from './FileUploader.module.scss'

export interface FileUploaderProps {
upload: (files: File[]) => void
upload: (file: File) => void
cancelTitle: string
info: string
selectText: string
Expand All @@ -30,21 +30,14 @@ export function FileUploader({

const addFiles = (selectedFiles: FileList | null) => {
if (selectedFiles && selectedFiles.length > 0) {
setFiles((alreadyAdded) => {
const selectedFilesArray = Array.from(selectedFiles)
const selectedFilesSet = new Set(selectedFilesArray.map((x) => FileUploadTools.key(x)))
const alreadyAddedFiltered = alreadyAdded.filter(
/* istanbul ignore next */
(x) => !selectedFilesSet.has(FileUploadTools.key(x))
)
return [...alreadyAddedFiltered, ...selectedFilesArray]
})
Array.from(selectedFiles).forEach((file) => addFile(file))
}
}

const addFile = (file: File) => {
if (!files.some((x) => FileUploadTools.key(x) === FileUploadTools.key(file))) {
setFiles((oldFiles) => [...oldFiles, file])
upload(file)
}
}

Expand Down Expand Up @@ -106,15 +99,11 @@ export function FileUploader({
}

useEffect(() => {
upload(files)
}, [files, upload])

useEffect(() => {
setFiles((newFiles) =>
newFiles.filter((x) => {
const res = !FileUploadTools.get(x, fileUploaderState).removed
setFiles((currentFiles) =>
currentFiles.filter((file) => {
const res = !FileUploadTools.get(file, fileUploaderState).removed
if (!res) {
cleanFileState(x)
cleanFileState(file)
}
return res
})
Expand Down
Loading
Loading