refactor as setup
This commit is contained in:
parent
551631d8e2
commit
7c713f27fa
@ -3,6 +3,7 @@ import { useFileStore } from "./file";
|
|||||||
import { files as api } from "@/api";
|
import { files as api } from "@/api";
|
||||||
import { throttle } from "lodash-es";
|
import { throttle } from "lodash-es";
|
||||||
import buttons from "@/utils/buttons";
|
import buttons from "@/utils/buttons";
|
||||||
|
import { computed, ref } from "vue";
|
||||||
|
|
||||||
// TODO: make this into a user setting
|
// TODO: make this into a user setting
|
||||||
const UPLOADS_LIMIT = 5;
|
const UPLOADS_LIMIT = 5;
|
||||||
@ -25,186 +26,224 @@ function formatSize(bytes: number): string {
|
|||||||
return (bytes / k ** i).toFixed(2) + " " + sizes[i];
|
return (bytes / k ** i).toFixed(2) + " " + sizes[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
export const useUploadStore = defineStore("upload", {
|
export const useUploadStore = defineStore("upload", () => {
|
||||||
// convert to a function
|
//
|
||||||
state: (): {
|
// STATE
|
||||||
id: number;
|
//
|
||||||
sizes: number[];
|
|
||||||
progress: number[];
|
const id = ref<number>(0);
|
||||||
queue: UploadItem[];
|
const sizes = ref<number[]>([]);
|
||||||
uploads: Uploads;
|
const progress = ref<number[]>([]);
|
||||||
error: Error | null;
|
const queue = ref<UploadItem[]>([]);
|
||||||
} => ({
|
const uploads = ref<Uploads>({});
|
||||||
id: 0,
|
const error = ref<Error | null>(null);
|
||||||
sizes: [],
|
|
||||||
progress: [],
|
//
|
||||||
queue: [],
|
// GETTERS
|
||||||
uploads: {},
|
//
|
||||||
error: null,
|
|
||||||
}),
|
const getProgress = computed(() => {
|
||||||
getters: {
|
if (progress.value.length === 0) {
|
||||||
// user and jwt getter removed, no longer needed
|
return 0;
|
||||||
getProgress: (state) => {
|
}
|
||||||
if (state.progress.length === 0) {
|
|
||||||
return 0;
|
const totalSize = sizes.value.reduce((a, b) => a + b, 0);
|
||||||
|
const sum = progress.value.reduce((a, b) => a + b, 0);
|
||||||
|
return Math.ceil((sum / totalSize) * 100);
|
||||||
|
});
|
||||||
|
|
||||||
|
const getProgressDecimal = computed(() => {
|
||||||
|
if (progress.value.length === 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const totalSize = sizes.value.reduce((a, b) => a + b, 0);
|
||||||
|
const sum = progress.value.reduce((a, b) => a + b, 0);
|
||||||
|
return ((sum / totalSize) * 100).toFixed(2);
|
||||||
|
});
|
||||||
|
|
||||||
|
const getTotalProgressBytes = computed(() => {
|
||||||
|
if (progress.value.length === 0 || sizes.value.length === 0) {
|
||||||
|
return "0 Bytes";
|
||||||
|
}
|
||||||
|
const sum = progress.value.reduce((a, b) => a + b, 0);
|
||||||
|
return formatSize(sum);
|
||||||
|
});
|
||||||
|
|
||||||
|
const getTotalProgress = computed(() => {
|
||||||
|
return progress.value.reduce((a, b) => a + b, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
const getTotalSize = computed(() => {
|
||||||
|
if (sizes.value.length === 0) {
|
||||||
|
return "0 Bytes";
|
||||||
|
}
|
||||||
|
const totalSize = sizes.value.reduce((a, b) => a + b, 0);
|
||||||
|
return formatSize(totalSize);
|
||||||
|
});
|
||||||
|
|
||||||
|
const getTotalBytes = computed(() => {
|
||||||
|
return sizes.value.reduce((a, b) => a + b, 0);
|
||||||
|
});
|
||||||
|
|
||||||
|
const filesInUploadCount = computed(() => {
|
||||||
|
return Object.keys(uploads.value).length + queue.value.length;
|
||||||
|
});
|
||||||
|
|
||||||
|
const filesInUpload = computed(() => {
|
||||||
|
const files = [];
|
||||||
|
|
||||||
|
for (const index in uploads.value) {
|
||||||
|
const upload = uploads.value[index];
|
||||||
|
const id = upload.id;
|
||||||
|
const type = upload.type;
|
||||||
|
const name = upload.file.name;
|
||||||
|
const size = sizes.value[id];
|
||||||
|
const isDir = upload.file.isDir;
|
||||||
|
const p = isDir ? 100 : Math.ceil((progress.value[id] / size) * 100);
|
||||||
|
|
||||||
|
files.push({
|
||||||
|
id,
|
||||||
|
name,
|
||||||
|
progress: p,
|
||||||
|
type,
|
||||||
|
isDir,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return files.sort((a, b) => a.progress - b.progress);
|
||||||
|
});
|
||||||
|
|
||||||
|
//
|
||||||
|
// ACTIONS
|
||||||
|
//
|
||||||
|
|
||||||
|
const setProgress = ({ id, loaded }: { id: number; loaded: number }) => {
|
||||||
|
progress.value[id] = loaded;
|
||||||
|
};
|
||||||
|
|
||||||
|
const setError = (err: Error) => {
|
||||||
|
error.value = err;
|
||||||
|
};
|
||||||
|
|
||||||
|
const reset = () => {
|
||||||
|
id.value = 0;
|
||||||
|
sizes.value = [];
|
||||||
|
progress.value = [];
|
||||||
|
queue.value = [];
|
||||||
|
uploads.value = {};
|
||||||
|
error.value = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const addJob = (item: UploadItem) => {
|
||||||
|
queue.value.push(item);
|
||||||
|
sizes.value[id.value] = item.file.size;
|
||||||
|
id.value++;
|
||||||
|
};
|
||||||
|
|
||||||
|
const moveJob = () => {
|
||||||
|
const item = queue.value[0];
|
||||||
|
queue.value.shift();
|
||||||
|
uploads.value[item.id] = item;
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeJob = (id: number) => {
|
||||||
|
delete uploads.value[id];
|
||||||
|
};
|
||||||
|
|
||||||
|
const upload = (item: UploadItem) => {
|
||||||
|
const uploadsCount = Object.keys(uploads.value).length;
|
||||||
|
|
||||||
|
const isQueueEmpty = queue.value.length == 0;
|
||||||
|
const isUploadsEmpty = uploadsCount == 0;
|
||||||
|
|
||||||
|
if (isQueueEmpty && isUploadsEmpty) {
|
||||||
|
window.addEventListener("beforeunload", beforeUnload);
|
||||||
|
buttons.loading("upload");
|
||||||
|
}
|
||||||
|
|
||||||
|
addJob(item);
|
||||||
|
processUploads();
|
||||||
|
};
|
||||||
|
|
||||||
|
const finishUpload = (item: UploadItem) => {
|
||||||
|
setProgress({ id: item.id, loaded: item.file.size });
|
||||||
|
removeJob(item.id);
|
||||||
|
processUploads();
|
||||||
|
};
|
||||||
|
|
||||||
|
const processUploads = async () => {
|
||||||
|
const uploadsCount = Object.keys(uploads.value).length;
|
||||||
|
|
||||||
|
const isBelowLimit = uploadsCount < UPLOADS_LIMIT;
|
||||||
|
const isQueueEmpty = queue.value.length == 0;
|
||||||
|
const isUploadsEmpty = uploadsCount == 0;
|
||||||
|
|
||||||
|
const isFinished = isQueueEmpty && isUploadsEmpty;
|
||||||
|
const canProcess = isBelowLimit && !isQueueEmpty;
|
||||||
|
|
||||||
|
if (isFinished) {
|
||||||
|
const fileStore = useFileStore();
|
||||||
|
window.removeEventListener("beforeunload", beforeUnload);
|
||||||
|
buttons.success("upload");
|
||||||
|
reset();
|
||||||
|
fileStore.reload = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (canProcess) {
|
||||||
|
const item = queue.value[0];
|
||||||
|
moveJob();
|
||||||
|
|
||||||
|
if (item.file.isDir) {
|
||||||
|
await api.post(item.path).catch(setError);
|
||||||
|
} else {
|
||||||
|
const onUpload = throttle(
|
||||||
|
(event: ProgressEvent) =>
|
||||||
|
setProgress({
|
||||||
|
id: item.id,
|
||||||
|
loaded: event.loaded,
|
||||||
|
}),
|
||||||
|
100,
|
||||||
|
{ leading: true, trailing: false }
|
||||||
|
);
|
||||||
|
|
||||||
|
await api
|
||||||
|
.post(item.path, item.file.file as File, item.overwrite, onUpload)
|
||||||
|
.catch(setError);
|
||||||
}
|
}
|
||||||
|
|
||||||
const totalSize = state.sizes.reduce((a, b) => a + b, 0);
|
finishUpload(item);
|
||||||
const sum = state.progress.reduce((a, b) => a + b, 0);
|
}
|
||||||
return Math.ceil((sum / totalSize) * 100);
|
};
|
||||||
},
|
|
||||||
getProgressDecimal: (state) => {
|
|
||||||
if (state.progress.length === 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
const totalSize = state.sizes.reduce((a, b) => a + b, 0);
|
return {
|
||||||
const sum = state.progress.reduce((a, b) => a + b, 0);
|
// STATE
|
||||||
return ((sum / totalSize) * 100).toFixed(2);
|
id,
|
||||||
},
|
sizes,
|
||||||
getTotalProgressBytes: (state) => {
|
progress,
|
||||||
if (state.progress.length === 0 || state.sizes.length === 0) {
|
queue,
|
||||||
return "0 Bytes";
|
uploads,
|
||||||
}
|
error,
|
||||||
const sum = state.progress.reduce((a, b) => a + b, 0);
|
|
||||||
return formatSize(sum);
|
|
||||||
},
|
|
||||||
getTotalProgress: (state) => {
|
|
||||||
return state.progress.reduce((a, b) => a + b, 0);
|
|
||||||
},
|
|
||||||
getTotalSize: (state) => {
|
|
||||||
if (state.sizes.length === 0) {
|
|
||||||
return "0 Bytes";
|
|
||||||
}
|
|
||||||
const totalSize = state.sizes.reduce((a, b) => a + b, 0);
|
|
||||||
return formatSize(totalSize);
|
|
||||||
},
|
|
||||||
getTotalBytes: (state) => {
|
|
||||||
return state.sizes.reduce((a, b) => a + b, 0);
|
|
||||||
},
|
|
||||||
filesInUploadCount: (state) => {
|
|
||||||
return Object.keys(state.uploads).length + state.queue.length;
|
|
||||||
},
|
|
||||||
filesInUpload: (state) => {
|
|
||||||
const files = [];
|
|
||||||
|
|
||||||
for (const index in state.uploads) {
|
// GETTERS
|
||||||
const upload = state.uploads[index];
|
getProgress,
|
||||||
const id = upload.id;
|
getProgressDecimal,
|
||||||
const type = upload.type;
|
getTotalProgressBytes,
|
||||||
const name = upload.file.name;
|
getTotalProgress,
|
||||||
const size = state.sizes[id];
|
getTotalSize,
|
||||||
const isDir = upload.file.isDir;
|
getTotalBytes,
|
||||||
const progress = isDir
|
filesInUploadCount,
|
||||||
? 100
|
filesInUpload,
|
||||||
: Math.ceil((state.progress[id] / size) * 100);
|
|
||||||
|
|
||||||
files.push({
|
// ACTIONS
|
||||||
id,
|
setProgress,
|
||||||
name,
|
setError,
|
||||||
progress,
|
reset,
|
||||||
type,
|
addJob,
|
||||||
isDir,
|
moveJob,
|
||||||
});
|
removeJob,
|
||||||
}
|
upload,
|
||||||
|
finishUpload,
|
||||||
return files.sort((a, b) => a.progress - b.progress);
|
processUploads,
|
||||||
},
|
};
|
||||||
},
|
|
||||||
actions: {
|
|
||||||
// no context as first argument, use `this` instead
|
|
||||||
setProgress({ id, loaded }: { id: number; loaded: number }) {
|
|
||||||
this.progress[id] = loaded;
|
|
||||||
},
|
|
||||||
setError(error: Error) {
|
|
||||||
this.error = error;
|
|
||||||
},
|
|
||||||
reset() {
|
|
||||||
this.id = 0;
|
|
||||||
this.sizes = [];
|
|
||||||
this.progress = [];
|
|
||||||
this.queue = [];
|
|
||||||
this.uploads = {};
|
|
||||||
this.error = null;
|
|
||||||
},
|
|
||||||
addJob(item: UploadItem) {
|
|
||||||
this.queue.push(item);
|
|
||||||
this.sizes[this.id] = item.file.size;
|
|
||||||
this.id++;
|
|
||||||
},
|
|
||||||
moveJob() {
|
|
||||||
const item = this.queue[0];
|
|
||||||
this.queue.shift();
|
|
||||||
this.uploads[item.id] = item;
|
|
||||||
},
|
|
||||||
removeJob(id: number) {
|
|
||||||
delete this.uploads[id];
|
|
||||||
},
|
|
||||||
upload(item: UploadItem) {
|
|
||||||
const uploadsCount = Object.keys(this.uploads).length;
|
|
||||||
|
|
||||||
const isQueueEmpty = this.queue.length == 0;
|
|
||||||
const isUploadsEmpty = uploadsCount == 0;
|
|
||||||
|
|
||||||
if (isQueueEmpty && isUploadsEmpty) {
|
|
||||||
window.addEventListener("beforeunload", beforeUnload);
|
|
||||||
buttons.loading("upload");
|
|
||||||
}
|
|
||||||
|
|
||||||
this.addJob(item);
|
|
||||||
this.processUploads();
|
|
||||||
},
|
|
||||||
finishUpload(item: UploadItem) {
|
|
||||||
this.setProgress({ id: item.id, loaded: item.file.size });
|
|
||||||
this.removeJob(item.id);
|
|
||||||
this.processUploads();
|
|
||||||
},
|
|
||||||
async processUploads() {
|
|
||||||
const uploadsCount = Object.keys(this.uploads).length;
|
|
||||||
|
|
||||||
const isBelowLimit = uploadsCount < UPLOADS_LIMIT;
|
|
||||||
const isQueueEmpty = this.queue.length == 0;
|
|
||||||
const isUploadsEmpty = uploadsCount == 0;
|
|
||||||
|
|
||||||
const isFinished = isQueueEmpty && isUploadsEmpty;
|
|
||||||
const canProcess = isBelowLimit && !isQueueEmpty;
|
|
||||||
|
|
||||||
if (isFinished) {
|
|
||||||
const fileStore = useFileStore();
|
|
||||||
window.removeEventListener("beforeunload", beforeUnload);
|
|
||||||
buttons.success("upload");
|
|
||||||
this.reset();
|
|
||||||
fileStore.reload = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canProcess) {
|
|
||||||
const item = this.queue[0];
|
|
||||||
this.moveJob();
|
|
||||||
|
|
||||||
if (item.file.isDir) {
|
|
||||||
await api.post(item.path).catch(this.setError);
|
|
||||||
} else {
|
|
||||||
const onUpload = throttle(
|
|
||||||
(event: ProgressEvent) =>
|
|
||||||
this.setProgress({
|
|
||||||
id: item.id,
|
|
||||||
loaded: event.loaded,
|
|
||||||
}),
|
|
||||||
100,
|
|
||||||
{ leading: true, trailing: false }
|
|
||||||
);
|
|
||||||
|
|
||||||
await api
|
|
||||||
.post(item.path, item.file.file as File, item.overwrite, onUpload)
|
|
||||||
.catch(this.setError);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.finishUpload(item);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
// easily reset state using `$reset`
|
|
||||||
clearUpload() {
|
|
||||||
this.$reset();
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user