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 integrate file upload page with use cases (early implementation) #418

Merged
merged 99 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from 98 commits
Commits
Show all changes
99 commits
Select commit Hold shift + click to select a range
d1a4186
merged file upload use case
ErykKul Jun 14, 2024
2693d45
added file list top file uploader
ErykKul Jun 14, 2024
f8dc2d0
uploaded files list
ErykKul Jun 14, 2024
b0dc639
added info on dirs drop
ErykKul Jun 14, 2024
854a0b3
save and cancel buttons implementation
ErykKul Jun 17, 2024
62d9f71
passing label not possible yet
ErykKul Jun 17, 2024
37ff2be
clean state after add
ErykKul Jun 17, 2024
3220abc
some fixes
ErykKul Jun 17, 2024
00f8ab2
added description setter
ErykKul Jun 17, 2024
2a73966
save button enabled logic fix
ErykKul Jun 17, 2024
ab20b77
moved files rebuilding
ErykKul Jun 17, 2024
9ae3275
promise all
ErykKul Jun 17, 2024
53e6bca
use case integration preparation
ErykKul Jun 17, 2024
3159a8b
merged develop branch
ErykKul Jun 18, 2024
5831706
fixed unit tests
ErykKul Jun 18, 2024
ab49fe0
added tests and improved coverage
ErykKul Jun 18, 2024
d24318b
background color on drag fix
ErykKul Jun 18, 2024
b5d04fb
editable file name, dir and description
ErykKul Jun 18, 2024
5228ce9
restricted and tags edit
ErykKul Jun 18, 2024
1d163e7
css tweaks
ErykKul Jun 18, 2024
9900237
fixed tag button
ErykKul Jun 18, 2024
bf2cddc
file selection
ErykKul Jun 19, 2024
fda7c63
lint fix
ErykKul Jun 19, 2024
046f016
select actions
ErykKul Jun 19, 2024
8ebeda7
checkox fix
ErykKul Jun 19, 2024
f73c9a5
select click fix
ErykKul Jun 19, 2024
921ba0c
improved file list design
ErykKul Jun 19, 2024
d378b15
rename class in css: selected -> selected_files_info
ErykKul Jun 19, 2024
9e2bd2a
code format
ErykKul Jun 19, 2024
91f744d
added tag options form and refactored code
ErykKul Jun 20, 2024
af9a0d9
form field reset after the tag option is added
ErykKul Jun 20, 2024
7c90fbf
restrict access form
ErykKul Jun 20, 2024
f19d7a1
restriction dialog
ErykKul Jun 20, 2024
4e535a6
moved uploaded files list implementation
ErykKul Jun 20, 2024
bc315cd
rename: restriction form -> restriction modal
ErykKul Jun 20, 2024
8364d7a
rename: tag options -> tag options modal
ErykKul Jun 20, 2024
79ec76a
improved restriction modal
ErykKul Jun 20, 2024
d155922
tag options modal
ErykKul Jun 20, 2024
4342a67
handle enter in tag options dialog
ErykKul Jun 20, 2024
f4351c9
fixed restriction modal
ErykKul Jun 20, 2024
d6dc078
cleanup of the mock file repo upload funcs
ErykKul Jun 20, 2024
211ba8a
lint fix
ErykKul Jun 20, 2024
e5543ce
test: fix test, add new missing property
g-saracca Jun 18, 2024
683ede2
tests fix
ErykKul Jun 21, 2024
74c6f80
improved test coverage
ErykKul Jun 21, 2024
fb8b4aa
lint fix
ErykKul Jun 21, 2024
7b8e727
improved coverage
ErykKul Jun 21, 2024
0f662a1
improved coverage even more
ErykKul Jun 21, 2024
b4a5962
better istanbul ignores
ErykKul Jun 21, 2024
654e2bc
removed sanity check for better coverage
ErykKul Jun 21, 2024
9231f2d
added translattions
ErykKul Jun 21, 2024
caf1a3e
translations
ErykKul Jun 24, 2024
7a53222
Merge branch 'develop' into feature/417-integrate-file-upload-page-wi…
ErykKul Jun 24, 2024
8b87197
calling real API for file uploads put in comment
ErykKul Jun 24, 2024
a44e4db
integration with the upload use case
ErykKul Jun 25, 2024
0a99c59
feat: update to new naming of imports and add method to mocks repos
g-saracca Jun 19, 2024
9387934
better selection mechanics for the uploaded files
ErykKul Jun 27, 2024
2860e0d
added save button at the bottom
ErykKul Jun 27, 2024
a13cdc2
removed dot
ErykKul Jun 27, 2024
146f4f4
lint fix
ErykKul Jun 27, 2024
e1402b3
fixed tests
ErykKul Jun 27, 2024
8c0c6ce
small margin between files
ErykKul Jun 27, 2024
2058851
flaky test
ErykKul Jun 27, 2024
5efb5d2
added add tags menu action
ErykKul Jun 27, 2024
f458d79
lint fix
ErykKul Jun 27, 2024
d786d9c
improved coverage
ErykKul Jun 27, 2024
be645cd
increased coverage
ErykKul Jun 27, 2024
4044038
file form improvements
ErykKul Jun 28, 2024
2ddb63e
removed click listener on the file
ErykKul Jun 28, 2024
3867fa7
improved coverage
ErykKul Jun 28, 2024
2dcea45
fixed add tags to selected files from menu action
ErykKul Jul 1, 2024
804bbfd
replaced SelectMultiple with a basic select input
ErykKul Jul 1, 2024
400cefc
cleanup after removal of the tag options modal
ErykKul Jul 1, 2024
e5e95ab
tag changes
ErykKul Jul 1, 2024
ecafcbb
updated select tags components
ErykKul Jul 1, 2024
84b6e08
adding tags improvements
ErykKul Jul 1, 2024
96d6302
removed unused component
ErykKul Jul 1, 2024
429b1ca
tests fix
ErykKul Jul 2, 2024
b63bfb8
improved coverage
ErykKul Jul 2, 2024
e3ac62a
moved file holder to models
ErykKul Jul 16, 2024
fdd9bb6
removed log line
ErykKul Jul 16, 2024
aa98151
improved syntax in css for grid-template-columns
ErykKul Jul 16, 2024
43ea8f8
removed important keyword and renamed vars ending with _cb to ending …
ErykKul Jul 16, 2024
9b5fa4d
restored the important key in css
ErykKul Jul 16, 2024
6a4e058
padding-block i.s.o. padding-top and padding-bottom
ErykKul Jul 16, 2024
be16f40
format and empty line at the end of css
ErykKul Jul 16, 2024
9770b27
replaced float:right with display:flex nad justify-content:flex-end
ErykKul Jul 16, 2024
245e08d
removed commented-out defensive programming code (if not commented ou…
ErykKul Jul 16, 2024
ddf3cbf
added empty line at the end of css file
ErykKul Jul 16, 2024
022609f
padding-block
ErykKul Jul 16, 2024
0098925
rename: o -> tagName
ErykKul Jul 16, 2024
948f219
removed unused colors import
ErykKul Jul 16, 2024
3d25038
rename: tag -> newCustomTag
ErykKul Jul 16, 2024
d9cdfb2
removed float:right
ErykKul Jul 16, 2024
8219be4
aria-label select all for checkbox
ErykKul Jul 16, 2024
efcb923
modals no longer in div
ErykKul Jul 16, 2024
cd89db2
re-added sanity check
ErykKul Jul 17, 2024
bb68210
Merge branch 'develop' into feature/417-integrate-file-upload-page-wi…
ErykKul Jul 17, 2024
7d889e4
add uploaded file workaround until js-dataverse implementation is fin…
ErykKul Jul 20, 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
62 changes: 60 additions & 2 deletions public/locales/en/uploadDatasetFiles.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,64 @@
{
"breadcrumbActionItem": "Upload files",
"cancel": "Cancel upload",
"info": "Drag and drop files here.",
"select": "Select files to add"
"info": "Drag and drop files and/or directories here.",
"select": "Select files to add",
"delete": "Delete",
"save": "Save",
"saveUploaded": "Save uploaded files",
"uploadedFileSize": "Uploaded file size",
"restricted": "Restricted",
"tags": {
"documentation": "Documentation",
"data": "Data",
"code": "Code",
"editTagOptions": "Edit tag options",
"customFileTag": "Custom file tag",
"creatingNewTag": "Creating a new tag will add it as a tag option for all files in this dataset.",
"addNewTag": "Add new file tag...",
"availableTagOptions": "Available tag options: ",
"apply": "Apply",
"close": "Close",
"addCustomTag": "Add new custom file tag..."
},
"restriction": {
"restrictAccess": "Restrict Access",
"restrictionInfoP1": "Restricting limits access to published files. People who want to use the restricted files can request access by default. If you disable request access, you must add information about access to the Terms of Access field.",
"restrictionInfoP2": "Learn about restricting files and dataset access in the User Guide.",
"termsOfAccess": "Terms of Access for Restricted Files",
"enableAccessRequest": "Enable access request",
"saveChanges": "Save Changes",
"cancelChanges": "Cancel Changes"
},
"fileForm": {
"fileName": "File name",
"filePath": "File path",
"description": "Description",
"tags": "Tags",
"selectTags": "Select tags",
"editTagOptions": "Edit tag options",
"plus": "Add new tag option"
},
"filesHeader": {
"save": "Save",
"cancel": "Cancel",
"editFiles": "Edit files",
"restrict": "Restrict",
"unrestrict": "Unrestrict",
"filesUploaded_one": "{{count}} file uploaded",
"filesUploaded_other": "{{count}} files uploaded",
"filesSelected_one": "{{count}} file selected",
"filesSelected_other": "{{count}} files selected",
"deleteSelected": "Delete selected",
"addTagsToSelected": "Add tags to selected",
"addTags": "Add tags",
"selectAll": "Select all"
},
"addTags": {
"title": "Add tags to selected files",
"customTag": "Custom tag",
"selectTags": "Select tags to add",
"saveChanges": "Save Changes",
"cancelChanges": "Cancel Changes"
}
}
89 changes: 75 additions & 14 deletions src/files/domain/models/FileUploadState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,26 @@ import { FileSize, FileSizeUnit } from './FileMetadata'

export interface FileUploadState {
progress: number
storageId?: string
progressHidden: boolean
fileSizeString: string
fileSize: number
fileLastModified: number
failed: boolean
done: boolean
removed: boolean
fileName: string
fileDir: string
fileType: string
key: string
description?: string
tags: string[]
restricted: boolean
}

export interface FileUploaderState {
state: Map<string, FileUploadState>
uploaded: FileUploadState[]
}

export class FileUploadTools {
Expand All @@ -20,19 +31,28 @@ export class FileUploadTools {
const key = this.key(file)
const newValue: FileUploadState = {
progress: 0,
storageId: undefined,
progressHidden: true,
fileSizeString: new FileSize(file.size, FileSizeUnit.BYTES).toString(),
fileSize: file.size,
fileLastModified: file.lastModified,
failed: false,
done: false,
removed: false
removed: false,
fileName: file.name,
fileDir: this.toDir(file.webkitRelativePath),
fileType: file.type,
key: key,
tags: [],
restricted: false
}
newState.set(key, newValue)
})
return { state: newState }
return { state: newState, uploaded: this.toUploaded(newState) }
}

static key(file: File): string {
return file.webkitRelativePath + file.name
return file.webkitRelativePath ? file.webkitRelativePath : file.name
}

static get(file: File, state: FileUploaderState): FileUploadState {
Expand All @@ -44,28 +64,50 @@ export class FileUploadTools {
progress: 0,
progressHidden: true,
fileSizeString: new FileSize(file.size, FileSizeUnit.BYTES).toString(),
fileSize: file.size,
fileLastModified: file.lastModified,
failed: false,
done: false,
removed: false
removed: false,
fileName: file.name,
fileDir: this.toDir(file.webkitRelativePath),
fileType: file.type,
key: this.key(file),
tags: [],
restricted: false
}
}

static progress(file: File, now: number, oldState: FileUploaderState): FileUploaderState {
const [newState, newValue] = this.toNewState(file, oldState)
newValue.progress = now
return newState
const fileUploadState = oldState.state.get(this.key(file))
if (fileUploadState) {
fileUploadState.progress = now
}
return { state: oldState.state, uploaded: this.toUploaded(oldState.state) }
}

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

static failed(file: File, oldState: FileUploaderState): FileUploaderState {
const [newState, newValue] = this.toNewState(file, oldState)
newValue.failed = true
return newState
const fileUploadState = oldState.state.get(this.key(file))
if (fileUploadState) {
fileUploadState.failed = true
}
return { state: oldState.state, uploaded: this.toUploaded(oldState.state) }
}

static done(file: File, oldState: FileUploaderState): FileUploaderState {
const [newState, newValue] = this.toNewState(file, oldState)
newValue.done = true
return newState
const fileUploadState = oldState.state.get(this.key(file))
if (fileUploadState) {
fileUploadState.done = true
}
return { state: oldState.state, uploaded: this.toUploaded(oldState.state) }
}

static removed(file: File, oldState: FileUploaderState): FileUploaderState {
Expand All @@ -80,12 +122,31 @@ export class FileUploadTools {
return newState
}

static delete(file: File, oldState: FileUploaderState): FileUploaderState {
oldState.state.delete(this.key(file))
return { state: oldState.state, uploaded: this.toUploaded(oldState.state) }
}

private static toNewState(
file: File,
oldState: FileUploaderState
): [FileUploaderState, FileUploadState] {
const newValue = this.get(file, oldState)
oldState.state.set(this.key(file), newValue)
return [{ state: oldState.state }, newValue]
return [{ state: oldState.state, uploaded: this.toUploaded(oldState.state) }, newValue]
}

private static toUploaded(state: Map<string, FileUploadState>): FileUploadState[] {
return Array.from(state.values())
.filter((x) => !x.removed && x.done)
.sort((a, b) => (a.fileDir + a.fileName).localeCompare(b.fileDir + b.fileName))
}

private static toDir(relativePath: string): string {
const parts = relativePath.split('/')
if (parts.length > 0) {
return parts.slice(0, parts.length - 1).join('/')
}
return relativePath
}
}
7 changes: 5 additions & 2 deletions src/files/domain/repositories/FileRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ import { DatasetVersion, DatasetVersionNumber } from '../../../dataset/domain/mo
import { FilePaginationInfo } from '../models/FilePaginationInfo'
import { FilePreview } from '../models/FilePreview'
import { FilesWithCount } from '../models/FilesWithCount'
import { FileHolder } from './File'
import { FileHolder } from '../models/FileHolder'
import { FileUploadState } from '../models/FileUploadState'

export interface FileRepository {
getAllByDatasetPersistentId: (
Expand Down Expand Up @@ -38,6 +39,8 @@ export interface FileRepository {
datasetId: number | string,
file: FileHolder,
progress: (now: number) => void,
abortController: AbortController
abortController: AbortController,
storageIdSetter: (storageId: string) => void
) => Promise<void>
addUploadedFile: (datasetId: number | string, files: FileUploadState[]) => Promise<void[]>
}
16 changes: 16 additions & 0 deletions src/files/domain/useCases/addUploadedFiles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { FileUploadState } from '../models/FileUploadState'
import { FileRepository } from '../repositories/FileRepository'

export function addUploadedFiles(
fileRepository: FileRepository,
datasetId: number | string,
files: FileUploadState[],
done: () => void
): void {
fileRepository
.addUploadedFile(datasetId, files)
.catch((error: Error) => {
throw new Error(error.message)
})
.finally(done)
}
9 changes: 5 additions & 4 deletions src/files/domain/useCases/uploadFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ export function uploadFile(
file: File,
done: () => void,
failed: () => void,
progress: (now: number) => void
progress: (now: number) => void,
storageIdSetter: (storageId: string) => void
): () => void {
const controller = new AbortController()
fileRepository
.uploadFile(datasetId, { file: file }, progress, controller)
.then(() => done())
.catch(() => failed())
.uploadFile(datasetId, { file: file }, progress, controller, storageIdSetter)
.then(done)
.catch(failed)
return () => controller.abort()
}
55 changes: 48 additions & 7 deletions src/files/infrastructure/FileJSDataverseRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import {
getFileDataTables,
getFileDownloadCount,
getFileUserPermissions,
uploadFile as jsUploadFile,
addUploadedFileToDataset,
ReadError
} from '@iqss/dataverse-client-javascript'
import { FileCriteria } from '../domain/models/FileCriteria'
Expand All @@ -29,7 +31,8 @@ import { JSFileMetadataMapper } from './mappers/JSFileMetadataMapper'
import { FilePermissions } from '../domain/models/FilePermissions'
import { JSFilePermissionsMapper } from './mappers/JSFilePermissionsMapper'
import { FilesWithCount } from '../domain/models/FilesWithCount'
import { FileHolder } from '../domain/repositories/File'
import { FileHolder } from '../domain/models/FileHolder'
import { FileUploadState } from '../domain/models/FileUploadState'

const includeDeaccessioned = true

Expand Down Expand Up @@ -284,12 +287,50 @@ export class FileJSDataverseRepository implements FileRepository {
}

uploadFile(
_datasetId: number | string,
_file: FileHolder,
_progress: (now: number) => void,
_abortController: AbortController
datasetId: number | string,
file: FileHolder,
progress: (now: number) => void,
abortController: AbortController,
storageIdSetter: (storageId: string) => void
): Promise<void> {
// TODO:
return new Promise(() => {})
return jsUploadFile
.execute(datasetId, file.file, progress, abortController)
.then(storageIdSetter)
.catch((error: ReadError) => {
throw new Error(error.message)
})
}

addUploadedFile(datasetId: number | string, files: FileUploadState[]): Promise<void[]> {
const all: Promise<void>[] = []
files.forEach((file) => {
const f: FileHolder = {
file: {
lastModified: file.fileLastModified,
name: file.fileName,
webkitRelativePath: file.fileDir ? file.fileDir + '/' + file.fileName : file.fileName,
size: file.fileSize,
type: file.fileType,
arrayBuffer: function (): Promise<ArrayBuffer> {
ErykKul marked this conversation as resolved.
Show resolved Hide resolved
throw new Error('Function not implemented.')
},
slice: function (
_start?: number | undefined,
_end?: number | undefined,
_contentType?: string | undefined
): Blob {
throw new Error('Function not implemented.')
},
stream: function (): ReadableStream<Uint8Array> {
throw new Error('Function not implemented.')
},
text: function (): Promise<string> {
throw new Error('Function not implemented.')
}
}
}
all.push(addUploadedFileToDataset.execute(datasetId, f.file, file.storageId as string))
})
return Promise.all(all)
}
}
Loading
Loading