Umbraco.CMS.Backoffice icon indicating copy to clipboard operation
Umbraco.CMS.Backoffice copied to clipboard

Media dropzone improvements (Batch upload, Upload sorting, Folder upload, Progress notification)

Open nikcio opened this issue 5 months ago • 2 comments

Description

  • Fixes #16559
    • This implements batching of the file uploads which creates this issue and then fixes it by sorting the uploaded files after a successful upload. This makes sure the order remains the correct order.
  • Fixes #16484
    • This adds the missing implementation for folder uploads
  • Fixes #16508
    • This changes from using the MIME type to using the file extension in the file name and will therefore mark the file as audio if the file extension on a file is .mp3

Types of changes

  • [x] Bug fix (non-breaking change which fixes an issue)
  • [x] New feature (non-breaking change which adds functionality)
  • [ ] Breaking change (fix or feature that would cause existing functionality to change)
  • [ ] Chore (minor updates related to the tooling or maintenance of the repository, does not impact compiled assets)

Motivation and context

This aims to solve some of the problems and shortcomings of the drag-and-drop functionality in the Media library

How to test?

Usage of the media drag and drop feature. As well as other usages of the umb-dropzone component. This can also be found in the media type import and document type import but see the "Still present bugs" section first.

Screenshots (if appropriate)

Multiple media types available for uploaded files: image

Info view of files for selection (Can be shown by pressing the info icon) image

Progress notification (Auto updates with progress) image

Completed progress notification image

Videos

Notice that in these videos I have a custom Media type that applies to the images I upload which means I get the popup every time.

To create a media type for this follow these steps:

  1. Create a media type
  2. Add a Upload field with an alias of umbracoFile
  3. Add jpg or any other required image file type to Accepted file extensions

Video 1 - Normal uploads

https://github.com/user-attachments/assets/c20a6f3e-c618-4bd0-bb9e-c536f6f59561

Video 2 - Folder uploads

https://github.com/user-attachments/assets/1427f08b-a720-4305-a36e-d4caa50dd768

Video 3 - Upload as Custom media type

https://github.com/user-attachments/assets/634a947b-ed83-41fb-91af-88988c13be33

Checklist

  • [x] If my change requires a change to the documentation, I have updated the documentation in this pull request.
  • [x] I have read the CONTRIBUTING document.
  • [ ] I have added tests to cover my changes.
    • I would like some guidance on what would make sense here.

Still present bugs

  • Unable to drag and drop files produced by Umbraco due to missing MIME type

    • See: https://github.com/umbraco/Umbraco.UI/issues/895
  • In the Import media type / document type feature there is no error handling if you drag and drop for example a picture in the dropzone but that is outside the scope of this PR to fix.

  • You are unable to dismiss any notification when having a folder open.

  • SQL database table locked

    • I'm pretty sure that none of these changes have created this bug but I've had a lot of issues with the database being locked when uploading many images at a time.
Stacktrace from this:

[22:10:20 ERR] Failed executing DbCommand (30,100ms) [Parameters=[@__identifier_0='?' (Size = 44)], CommandType='Text', CommandTimeout='30']
SELECT "u"."Id", "u"."ApplicationId", "u"."AuthorizationId", "u"."ConcurrencyToken", "u"."CreationDate", "u"."ExpirationDate", "u"."Payload", "u"."Properties", "u"."RedemptionDate", "u"."ReferenceId", "u"."Status", "u"."Subject", "u"."Type", "u0"."Id", "u0"."ApplicationType", "u0"."ClientId", "u0"."ClientSecret", "u0"."ClientType", "u0"."ConcurrencyToken", "u0"."ConsentType", "u0"."DisplayName", "u0"."DisplayNames", "u0"."JsonWebKeySet", "u0"."Permissions", "u0"."PostLogoutRedirectUris", "u0"."Properties", "u0"."RedirectUris", "u0"."Requirements", "u0"."Settings", "u1"."Id", "u1"."ApplicationId", "u1"."ConcurrencyToken", "u1"."CreationDate", "u1"."Properties", "u1"."Scopes", "u1"."Status", "u1"."Subject", "u1"."Type"
FROM "umbracoOpenIddictTokens" AS "u"
LEFT JOIN "umbracoOpenIddictApplications" AS "u0" ON "u"."ApplicationId" = "u0"."Id"
LEFT JOIN "umbracoOpenIddictAuthorizations" AS "u1" ON "u"."AuthorizationId" = "u1"."Id"
WHERE "u"."ReferenceId" = @__identifier_0
LIMIT 1
[22:10:20 ERR] An exception occurred while iterating over the results of a query for context type 'Umbraco.Cms.Persistence.EFCore.UmbracoDbContext'.
Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 6: 'database table is locked'.
   at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
   at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
   at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
   at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.InitializeReaderAsync(AsyncEnumerator enumerator, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()
Microsoft.Data.Sqlite.SqliteException (0x80004005): SQLite Error 6: 'database table is locked'.
   at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
   at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
   at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
   at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.InitializeReaderAsync(AsyncEnumerator enumerator, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.AsyncEnumerator.MoveNextAsync()
   at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync[TSource](IAsyncEnumerable`1 asyncEnumerable, CancellationToken cancellationToken)
   at Microsoft.EntityFrameworkCore.Query.ShapedQueryCompilingExpressionVisitor.SingleOrDefaultAsync[TSource](IAsyncEnumerable`1 asyncEnumerable, CancellationToken cancellationToken)
   at OpenIddict.Core.OpenIddictTokenCache`1.<>c__DisplayClass12_0.<<FindByReferenceIdAsync>g__ExecuteAsync|0>d.MoveNext()
--- End of stack trace from previous location ---
   at OpenIddict.Core.OpenIddictTokenManager`1.FindByReferenceIdAsync(String identifier, CancellationToken cancellationToken)
   at OpenIddict.Core.OpenIddictTokenManager`1.OpenIddict.Abstractions.IOpenIddictTokenManager.FindByReferenceIdAsync(String identifier, CancellationToken cancellationToken)
   at OpenIddict.Validation.OpenIddictValidationHandlers.Protection.ValidateReferenceTokenIdentifier.HandleAsync(ValidateTokenContext context)
   at OpenIddict.Validation.OpenIddictValidationDispatcher.DispatchAsync[TContext](TContext context)
   at OpenIddict.Validation.OpenIddictValidationDispatcher.DispatchAsync[TContext](TContext context)
   at OpenIddict.Validation.OpenIddictValidationHandlers.ValidateAccessToken.HandleAsync(ProcessAuthenticationContext context)
   at OpenIddict.Validation.OpenIddictValidationDispatcher.DispatchAsync[TContext](TContext context)
   at OpenIddict.Validation.OpenIddictValidationDispatcher.DispatchAsync[TContext](TContext context)
   at OpenIddict.Validation.AspNetCore.OpenIddictValidationAspNetCoreHandler.HandleAuthenticateAsync()
   at Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.AuthenticateAsync()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)

nikcio avatar Sep 06 '24 16:09 nikcio