From de06939b01f999da96ca3ca4df2dbce4090643fb Mon Sep 17 00:00:00 2001 From: LordMathis Date: Tue, 28 Oct 2025 18:58:10 +0100 Subject: [PATCH] Fix file upload --- app/src/api/api.ts | 17 +++++++++++++++-- app/src/hooks/useFileOperations.ts | 3 ++- server/internal/handlers/file_handlers.go | 3 ++- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/app/src/api/api.ts b/app/src/api/api.ts index 6f97c76..f46c0d1 100644 --- a/app/src/api/api.ts +++ b/app/src/api/api.ts @@ -29,10 +29,16 @@ export const apiCall = async ( // Set up headers with CSRF token for non-GET requests const method = options.method || 'GET'; const headers: Record = { - 'Content-Type': 'application/json', ...(options.headers as Record), }; + // Only set Content-Type to application/json if not already set and body is not FormData + // FormData requires the browser to set Content-Type with the boundary parameter + const isFormData = options.body instanceof FormData; + if (!headers['Content-Type'] && !isFormData) { + headers['Content-Type'] = 'application/json'; + } + // Add CSRF token for non-GET methods if (method !== 'GET') { const csrfToken = getCsrfToken(); @@ -41,11 +47,18 @@ export const apiCall = async ( } } + // For FormData, don't include Content-Type in headers - let the browser set it + const fetchHeaders = isFormData + ? Object.fromEntries( + Object.entries(headers).filter(([key]) => key !== 'Content-Type') + ) + : headers; + const response = await fetch(url, { ...options, // Include credentials to send/receive cookies credentials: 'include', - headers, + headers: fetchHeaders, }); console.debug(`Response status: ${response.status} for URL: ${url}`); diff --git a/app/src/hooks/useFileOperations.ts b/app/src/hooks/useFileOperations.ts index 6317c47..dc26607 100644 --- a/app/src/hooks/useFileOperations.ts +++ b/app/src/hooks/useFileOperations.ts @@ -122,7 +122,8 @@ export const useFileOperations = (): UseFileOperationsResult => { if (!currentWorkspace) return false; try { - await uploadFile(currentWorkspace.name, targetPath || '', files); + // Default to '.' (root directory) if no target path is provided + await uploadFile(currentWorkspace.name, targetPath || '.', files); notifications.show({ title: 'Success', diff --git a/server/internal/handlers/file_handlers.go b/server/internal/handlers/file_handlers.go index 33f37e1..5b03858 100644 --- a/server/internal/handlers/file_handlers.go +++ b/server/internal/handlers/file_handlers.go @@ -410,7 +410,8 @@ func (h *Handler) UploadFile() http.HandlerFunc { } }() - filePath := decodedPath + "/" + formFile.Filename + // Use filepath.Join to properly construct the path + filePath := filepath.Join(decodedPath, formFile.Filename) content, err := io.ReadAll(file) if err != nil {