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 15 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
6 changes: 6 additions & 0 deletions package-lock.json

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

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@
"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"
},
"scripts": {
"start": "vite --base=/spa",
Expand Down
13 changes: 13 additions & 0 deletions src/files/domain/models/FileUploadState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export interface FileUploadState {
description?: string
tags: string[]
restricted: boolean
checksumValue?: string
}

export interface FileUploaderState {
Expand Down Expand Up @@ -94,6 +95,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
5 changes: 0 additions & 5 deletions src/files/domain/repositories/FileRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,4 @@ export interface FileRepository {
storageIdSetter: (storageId: string) => void
) => Promise<void>
addUploadedFiles: (datasetId: number | string, files: FileUploadState[]) => Promise<void>
addUploadedFile: (
datasetId: number | string,
file: FileHolder,
storageId: string
) => Promise<void>
}
15 changes: 0 additions & 15 deletions src/files/domain/useCases/addUploadedFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,3 @@ export function addUploadedFiles(
})
.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)
}
23 changes: 15 additions & 8 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 Down Expand Up @@ -300,13 +302,18 @@ 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, files: FileUploadState[]): Promise<void> {
const uploadedFiles: UploadedFileDTO[] = files.map((x) => ({
fileName: x.fileName,
description: x.description,
directoryLabel: x.fileDir,
categories: x.tags,
restrict: x.restricted,
storageId: x.storageId as string,
checksumValue: x.checksumValue as string,
checksumType: 'md5',
mimeType: x.fileType
}))
return addUploadedFilesToDataset.execute(datasetId, uploadedFiles)
}
}
47 changes: 34 additions & 13 deletions src/sections/upload-dataset-files/UploadDatasetFiles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ import { FileUploader } from './FileUploader'
import { FileUploadState, FileUploadTools } from '../../files/domain/models/FileUploadState'
import { uploadFile } from '../../files/domain/useCases/uploadFile'
import { UploadedFiles } from './uploaded-files-list/UploadedFiles'
import { addUploadedFile, addUploadedFiles } from '../../files/domain/useCases/addUploadedFiles'
import { addUploadedFiles } from '../../files/domain/useCases/addUploadedFiles'
import { md5 } from 'js-md5'
import { useNavigate } from 'react-router-dom'
import { Route } from '../Route.enum'

interface UploadDatasetFilesProps {
fileRepository: FileRepository
Expand All @@ -22,6 +25,7 @@ export const UploadDatasetFiles = ({ fileRepository: fileRepository }: UploadDat
const [fileUploaderState, setState] = useState(FileUploadTools.createNewState([]))
const [uploadingToCancelMap, setUploadingToCancelMap] = useState(new Map<string, () => void>())
const [semaphore, setSemaphore] = useState(new Set<string>())
const navigate = useNavigate()

const sleep = (delay: number) => new Promise((res) => setTimeout(res, delay))
const limit = 6
Expand All @@ -42,15 +46,36 @@ export const UploadDatasetFiles = ({ fileRepository: fileRepository }: UploadDat
})
}

const fileUploadFinished = (file: File) => {
const key = FileUploadTools.key(file)
const fileUploadFailed = (file: File) => {
setUploadingToCancelMap((x) => {
x.delete(key)
x.delete(FileUploadTools.key(file))
return x
})
releaseSemaphore(file)
}

const fileUploadFinished = (file: File) => {
const hash = md5.create()
const reader = file.stream().getReader()
reader
.read()
.then(async function updateHash({ done, value }) {
if (done) {
FileUploadTools.checksum(file, hash.hex(), fileUploaderState)
} else {
hash.update(value)
await updateHash(await reader.read())
}
})
.finally(() => {
setUploadingToCancelMap((x) => {
x.delete(FileUploadTools.key(file))
return x
})
releaseSemaphore(file)
})
}

const canUpload = (file: File) =>
!uploadingToCancelMap.has(FileUploadTools.key(file)) &&
!FileUploadTools.get(file, fileUploaderState).failed &&
Expand All @@ -71,17 +96,10 @@ export const UploadDatasetFiles = ({ fileRepository: fileRepository }: UploadDat
() => {
setState(FileUploadTools.done(file, fileUploaderState))
fileUploadFinished(file)
addUploadedFile(
fileRepository,
dataset?.persistentId as string,
file,
FileUploadTools.get(file, fileUploaderState).storageId as string,
() => {}
)
},
() => {
setState(FileUploadTools.failed(file, fileUploaderState))
fileUploadFinished(file)
fileUploadFailed(file)
},
(now) => setState(FileUploadTools.progress(file, now, fileUploaderState)),
(storageId) => setState(FileUploadTools.storageId(file, storageId, fileUploaderState))
Expand Down Expand Up @@ -141,7 +159,10 @@ export const UploadDatasetFiles = ({ fileRepository: fileRepository }: UploadDat

const addFiles = (state: FileUploadState[]) => {
setIsLoading(true)
const done = () => setIsLoading(false)
const done = () => {
setIsLoading(false)
navigate(`${Route.DATASETS}?persistentId=${dataset?.persistentId as string}&version=:draft`)
}
addUploadedFiles(fileRepository, dataset?.persistentId as string, state, done)
cleanAllState()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { DatasetJSDataverseRepository } from '../../dataset/infrastructure/repos
import { FileJSDataverseRepository } from '../../files/infrastructure/FileJSDataverseRepository'
import { DatasetProvider } from '../dataset/DatasetProvider'
import { UploadDatasetFiles } from './UploadDatasetFiles'
import { DatasetNonNumericVersion } from '../../dataset/domain/models/Dataset'

const datasetRepository = new DatasetJSDataverseRepository()
const fileRepository = new FileJSDataverseRepository()
Expand All @@ -17,9 +18,12 @@ export class UploadDatasetFilesFactory {
function UploadDatasetFilesWithSearchParams() {
const [searchParams] = useSearchParams()
const persistentId = searchParams.get('persistentId') ?? undefined
const version = searchParams.get('version') ?? DatasetNonNumericVersion.DRAFT

return (
<DatasetProvider repository={datasetRepository} searchParams={{ persistentId: persistentId }}>
<DatasetProvider
repository={datasetRepository}
searchParams={{ persistentId: persistentId, version: version }}>
<UploadDatasetFiles fileRepository={fileRepository} />
</DatasetProvider>
)
Expand Down
12 changes: 0 additions & 12 deletions src/stories/file/FileMockRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,16 +114,4 @@ export class FileMockRepository implements FileRepository {
}, FakerHelper.loadingTimout())
})
}

addUploadedFile(
_datasetId: number | string,
_file: FileHolder,
_storageId: string
): Promise<void> {
return new Promise((resolve) => {
setTimeout(() => {
resolve()
}, FakerHelper.loadingTimout())
})
}
}
Loading
Loading