@@ -84,28 +84,31 @@ export async function upload_file(
|
||||
token: string,
|
||||
file: UploadFile,
|
||||
onProgress: (progressEvent: ProgressEvent) => void
|
||||
): Promise<Responses.Success | Responses.Error> {
|
||||
): Promise<[Responses.Success | Responses.Error, boolean]> {
|
||||
const node = await create_file(token, file.parent, file.file.name);
|
||||
if (isErrorResponse(node)) return node;
|
||||
if (isErrorResponse(node)) return [node, false];
|
||||
if ('exists' in node && !node.isFile)
|
||||
return { statusCode: 400, message: 'File exists as folder' };
|
||||
return [{ statusCode: 400, message: 'File exists as folder' }, false];
|
||||
|
||||
return axios
|
||||
.post(`/api/fs/upload/${node.id}`, file.file, {
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + token,
|
||||
'Content-type': 'multipart/form-data'
|
||||
},
|
||||
onUploadProgress: onProgress
|
||||
})
|
||||
.then((res) => {
|
||||
console.log(res);
|
||||
return res.data;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
return err.response.data;
|
||||
});
|
||||
return [
|
||||
await axios
|
||||
.post(`/api/fs/upload/${node.id}`, file.file, {
|
||||
headers: {
|
||||
Authorization: 'Bearer ' + token,
|
||||
'Content-type': 'multipart/form-data'
|
||||
},
|
||||
onUploadProgress: onProgress
|
||||
})
|
||||
.then((res) => {
|
||||
console.log(res);
|
||||
return res.data;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
return err.response.data;
|
||||
}),
|
||||
'exists' in node
|
||||
];
|
||||
}
|
||||
|
||||
export function download_file(token: string, id: number) {
|
||||
|
||||
@@ -48,7 +48,7 @@ async function startDelete() {
|
||||
await resp.body.pipeTo(logWriter);
|
||||
} catch (err) {
|
||||
log.value += `Error: ${err}\n`;
|
||||
logInst.value?.scrollTo({ position: 'top' });
|
||||
logInst.value?.scrollTo({ position: 'bottom', slient: true });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,6 +115,8 @@ watch(
|
||||
v-else-if="fileType === fileTypes.IMAGE && src !== ''"
|
||||
:src="src"
|
||||
:alt="node.name"
|
||||
:img-props="{ style: 'max-width: 80vw; max-height: 70vh;' }"
|
||||
object-fit="contain"
|
||||
/>
|
||||
<iframe
|
||||
v-else-if="fileType === fileTypes.IFRAME && src !== ''"
|
||||
@@ -137,4 +139,4 @@ watch(
|
||||
</n-grid>
|
||||
</template>
|
||||
|
||||
<style scoped></style>
|
||||
<style scoped lang="scss"></style>
|
||||
|
||||
@@ -8,6 +8,7 @@ import filesize from 'filesize';
|
||||
|
||||
const props = defineProps<{
|
||||
file: UploadFile;
|
||||
abort: boolean;
|
||||
}>();
|
||||
|
||||
const progress = ref(0);
|
||||
@@ -15,13 +16,26 @@ const percentage = ref(0);
|
||||
const err = ref('');
|
||||
const status = ref<Status>('info');
|
||||
const shown = ref(true);
|
||||
const existed = ref(false);
|
||||
|
||||
async function startUpload(token: string, done: () => void) {
|
||||
const resp = await FS.upload_file(token, props.file, (e) => {
|
||||
let sendDone = false;
|
||||
if (props.abort) {
|
||||
done();
|
||||
shown.value = false;
|
||||
return;
|
||||
}
|
||||
const resp_tuple = await FS.upload_file(token, props.file, (e) => {
|
||||
progress.value = e.loaded;
|
||||
percentage.value = (e.loaded / e.total) * 100;
|
||||
if (e.loaded == e.total) done();
|
||||
if (e.loaded == e.total) {
|
||||
sendDone = true;
|
||||
done();
|
||||
}
|
||||
});
|
||||
const resp = resp_tuple[0];
|
||||
existed.value = resp_tuple[1];
|
||||
if (!sendDone) done();
|
||||
percentage.value = 100;
|
||||
if (isErrorResponse(resp)) {
|
||||
err.value = resp.message ?? 'Error';
|
||||
@@ -60,6 +74,12 @@ defineExpose({
|
||||
<div v-else-if="err !== ''">
|
||||
{{ file.fullName }} - Error: {{ err }}
|
||||
</div>
|
||||
<div v-else-if="existed">
|
||||
{{ file.fullName }} - Old file overridden
|
||||
</div>
|
||||
<div v-else-if="status !== 'success'">
|
||||
{{ file.fullName }} - Processing...
|
||||
</div>
|
||||
<div v-else>{{ file.fullName }} - Completed</div>
|
||||
<n-progress
|
||||
type="line"
|
||||
|
||||
@@ -3,20 +3,29 @@ import type { TokenInjectType, UploadFile } from '@/api';
|
||||
import { ref, inject } from 'vue';
|
||||
import { update_token } from '@/api';
|
||||
import UploadEntry from '@/components/UploadDialog/UploadEntry.vue';
|
||||
import { NCard } from 'naive-ui';
|
||||
import { NCard, NButton } from 'naive-ui';
|
||||
import semaphore from 'semaphore';
|
||||
|
||||
const jwt = inject<TokenInjectType>('jwt') as TokenInjectType;
|
||||
|
||||
const entries = ref<typeof UploadEntry[]>([]);
|
||||
|
||||
const abortUpload = ref(false);
|
||||
|
||||
async function startUpload() {
|
||||
const token = await update_token(jwt);
|
||||
if (!token) return;
|
||||
const ents: typeof UploadEntry[] = entries.value;
|
||||
const allProms: Promise<void>[] = [];
|
||||
const uploadSem = semaphore(5);
|
||||
for (const entry of ents) {
|
||||
await new Promise<void>((resolve) =>
|
||||
allProms.push(entry.startUpload(token, resolve))
|
||||
allProms.push(
|
||||
new Promise<void>((resolve) => {
|
||||
uploadSem.take(async () => {
|
||||
await entry.startUpload(token, () => uploadSem.leave());
|
||||
resolve();
|
||||
});
|
||||
})
|
||||
);
|
||||
}
|
||||
await Promise.all(allProms);
|
||||
@@ -32,11 +41,13 @@ defineProps<{
|
||||
|
||||
<template>
|
||||
<n-card title="Uploading files" style="margin: 20px">
|
||||
<n-button type="error" @click="abortUpload = true">Abort</n-button>
|
||||
<UploadEntry
|
||||
v-for="f in files"
|
||||
:key="f.file.name"
|
||||
ref="entries"
|
||||
:file="f"
|
||||
:abort="abortUpload"
|
||||
/>
|
||||
</n-card>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user