11/**
22 * Ragify Frontend Application
3- * Alpine.js + HTMX based SPA
3+ * Alpine.js based SPA
44 */
55
66function ragifyApp ( ) {
@@ -25,8 +25,7 @@ function ragifyApp() {
2525 uploadQueue : [ ] ,
2626 uploading : false ,
2727 dragOver : false ,
28- uploadPhase : '' , // 'zipping', 'uploading', ''
29- uploadLocalProgress : 0 ,
28+ showFolderError : false ,
3029
3130 // Search
3231 searchCollection : '' ,
@@ -68,15 +67,12 @@ function ragifyApp() {
6867 try {
6968 const res = await fetch ( '/api/collections' , { credentials : 'include' } ) ;
7069 const data = await res . json ( ) ;
71- console . log ( 'API response:' , data ) ;
7270 this . collections = data . collections || [ ] ;
73- console . log ( 'Collections loaded:' , this . collections ) ;
7471
7572 // Update stats
7673 this . stats . collections = this . collections . length ;
7774 this . stats . chunks = this . collections . reduce ( ( sum , c ) => sum + ( c . points_count || 0 ) , 0 ) ;
7875 this . stats . documents = this . collections . reduce ( ( sum , c ) => sum + ( c . documents_count || 0 ) , 0 ) ;
79- console . log ( 'Stats updated:' , this . stats ) ;
8076
8177 // Set default upload/search collection if not set or invalid
8278 if ( this . collections . length > 0 ) {
@@ -87,7 +83,6 @@ function ragifyApp() {
8783 if ( ! this . searchCollection || ! collectionNames . includes ( this . searchCollection ) ) {
8884 this . searchCollection = this . collections [ 0 ] . name ;
8985 }
90- console . log ( 'Default collections set:' , this . uploadCollection , this . searchCollection ) ;
9186 }
9287 } catch ( e ) {
9388 console . error ( 'Failed to load collections:' , e ) ;
@@ -158,22 +153,31 @@ function ragifyApp() {
158153 }
159154 } ,
160155
161- // Upload
156+ // Upload - simplified: files only, no folder handling
162157 handleDrop ( event ) {
163158 this . dragOver = false ;
164- const files = event . dataTransfer . files ;
165- this . addFilesToQueue ( files ) ;
159+
160+ // Check if any dropped item is a folder
161+ const items = event . dataTransfer . items ;
162+ for ( const item of items ) {
163+ const entry = item . webkitGetAsEntry && item . webkitGetAsEntry ( ) ;
164+ if ( entry && entry . isDirectory ) {
165+ this . showFolderError = true ;
166+ return ; // Block upload
167+ }
168+ }
169+
170+ this . addFilesToQueue ( event . dataTransfer . files ) ;
166171 } ,
167172
168173 handleFileSelect ( event ) {
169- const files = event . target . files ;
170- this . addFilesToQueue ( files ) ;
174+ this . addFilesToQueue ( event . target . files ) ;
171175 event . target . value = '' ; // Reset input
172176 } ,
173177
174178 addFilesToQueue ( files ) {
175179 for ( const file of files ) {
176- // Avoid duplicates
180+ // Avoid duplicates by name
177181 if ( ! this . uploadQueue . find ( f => f . name === file . name ) ) {
178182 this . uploadQueue . push ( file ) ;
179183 }
@@ -184,86 +188,38 @@ function ragifyApp() {
184188 if ( this . uploadQueue . length === 0 || this . uploading ) return ;
185189 this . uploading = true ;
186190
187- // Decide: ZIP if multiple files OR total size > 5MB
188- const totalSize = this . uploadQueue . reduce ( ( sum , f ) => sum + f . size , 0 ) ;
189- const shouldZip = this . uploadQueue . length > 1 || totalSize > 5 * 1024 * 1024 ;
190-
191191 try {
192- if ( shouldZip ) {
193- await this . uploadAsZip ( ) ;
194- } else {
195- await this . uploadSingleFile ( ) ;
192+ // Upload each file - ZIP files go to /api/upload-zip, others to /api/upload
193+ for ( const file of this . uploadQueue ) {
194+ await this . uploadFile ( file ) ;
196195 }
197196 } catch ( e ) {
198197 this . showToast ( `Upload failed: ${ e . message || 'Unknown error' } ` , 'error' ) ;
199198 }
200199
201200 this . uploadQueue = [ ] ;
202201 this . uploading = false ;
203- this . uploadPhase = '' ;
204- this . uploadLocalProgress = 0 ;
205202 await this . loadJobs ( ) ;
206203 } ,
207204
208- async uploadSingleFile ( ) {
209- const file = this . uploadQueue [ 0 ] ;
210- this . uploadPhase = 'uploading' ;
211- this . uploadLocalProgress = 0 ;
205+ async uploadFile ( file ) {
206+ const isZip = file . name . toLowerCase ( ) . endsWith ( '.zip' ) ;
207+ const endpoint = isZip ? '/api/upload-zip' : '/api/upload' ;
212208
213209 const formData = new FormData ( ) ;
214210 formData . append ( 'file' , file ) ;
215211 formData . append ( 'collection' , this . uploadCollection ) ;
216212
217- const res = await fetch ( '/api/upload' , {
218- method : 'POST' ,
219- body : formData ,
220- credentials : 'include'
221- } ) ;
222-
223- if ( res . ok ) {
224- const data = await res . json ( ) ;
225- this . showToast ( `Uploaded: ${ file . name } (Job: ${ data . job_id ?. slice ( 0 , 8 ) || 'queued' } )` , 'success' ) ;
226- } else {
227- const error = await res . json ( ) . catch ( ( ) => ( { } ) ) ;
228- throw new Error ( error . detail || res . statusText ) ;
229- }
230- } ,
231-
232- async uploadAsZip ( ) {
233- // Phase 1: Zipping
234- this . uploadPhase = 'zipping' ;
235- this . uploadLocalProgress = 0 ;
236-
237- const zip = new JSZip ( ) ;
238- for ( const file of this . uploadQueue ) {
239- zip . file ( file . name , file ) ;
240- }
241-
242- const blob = await zip . generateAsync ( {
243- type : 'blob' ,
244- compression : 'DEFLATE' ,
245- compressionOptions : { level : 6 }
246- } , ( meta ) => {
247- this . uploadLocalProgress = meta . percent / 100 ;
248- } ) ;
249-
250- // Phase 2: Uploading
251- this . uploadPhase = 'uploading' ;
252- this . uploadLocalProgress = 0 ;
253-
254- const formData = new FormData ( ) ;
255- formData . append ( 'file' , blob , 'upload.zip' ) ;
256- formData . append ( 'collection' , this . uploadCollection ) ;
257-
258- const res = await fetch ( '/api/upload-zip' , {
213+ const res = await fetch ( endpoint , {
259214 method : 'POST' ,
260215 body : formData ,
261216 credentials : 'include'
262217 } ) ;
263218
264219 if ( res . ok ) {
265220 const data = await res . json ( ) ;
266- this . showToast ( `Uploaded ${ this . uploadQueue . length } files as ZIP (Job: ${ data . job_id ?. slice ( 0 , 8 ) || 'queued' } )` , 'success' ) ;
221+ const jobInfo = data . job_id ? ` (Job: ${ data . job_id . slice ( 0 , 8 ) } )` : '' ;
222+ this . showToast ( `Uploaded: ${ file . name } ${ jobInfo } ` , 'success' ) ;
267223 } else {
268224 const error = await res . json ( ) . catch ( ( ) => ( { } ) ) ;
269225 throw new Error ( error . detail || res . statusText ) ;
0 commit comments