refactor: separate selectAndUploadFile and uploadFile functions (#2085)

This commit is contained in:
Aman Harwara
2022-12-04 11:11:37 +05:30
committed by GitHub
parent 2175c9cdcb
commit 90e10c76f7
9 changed files with 108 additions and 113 deletions

View File

@@ -114,7 +114,7 @@ const ContentListView = forwardRef<HTMLDivElement, Props>(
}, [selectedTag, application, onPanelWidthLoad])
const fileDropCallback = useCallback(
async (files: FileItem[]) => {
async (file: FileItem) => {
const currentTag = navigationController.selected
if (!currentTag) {
@@ -126,9 +126,7 @@ const ContentListView = forwardRef<HTMLDivElement, Props>(
return
}
files.forEach(async (file) => {
await linkingController.linkItems(file, currentTag)
})
await linkingController.linkItems(file, currentTag)
},
[navigationController, linkingController],
)
@@ -170,7 +168,7 @@ const ContentListView = forwardRef<HTMLDivElement, Props>(
return
}
void filesController.uploadNewFile()
void filesController.selectAndUploadNewFiles()
} else {
await createNewNote()
toggleAppPane(AppPaneId.Editor)

View File

@@ -11,7 +11,7 @@ import Portal from './Portal/Portal'
type FileDragTargetData = {
tooltipText: string
callback: (files: FileItem[]) => void
callback: (files: FileItem) => void
}
type FileDnDContextData = {
@@ -203,14 +203,14 @@ const FileDragNDropProvider = ({ application, children, featuresController, file
return
}
const uploadedFiles = await filesController.uploadNewFile(fileOrHandle)
const uploadedFile = await filesController.uploadNewFile(fileOrHandle)
if (!uploadedFiles) {
if (!uploadedFile) {
return
}
if (closestDragTarget && dragTargets.current.has(closestDragTarget)) {
dragTargets.current.get(closestDragTarget)?.callback(uploadedFiles)
dragTargets.current.get(closestDragTarget)?.callback(uploadedFile)
}
})

View File

@@ -51,10 +51,8 @@ const FileViewWithoutProtection = ({ application, viewControllerManager, file }:
if (target) {
addDragTarget(target, {
tooltipText: 'Drop your files to upload and link them to the current file',
callback(files) {
files.forEach(async (uploadedFile) => {
await viewControllerManager.linkingController.linkItems(uploadedFile, file)
})
async callback(uploadedFile) {
await viewControllerManager.linkingController.linkItems(uploadedFile, file)
},
})
}

View File

@@ -63,13 +63,9 @@ const LinkedItemsPanel = ({
return
}
const uploadedFiles = await filesController.uploadNewFile()
if (uploadedFiles && uploadedFiles.length) {
uploadedFiles.forEach((file) => {
void linkItemToSelectedItem(file)
})
}
void filesController.selectAndUploadNewFiles((file) => {
void linkItemToSelectedItem(file)
})
}
return (

View File

@@ -20,11 +20,9 @@ const NoteViewFileDropTarget = ({ note, linkingController, noteViewElement, file
if (target) {
addDragTarget(target, {
tooltipText: 'Drop your files to upload and link them to the current note',
callback: (files) => {
files.forEach(async (uploadedFile) => {
await linkingController.linkItems(note, uploadedFile)
filesController.notifyObserversOfUploadedFileLinkingToCurrentNote(uploadedFile.uuid)
})
callback: async (uploadedFile) => {
await linkingController.linkItems(note, uploadedFile)
filesController.notifyObserversOfUploadedFileLinkingToCurrentNote(uploadedFile.uuid)
},
})
}

View File

@@ -28,11 +28,9 @@ export default function FilePlugin(): JSX.Element | null {
const uploadFilesList = (files: FileList) => {
Array.from(files).forEach(async (file) => {
try {
const uploadedFiles = await filesController.uploadNewFile(file)
if (uploadedFiles) {
uploadedFiles.forEach((uploadedFile) => {
editor.dispatchCommand(INSERT_FILE_COMMAND, uploadedFile.uuid)
})
const uploadedFile = await filesController.uploadNewFile(file)
if (uploadedFile) {
editor.dispatchCommand(INSERT_FILE_COMMAND, uploadedFile.uuid)
}
} catch (error) {
console.error(error)

View File

@@ -178,10 +178,8 @@ export const TagsListItem: FunctionComponent<Props> = observer(
if (target) {
addDragTarget(target, {
tooltipText: `Drop your files to upload and link them to tag "${tag.title}"`,
callback(files) {
files.forEach(async (file) => {
await linkingController.linkItems(file, tag)
})
async callback(file) {
await linkingController.linkItems(file, tag)
},
})
}

View File

@@ -56,6 +56,10 @@ export class FilesController extends AbstractViewController<FilesControllerEvent
showProtectedOverlay = false
fileContextMenuLocation: FileContextMenuLocation = { x: 0, y: 0 }
shouldUseStreamingReader = StreamingFileSaver.available()
reader = this.shouldUseStreamingReader ? StreamingFileReader : ClassicFileReader
maxFileSize = this.reader.maximumFileSize()
override deinit(): void {
super.deinit()
;(this.notesController as unknown) = undefined
@@ -318,98 +322,103 @@ export class FilesController extends AbstractViewController<FilesControllerEvent
}
}
public async uploadNewFile(fileOrHandle?: File | FileSystemFileHandle) {
alertIfFileExceedsSizeLimit = (file: File): boolean => {
if (!this.shouldUseStreamingReader && this.maxFileSize && file.size >= this.maxFileSize) {
this.application.alertService
.alert(
`This file exceeds the limits supported in this browser. To upload files greater than ${
this.maxFileSize / BYTES_IN_ONE_MEGABYTE
}MB, please use the desktop application or the Chrome browser.`,
`Cannot upload file "${file.name}"`,
)
.catch(console.error)
return true
}
return false
}
public async selectAndUploadNewFiles(callback?: (file: FileItem) => void) {
const selectedFiles = await this.reader.selectFiles()
selectedFiles.forEach(async (file) => {
if (this.alertIfFileExceedsSizeLimit(file)) {
return
}
const uploadedFile = await this.uploadNewFile(file)
if (uploadedFile && callback) {
callback(uploadedFile)
}
})
}
public async uploadNewFile(fileOrHandle: File | FileSystemFileHandle): Promise<FileItem | undefined> {
let toastId = ''
try {
const minimumChunkSize = this.application.files.minimumChunkSize()
const shouldUseStreamingReader = StreamingFileReader.available()
const picker = shouldUseStreamingReader ? StreamingFileReader : ClassicFileReader
const maxFileSize = picker.maximumFileSize()
const selectedFiles =
fileOrHandle instanceof File
? [fileOrHandle]
: shouldUseStreamingReader && fileOrHandle instanceof FileSystemFileHandle
? await StreamingFileReader.getFilesFromHandles([fileOrHandle])
: await picker.selectFiles()
if (selectedFiles.length === 0) {
if (fileOrHandle instanceof FileSystemFileHandle && !this.shouldUseStreamingReader) {
return
}
const uploadedFiles: FileItem[] = []
const fileToUpload = fileOrHandle instanceof File ? fileOrHandle : await fileOrHandle.getFile()
for (const file of selectedFiles) {
if (!shouldUseStreamingReader && maxFileSize && file.size >= maxFileSize) {
this.application.alertService
.alert(
`This file exceeds the limits supported in this browser. To upload files greater than ${
maxFileSize / BYTES_IN_ONE_MEGABYTE
}MB, please use the desktop application or the Chrome browser.`,
`Cannot upload file "${file.name}"`,
)
.catch(console.error)
continue
}
if (this.alertIfFileExceedsSizeLimit(fileToUpload)) {
return
}
const operation = await this.application.files.beginNewFileUpload(file.size)
const operation = await this.application.files.beginNewFileUpload(fileToUpload.size)
if (operation instanceof ClientDisplayableError) {
addToast({
type: ToastType.Error,
message: 'Unable to start upload session',
})
throw new Error('Unable to start upload session')
}
const initialProgress = operation.getProgress().percentComplete
toastId = addToast({
type: ToastType.Progress,
message: `Uploading file "${file.name}" (${initialProgress}%)`,
progress: initialProgress,
})
const onChunk: OnChunkCallbackNoProgress = async ({ data, index, isLast }) => {
await this.application.files.pushBytesForUpload(operation, data, index, isLast)
const percentComplete = Math.round(operation.getProgress().percentComplete)
updateToast(toastId, {
message: `Uploading file "${file.name}" (${percentComplete}%)`,
progress: percentComplete,
})
}
const fileResult = await picker.readFile(file, minimumChunkSize, onChunk)
if (!fileResult.mimeType) {
const { ext } = parseFileName(file.name)
fileResult.mimeType = await this.application.getArchiveService().getMimeType(ext)
}
const uploadedFile = await this.application.files.finishUpload(operation, fileResult)
if (uploadedFile instanceof ClientDisplayableError) {
addToast({
type: ToastType.Error,
message: 'Unable to close upload session',
})
throw new Error('Unable to close upload session')
}
uploadedFiles.push(uploadedFile)
dismissToast(toastId)
if (operation instanceof ClientDisplayableError) {
addToast({
type: ToastType.Success,
message: `Uploaded file "${uploadedFile.name}"`,
type: ToastType.Error,
message: 'Unable to start upload session',
})
throw new Error('Unable to start upload session')
}
const initialProgress = operation.getProgress().percentComplete
toastId = addToast({
type: ToastType.Progress,
message: `Uploading file "${fileToUpload.name}" (${initialProgress}%)`,
progress: initialProgress,
})
const onChunk: OnChunkCallbackNoProgress = async ({ data, index, isLast }) => {
await this.application.files.pushBytesForUpload(operation, data, index, isLast)
const percentComplete = Math.round(operation.getProgress().percentComplete)
updateToast(toastId, {
message: `Uploading file "${fileToUpload.name}" (${percentComplete}%)`,
progress: percentComplete,
})
}
return uploadedFiles
const fileResult = await this.reader.readFile(fileToUpload, minimumChunkSize, onChunk)
if (!fileResult.mimeType) {
const { ext } = parseFileName(fileToUpload.name)
fileResult.mimeType = await this.application.getArchiveService().getMimeType(ext)
}
const uploadedFile = await this.application.files.finishUpload(operation, fileResult)
if (uploadedFile instanceof ClientDisplayableError) {
addToast({
type: ToastType.Error,
message: 'Unable to close upload session',
})
throw new Error('Unable to close upload session')
}
dismissToast(toastId)
addToast({
type: ToastType.Success,
message: `Uploaded file "${uploadedFile.name}"`,
})
return uploadedFile
} catch (error) {
console.error(error)

View File

@@ -80,7 +80,7 @@ export class MomentsService extends AbstractViewController {
}
}
public async takePhoto(): Promise<FileItem[] | undefined> {
public async takePhoto(): Promise<FileItem | undefined> {
const toastId = addToast({
type: ToastType.Loading,
message: 'Capturing Moment...',
@@ -123,7 +123,7 @@ export class MomentsService extends AbstractViewController {
const defaultTag = this.getDefaultTag()
if (defaultTag && uploadedFile) {
void this.application.linkingController.linkItems(uploadedFile[0], defaultTag)
void this.application.linkingController.linkItems(uploadedFile, defaultTag)
}
stopCameraStream(canvas, video, stream)