Improve ts types in upload

This commit is contained in:
Kloon ImKloon 2023-09-14 12:57:39 +02:00
parent 065e11ff2b
commit 1ad7f4be5f
No known key found for this signature in database
GPG Key ID: CCF1C86A995C5B6A
4 changed files with 61 additions and 37 deletions

View File

@ -17,9 +17,9 @@ export const useUploadStore = defineStore("upload", {
// convert to a function // convert to a function
state: (): { state: (): {
id: number; id: number;
sizes: any[]; sizes: number[];
progress: any[]; progress: Progress[];
queue: any[]; queue: UploadItem[];
uploads: Uploads; uploads: Uploads;
error: Error | null; error: Error | null;
} => ({ } => ({
@ -39,7 +39,8 @@ export const useUploadStore = defineStore("upload", {
const totalSize = state.sizes.reduce((a, b) => a + b, 0); const totalSize = state.sizes.reduce((a, b) => a + b, 0);
const sum: number = state.progress.reduce((acc, val) => acc + val); // TODO: this looks ugly but it works with ts now
const sum = state.progress.reduce((acc, val) => +acc + +val) as number;
return Math.ceil((sum / totalSize) * 100); return Math.ceil((sum / totalSize) * 100);
}, },
filesInUploadCount: (state) => { filesInUploadCount: (state) => {
@ -58,7 +59,7 @@ export const useUploadStore = defineStore("upload", {
const isDir = upload.file.isDir; const isDir = upload.file.isDir;
const progress = isDir const progress = isDir
? 100 ? 100
: Math.ceil((state.progress[id] / size) * 100); : Math.ceil(((state.progress[id] as number) / size) * 100);
files.push({ files.push({
id, id,
@ -74,9 +75,7 @@ export const useUploadStore = defineStore("upload", {
}, },
actions: { actions: {
// no context as first argument, use `this` instead // no context as first argument, use `this` instead
setProgress(obj: { id: number; loaded: boolean }) { setProgress({ id, loaded }: { id: number; loaded: Progress }) {
// Vue.set(this.progress, id, loaded);
const { id, loaded } = obj;
this.progress[id] = loaded; this.progress[id] = loaded;
}, },
setError(error: Error) { setError(error: Error) {
@ -95,11 +94,9 @@ export const useUploadStore = defineStore("upload", {
moveJob() { moveJob() {
const item = this.queue[0]; const item = this.queue[0];
this.queue.shift(); this.queue.shift();
// Vue.set(this.uploads, item.id, item);
this.uploads[item.id] = item; this.uploads[item.id] = item;
}, },
removeJob(id: number) { removeJob(id: number) {
// Vue.delete(this.uploads, id);
delete this.uploads[id]; delete this.uploads[id];
}, },
upload(item: UploadItem) { upload(item: UploadItem) {
@ -147,7 +144,7 @@ export const useUploadStore = defineStore("upload", {
await api.post(item.path).catch(this.setError); await api.post(item.path).catch(this.setError);
} else { } else {
const onUpload = throttle( const onUpload = throttle(
(event) => (event: ProgressEvent) =>
this.setProgress({ this.setProgress({
id: item.id, id: item.id,
loaded: event.loaded, loaded: event.loaded,
@ -157,7 +154,7 @@ export const useUploadStore = defineStore("upload", {
); );
await api await api
.post(item.path, item.file, item.overwrite, onUpload) .post(item.path, item.file.file as File, item.overwrite, onUpload)
.catch(this.setError); .catch(this.setError);
} }

View File

@ -9,7 +9,6 @@ interface ResourceBase {
isSymlink: boolean; isSymlink: boolean;
type: ResourceType; type: ResourceType;
url: string; url: string;
fullPath?: string;
} }
interface Resource extends ResourceBase { interface Resource extends ResourceBase {

View File

@ -1,19 +1,31 @@
interface Uploads { interface Uploads {
[key: string]: Upload; [key: number]: Upload;
} }
interface Upload { interface Upload {
id: number; id: number;
file: Resource; file: UploadEntry;
type: string; type?: ResourceType;
} }
interface UploadItem { interface UploadItem {
id: number; id: number;
url?: string; url?: string;
path: string; path: string;
file: Resource; file: UploadEntry;
dir?: boolean; dir?: boolean;
overwrite?: boolean; overwrite?: boolean;
type?: ResourceType; type?: ResourceType;
} }
interface UploadEntry {
fullPath: string;
isDir: boolean;
name: string;
size: number;
file?: File;
}
type UploadList = UploadEntry[];
type Progress = number | boolean;

View File

@ -2,7 +2,7 @@ import { useUploadStore } from "@/stores/upload";
import url from "@/utils/url"; import url from "@/utils/url";
export function checkConflict( export function checkConflict(
files: ResourceItem[], files: UploadList,
dest: ResourceItem[] dest: ResourceItem[]
): boolean { ): boolean {
if (typeof dest === "undefined" || dest === null) { if (typeof dest === "undefined" || dest === null) {
@ -11,7 +11,7 @@ export function checkConflict(
const folder_upload = files[0].fullPath !== undefined; const folder_upload = files[0].fullPath !== undefined;
const names: string[] = []; const names = new Set<string>();
for (let i = 0; i < files.length; i++) { for (let i = 0; i < files.length; i++) {
const file = files[i]; const file = files[i];
let name = file.name; let name = file.name;
@ -23,39 +23,48 @@ export function checkConflict(
} }
} }
names.push(name); names.add(name);
} }
return dest.some((d) => names.includes(d.name)); return dest.some((d) => names.has(d.name));
} }
export function scanFiles(dt: { [key: string]: any; item: ResourceItem }) { export function scanFiles(dt: DataTransfer) {
return new Promise((resolve) => { return new Promise((resolve) => {
let reading = 0; let reading = 0;
const contents: any[] = []; const contents: UploadList = [];
if (dt.items !== undefined) { if (dt.items) {
for (const item of dt.items) { // ts didnt like the for of loop even tho
// it is the official example on MDN
// for (const item of dt.items) {
for (let i = 0; i < dt.items.length; i++) {
const item = dt.items[i];
if ( if (
item.kind === "file" && item.kind === "file" &&
typeof item.webkitGetAsEntry === "function" typeof item.webkitGetAsEntry === "function"
) { ) {
const entry = item.webkitGetAsEntry(); const entry = item.webkitGetAsEntry();
readEntry(entry); entry && readEntry(entry);
} }
} }
} else { } else {
resolve(dt.files); resolve(dt.files);
} }
function readEntry(entry: any, directory = "") { function readEntry(entry: FileSystemEntry, directory = ""): void {
if (entry.isFile) { if (entry.isFile) {
reading++; reading++;
entry.file((file: Resource) => { (entry as FileSystemFileEntry).file((file) => {
reading--; reading--;
file.fullPath = `${directory}${file.name}`; contents.push({
contents.push(file); file,
name: file.name,
size: file.size,
isDir: false,
fullPath: `${directory}${file.name}`,
});
if (reading === 0) { if (reading === 0) {
resolve(contents); resolve(contents);
@ -71,14 +80,20 @@ export function scanFiles(dt: { [key: string]: any; item: ResourceItem }) {
contents.push(dir); contents.push(dir);
readReaderContent(entry.createReader(), `${directory}${entry.name}`); readReaderContent(
(entry as FileSystemDirectoryEntry).createReader(),
`${directory}${entry.name}`
);
} }
} }
function readReaderContent(reader: any, directory: string) { function readReaderContent(
reader: FileSystemDirectoryReader,
directory: string
): void {
reading++; reading++;
reader.readEntries(function (entries: any[]) { reader.readEntries((entries) => {
reading--; reading--;
if (entries.length > 0) { if (entries.length > 0) {
for (const entry of entries) { for (const entry of entries) {
@ -106,16 +121,15 @@ function detectType(mimetype: string): ResourceType {
} }
export function handleFiles( export function handleFiles(
files: Resource[], files: UploadList,
base: string, base: string,
overwrite = false overwrite = false
) { ) {
const uploadStore = useUploadStore(); const uploadStore = useUploadStore();
for (let i = 0; i < files.length; i++) { for (const file of files) {
const id = uploadStore.id; const id = uploadStore.id;
let path = base; let path = base;
const file = files[i];
if (file.fullPath !== undefined) { if (file.fullPath !== undefined) {
path += url.encodePath(file.fullPath); path += url.encodePath(file.fullPath);
@ -127,12 +141,14 @@ export function handleFiles(
path += "/"; path += "/";
} }
console.log("File", file);
const item: UploadItem = { const item: UploadItem = {
id, id,
path, path,
file, file,
overwrite, overwrite,
...(!file.isDir && { type: detectType(file.type) }), ...(!file.isDir && { type: detectType((file.file as File).type) }),
}; };
uploadStore.upload(item); uploadStore.upload(item);