Skip to content

Commit

Permalink
Add support for media saving messages in dropzone (umbraco#11304)
Browse files Browse the repository at this point in the history
* WIP

Waiting for a response on the issue about how to proceed

* Support messages in dropzone

Update dropzone to allow the showing of messages that may be added in a media saving notification / handler

* Remove test code

Remove code used for testing

* Sort usings

Remove unused using

* Fix ordering

Ordering of files when they were being processed was backwards / out of order

* Add button to "okay" all messages

PR Feedback to add a button to dismiss all of the messages all at once.
Fixing a referencing issue with `currentFile`

Co-authored-by: Michael Latouche <[email protected]>
  • Loading branch information
matthewcare and mikecp authored Nov 10, 2021
1 parent 570841b commit fe7b696
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 176 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ angular.module("umbraco.directives")
propertyAlias: '@',
accept: '@',
maxFileSize: '@',

compact: '@',
hideDropzone: '@',
acceptedMediatypes: '=',
Expand All @@ -42,9 +42,10 @@ angular.module("umbraco.directives")
},
link: function(scope, element, attrs) {
scope.queue = [];
scope.done = [];
scope.rejected = [];
scope.totalQueued = 0;
scope.currentFile = undefined;
scope.processed = [];
scope.totalMessages = 0;

function _filterFile(file) {
var ignoreFileNames = ['Thumbs.db'];
Expand All @@ -65,51 +66,50 @@ angular.module("umbraco.directives")
function _filesQueued(files, event) {
//Push into the queue
Utilities.forEach(files, file => {
if (_filterFile(file) === true) {

if (file.$error) {
scope.rejected.push(file);
} else {
scope.queue.push(file);
}
if (_filterFile(file) === true) {
file.messages = [];
scope.queue.push(file);
}
});

//when queue is done, kick the uploader
if (!scope.working) {
// Upload not allowed
if (!scope.acceptedMediatypes || !scope.acceptedMediatypes.length) {
files.map(file => {
file.uploadStatus = "error";
file.serverErrorMessage = "File type is not allowed here";
scope.rejected.push(file);
});
scope.queue = [];
}
// If we have Accepted Media Types, we will ask to choose Media Type, if Choose Media Type returns false, it only had one choice and therefor no reason to
if (scope.acceptedMediatypes && _requestChooseMediaTypeDialog() === false) {
scope.contentTypeAlias = "umbracoAutoSelect";
// Upload not allowed
if (!scope.acceptedMediatypes || !scope.acceptedMediatypes.length) {
files.map(file => {
file.messages.push({message: "File type is not allowed here", type: "Error"});
});
}

_processQueueItem();
}
// If we have Accepted Media Types, we will ask to choose Media Type, if Choose Media Type returns false, it only had one choice and therefor no reason to
if (scope.acceptedMediatypes && _requestChooseMediaTypeDialog() === false) {
scope.contentTypeAlias = "umbracoAutoSelect";
}

// Add the processed length, as we might be uploading in stages
scope.totalQueued = scope.queue.length + scope.processed.length;

_processQueueItems();
}

function _processQueueItem() {
if (scope.queue.length > 0) {
function _processQueueItems() {
// if we have processed all files, either by successful
// upload, or attending to all messages, we deem the
// action complete, else continue processing files
scope.totalMessages = scope.processed.filter(e => e.messages.length > 0).length;
if (scope.totalQueued === scope.processed.length) {
if (scope.totalMessages === 0) {
if (scope.filesUploaded) {
//queue is empty, trigger the done action
scope.filesUploaded(scope.done);
}
//auto-clear the done queue after 3 secs
var currentLength = scope.processed.length;
$timeout(function() {
scope.processed.splice(0, currentLength);
}, 3000);
}
} else {
scope.currentFile = scope.queue.shift();
_upload(scope.currentFile);
} else if (scope.done.length > 0) {
if (scope.filesUploaded) {
//queue is empty, trigger the done action
scope.filesUploaded(scope.done);
}

//auto-clear the done queue after 3 secs
var currentLength = scope.done.length;
$timeout(function() {
scope.done.splice(0, currentLength);
}, 3000);
}
}

Expand All @@ -134,55 +134,36 @@ angular.module("umbraco.directives")
var progressPercentage = parseInt(100.0 * evt.loaded / evt.total, 10);
// set percentage property on file
file.uploadProgress = progressPercentage;
// set uploading status on file
file.uploadStatus = "uploading";
}
})
.success(function(data, status, headers, config) {
if (data.notifications && data.notifications.length > 0) {
// set error status on file
file.uploadStatus = "error";
// Throw message back to user with the cause of the error
file.serverErrorMessage = data.notifications[0].message;
// Put the file in the rejected pool
scope.rejected.push(file);
} else {
// set done status on file
file.uploadStatus = "done";
file.uploadProgress = 100;
// set date/time for when done - used for sorting
file.doneDate = new Date();
// Put the file in the done pool
scope.done.push(file);
}
.success(function (data, status, headers, config) {
// Set server messages
file.messages = data.notifications;
scope.processed.push(file);
//after processing, test if everything is done
scope.currentFile = undefined;
//after processing, test if everthing is done
_processQueueItem();
_processQueueItems();
})
.error(function(evt, status, headers, config) {
// set status done
file.uploadStatus = "error";
//if the service returns a detailed error
if (evt.InnerException) {
file.serverErrorMessage = evt.InnerException.ExceptionMessage;
file.messages.push({ message: evt.InnerException.ExceptionMessage, type: "Error" });
//Check if its the common "too large file" exception
if (evt.InnerException.StackTrace &&
evt.InnerException.StackTrace.indexOf("ValidateRequestEntityLength") > 0) {
file.serverErrorMessage = "File too large to upload";
file.messages.push({ message: "File too large to upload", type: "Error" });
}
} else if (evt.Message) {
file.serverErrorMessage = evt.Message;
} else if (evt && typeof evt === 'string') {
file.serverErrorMessage = evt;
file.messages.push({message: evt.Message, type: "Error"});
} else if (evt && typeof evt === "string") {
file.messages.push({message: evt, type: "Error"});
}
// If file not found, server will return a 404 and display this message
if (status === 404) {
file.serverErrorMessage = "File not found";
file.messages.push({message: "File not found", type: "Error"});
}
//after processing, test if everthing is done
scope.rejected.push(file);
scope.currentFile = undefined;
_processQueueItem();
_processQueueItems();
});
}

Expand Down Expand Up @@ -224,16 +205,14 @@ angular.module("umbraco.directives")
availableItems: filteredMediaTypes,
submit: function (model) {
scope.contentTypeAlias = model.selectedItem.alias;
_processQueueItem();
_processQueueItems();

overlayService.close();
},
close: function () {

scope.queue.map(function (file) {
file.uploadStatus = "error";
file.serverErrorMessage = "No files uploaded, no mediatype selected";
scope.rejected.push(file);
file.messages.push({message:"No files uploaded, no mediatype selected", type: "Error"});
});
scope.queue = [];

Expand All @@ -245,14 +224,26 @@ angular.module("umbraco.directives")
overlayService.open(dialog);
});

return true;// yes, we did open the choose-media dialog, therefor we return true.
return true; // yes, we did open the choose-media dialog, therefore we return true.
}

scope.dismissMessages = function (file) {
file.messages = [];
_processQueueItems();
}

scope.dismissAllMessages = function () {
Utilities.forEach(scope.processed, file => {
file.messages = [];
});
_processQueueItems();
}

scope.handleFiles = function(files, event, invalidFiles) {
const allFiles = [...files, ...invalidFiles];

// add unique key for each files to use in ng-repeats
allFiles.forEach(file => {
Utilities.forEach(allFiles, file => {
file.key = String.CreateGuid();
});

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@

.umb-file-dropzone {

// drop zone
// tall and small version - animate height
.dropzone {
Expand All @@ -21,17 +20,16 @@

&.is-small {
height: 100px;

.illustration {
width: 200px;
}
}

&.drag-over {
border: 1px dashed @gray-1;
}
}


// center the content of the drop zone
.content {
position: absolute;
Expand All @@ -41,8 +39,6 @@
display: flex;
flex-direction: column;
}


// file select link
.file-select {
background: transparent;
Expand All @@ -54,11 +50,10 @@
margin-top: 10px;

&:hover {
color: @ui-action-discreet-type-hover;
text-decoration: none;
color: @ui-action-discreet-type-hover;
text-decoration: none;
}
}

// uploading / uploaded file list
.file-list {
list-style: none;
Expand All @@ -67,26 +62,32 @@
padding: 10px 20px;

.file {
//border-bottom: 1px dashed @orange;
display: block;
width: 100%;
padding: 5px 0;
position: relative;
border-top: 1px solid @gray-8;

&:first-child {
border-top: none;
}

&.ng-enter {
animation: fadeIn 0.5s;
}

&.ng-leave {
animation: fadeOut 2s;
}

.file-description {
color: @gray-3;
font-size: 12px;
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
}

.file-messages, .file-messages span {
display: block;
}

Expand All @@ -95,25 +96,11 @@
width: 100%;
}

.file-icon {
position: absolute;
right: 0;
bottom: 0;

.icon {
font-size: 20px;
&.ng-enter {
animation: fadeIn 0.5s;
}
&.ng-leave {
animation: fadeIn 0.5s;
}
}
.ok-all {
margin-left: auto;
}
}
}


// progress bars
// could be moved to its own less file
.file-progress {
Expand All @@ -131,5 +118,4 @@
width: 0;
}
}

}
Loading

0 comments on commit fe7b696

Please sign in to comment.