Skip to content

Commit

Permalink
Upload folder, switch from FileList to File[], fix #97
Browse files Browse the repository at this point in the history
  • Loading branch information
arildm committed Apr 3, 2024
1 parent 2c0a039 commit 9bacbaa
Show file tree
Hide file tree
Showing 12 changed files with 29 additions and 20 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ As this project is a user-facing application, the places in the semantic version
- A quick, brief resource listing view for admin [#146](https://github.com/spraakbanken/mink-frontend/issues/146)
- Group export files by folder [#95](https://github.com/spraakbanken/mink-frontend/issues/95)
- JWT request now has a 2s timeout and two retries [#124](https://github.com/spraakbanken/mink-frontend/issues/124)
- Upload an entire folder of source files [#97](https://github.com/spraakbanken/mink-frontend/issues/97)

### Changed

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"@vueuse/core": "^10.7.2",
"autoprefixer": "^10.4.7",
"axios": "^1",
"datatransfer-files-promise": "^2.0.0",
"eslint": "^8.15.0",
"filesize": "^10.0.6",
"js-yaml": "^4.1.0",
Expand Down
4 changes: 2 additions & 2 deletions src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,11 @@ class MinkApi {
/** @see https://ws.spraakbanken.gu.se/ws/mink/api-doc#tag/Manage-Sources/operation/uploadsources */
async uploadSources(
corpusId: string,
files: FileList,
files: File[],
onProgress?: ProgressHandler,
) {
const formData = new FormData();
[...files].forEach((file) => formData.append("files[]", file));
files.forEach((file) => formData.append("files[]", file));
const response = await this.axios.put<MinkResponse>(
"upload-sources",
formData,
Expand Down
2 changes: 1 addition & 1 deletion src/api/backend.composable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export default function useMinkBackend() {

const uploadSources = (
corpusId: string,
files: FileList,
files: File[],
onProgress?: ProgressHandler,
) =>
spin(
Expand Down
9 changes: 6 additions & 3 deletions src/components/FileDropArea.vue
Original file line number Diff line number Diff line change
@@ -1,24 +1,27 @@
<script setup lang="ts">
import { useI18n } from "vue-i18n";
import { getFilesFromDataTransferItems } from "datatransfer-files-promise";
import useMessenger from "@/message/messenger.composable";
import useDropToPage from "@/components/droptopage.composable";
const emit = defineEmits<{
(e: "drop", files: FileList): void;
(e: "drop", files: File[]): void;
}>();
const { alert } = useMessenger();
const { t } = useI18n();
function drop(event: DragEvent) {
async function drop(event: DragEvent) {
// On Chrome+Ubuntu, the file list may be empty for security reasons.
// See https://askubuntu.com/a/1411727
if (!event.dataTransfer?.files[0]) {
alert(t("upload.drop.empty"), "error");
return;
}
emit("drop", event.dataTransfer.files);
const files = await getFilesFromDataTransferItems(event.dataTransfer.items);
emit("drop", files);
}
const { isDragover } = useDropToPage(drop);
Expand Down
8 changes: 5 additions & 3 deletions src/components/FileUpload.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const props = defineProps<{
/**
* A function that presumably uploads given file(s) to the appropriate API.
*/
fileHandler: (files: FileList, onProgress: ProgressHandler) => Promise<void>;
fileHandler: (files: File[], onProgress: ProgressHandler) => Promise<void>;
primary?: boolean;
accept?: string;
multiple?: boolean;
Expand All @@ -27,13 +27,15 @@ async function handleFileInput(event: Event) {
throw new RangeError("No file found in the file input");
}
await handleUpload(fileInput.files!);
// Convert from FileList to File[]
const files = [...fileInput.files!];
await handleUpload(files);
// Empty the input value to enable selecting the same file again.
fileInput.value = "";
}
/** Call upload function. */
async function handleUpload(files: FileList) {
async function handleUpload(files: File[]) {
clear();
try {
await props.fileHandler(files, onProgress);
Expand Down
4 changes: 2 additions & 2 deletions src/corpus/createCorpus.composable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default function useCreateCorpus() {
return corpusId;
}

async function createFromUpload(files: FileList) {
async function createFromUpload(files: File[]) {
const corpusId = await createCorpus().catch(alertError);
if (!corpusId) return;

Expand Down Expand Up @@ -70,7 +70,7 @@ export default function useCreateCorpus() {

// Like the `uploadSources` in `sources.composable.ts` but takes `corpusId` as argument.
async function uploadSources(
files: FileList,
files: File[],
corpusId: string,
onProgress?: ProgressHandler,
) {
Expand Down
7 changes: 2 additions & 5 deletions src/corpus/sources/SourceUpload.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import FileUpload from "@/components/FileUpload.vue";
import type { ProgressHandler } from "@/api/api.types";
const props = defineProps<{
fileHandler?: (files: FileList) => Promise<void>;
fileHandler?: (files: File[]) => Promise<void>;
primary?: boolean;
}>();
Expand All @@ -24,10 +24,7 @@ const extensionsAccept = computed(() =>
extensions.value?.map((ext) => `.${ext}`).join(),
);
async function defaultFileHandler(
files: FileList,
onProgress: ProgressHandler,
) {
async function defaultFileHandler(files: File[], onProgress: ProgressHandler) {
const requests = [uploadSources(files, onProgress).catch(alertError)];
// Also update format setting in config if needed
Expand Down
2 changes: 1 addition & 1 deletion src/corpus/sources/sources.composable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export default function useSources(corpusId: string) {
return mink.downloadPlaintext(corpusId, source.name).catch(alertError);
}

async function uploadSources(files: FileList, onProgress?: ProgressHandler) {
async function uploadSources(files: File[], onProgress?: ProgressHandler) {
await mink.uploadSources(corpusId, files, onProgress);
loadSources();
}
Expand Down
2 changes: 1 addition & 1 deletion src/library/LibraryView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ requireAuthentication(() => {
}
});
async function createCorpusFromFiles(files: FileList) {
async function createCorpusFromFiles(files: File[]) {
await spin(createFromUpload(files), "create");
}
</script>
Expand Down
4 changes: 2 additions & 2 deletions src/metadata/MetadataOverview.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ const { uploadYaml } = useMetadata(resourceId);
const metadata = computed(() => resourceStore.metadatas[resourceId]);
async function uploadMetadata(files: FileList) {
const yaml = await files.item(0)!.text();
async function uploadMetadata(files: File[]) {
const yaml = await files[0]!.text();
await uploadYaml(yaml);
}
</script>
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1494,6 +1494,11 @@ data-view-byte-offset@^1.0.0:
es-errors "^1.3.0"
is-data-view "^1.0.1"

datatransfer-files-promise@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/datatransfer-files-promise/-/datatransfer-files-promise-2.0.0.tgz#510e4cd22ec15a2d68942b37e070e18abc948bee"
integrity sha512-an4ngC5aqKsm13BsJxMctJWD6v8FCzU7WOoOljunNdpxAGFYBBicjmsvTCVn/IYgHTE/FdXEhzJlLJBVVsuByA==

de-indent@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"
Expand Down

0 comments on commit 9bacbaa

Please sign in to comment.