import {createIcons, icons} from "lucide"; export const CHUNK_SIZE = 8192; export function FSUploader(){ return { files: [], rawFiles: [], section: document.querySelector("meta[name='fs-section']")?.content ?? '', init( oldFiles ){ this.$watch('files', () =>{ this.$nextTick(() => window.refreshIcons(this.$el) ) }) }, get isUploading(){ return this.files.some(f => !f.done && !f.error); }, get hasErrors(){ return this.files.some(f => f.error); }, get allUploaded(){ return this.files.length === 0 || this.files.every(f => f.done); }, async submitFile(e){ const selected = Array.from(e.target.files); e.target.value = ''; for( const raw of selected ){ const totalChunks = Math.ceil(raw.size / CHUNK_SIZE ); const index = this.files.length; this.files.push({ name: raw.name, progress: 0, currentChunk: 0, totalChunks: totalChunks, done: false, error: null, uuid: crypto.randomUUID() }); this.rawFiles.push(raw); this.uploadChunks(raw,index); } }, async uploadChunks(rawFile, index){ const file = this.files[index]; const url = `/api/fs/upload-chunk/${this.section}`; const csrf = document.querySelector('meta[name=csrf-token]')?.content ?? ''; for( let i = 0; i < file.totalChunks; i++ ){ if( file.error ) return; const start = i * CHUNK_SIZE; const end = Math.min(start + CHUNK_SIZE, rawFile.size); const chunk = rawFile.slice(start, end); const formData = new FormData(); formData.append('file', chunk); formData.append('file_uuid', file.uuid); formData.append('current_chunk', i); formData.append('total_chunks', file.totalChunks); formData.append( 'filename', rawFile.name ); formData.append('_token', csrf ); try { const response = await fetch(url, { method: 'POST', body: formData }); if(!response.ok) throw new Error(`${response.status} ${response.statusText}`); const data = await response.json(); if( data.success !== true || data.uploaded !== true ) throw new Error(`${data.error}`); file.currentChunk = i + 1; file.progress = Math.round((( i + 1) / file.totalChunks ) * 100); if( data.finished === true ){ file.done = true; } } catch(err){ file.error = 'Error on chunk ' + ( i + 1 ) + '. ' + err.message; file.progress = 0; return; } } }, retry(index){ const rawFile = this.rawFiles[index]; const totalChunks = Math.ceil(rawFile.size / CHUNK_SIZE ); this.files[index] = { name: rawFile.name, progress: 0, currentChunk: 0, totalChunks: totalChunks, done: false, error: null, uuid: crypto.randomUUID() }; this.uploadChunks(raw,index); }, remove(index){ this.files.splice(index, 1); this.rawFiles.splice(index, 1); } } }