Skip to content

fix: upload double-submit, DB race, and add real progress tracking#1537

Open
kuu-26 wants to merge 2 commits intoValour-Software:mainfrom
kuu-26:fix/upload-double-submit-and-db-race
Open

fix: upload double-submit, DB race, and add real progress tracking#1537
kuu-26 wants to merge 2 commits intoValour-Software:mainfrom
kuu-26:fix/upload-double-submit-and-db-race

Conversation

@kuu-26
Copy link
Copy Markdown
Contributor

@kuu-26 kuu-26 commented Apr 18, 2026

Three related fixes for the upload flow, all in one branch since they stack on each other:

1. Prevent double-submit on upload + handle DB race on CDN insert (8895354)

  • Disable the upload button while an upload is in flight so users can't slam it
  • Catch the unique constraint violation on CDN item insert instead of crashing (concurrent uploads could race)

2. Add upload progress bar and cancel support (c5d1084)

  • Wire up the existing uploadWithProgress JS function so the modal actually shows real progress
  • Add a cancel button that calls abortCurrentUpload()
  • Show progress percentage + uploaded/total size

3. Wrap upload JS interop in reusable UploadService (1577f8f)

  • Extract all the messy [JSInvokable] callbacks out of FileUploadComponent into a proper scoped DI service
  • UploadService.cs: UploadAsync() with CancellationToken support, UploadProgressInfo and UploadResult records
  • UploadService.js: ES module (no more global window._currentUploadAbort), follows the ResizeObserver pattern already used in the project
  • FileUploadComponent is now way cleaner since it just consumes the service

Tested: builds clean on Client.csproj

kuu-26 added 2 commits April 18, 2026 19:10
- JS: uploadWithProgress() uses XMLHttpRequest with upload.onprogress for real-time progress tracking
- JS: abortCurrentUpload() allows cancelling in-progress uploads
- FileUploadComponent: shows progress bar with % and bytes during upload
- FileUploadComponent: cancel button during upload, error display on failure
- FileUploadComponent: new ModalParams with UploadUrl, AuthToken, OnUploadSuccess
- InputComponent: passes upload URL and auth token so modal can do the upload itself
- CSS: progress bar with gradient, error state styling, danger button for cancel
- UploadService.cs: scoped DI service with UploadAsync(), CancelCurrent()
  - real wire-level progress via XHR (not fake C# stream copying)
  - CancellationToken support for clean cancellation
  - UploadProgressInfo record with Percent, FormattedUploaded, FormattedTotal
  - UploadResult record with Success/Response/Error
  - IAsyncDisposable, lazy-loads JS module on first use
- UploadService.js: ES module following ResizeObserver pattern, no more globals
- FileUploadComponent: now uses UploadService instead of raw JS interop
  - deleted all the [JSInvokable] callbacks from the component
  - progress display uses UploadProgressInfo formatting
  - cancel via CancellationTokenSource instead of calling JS directly
- removed uploadWithProgress/abortCurrentUpload from main.js
- registered UploadService in DI
@kuu-26 kuu-26 requested a review from a team as a code owner April 18, 2026 19:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant