client/upload: add QoL features for bulk uploads

* Continue uploading remaining posts in an upload list even
when one fails

* Allow option to continue uploading even when similar posts are found

Closes #400
This commit is contained in:
Shyam Sunder 2021-09-13 13:28:34 -04:00
commit be0c867d25
4 changed files with 62 additions and 30 deletions

View file

@ -13,8 +13,10 @@ $cancel-button-color = tomato
&.inactive input[type=submit],
&.inactive .skip-duplicates
&.inactive .always-upload-similar
&.uploading input[type=submit],
&.uploading .skip-duplicates,
&.uploading .always-upload-similar
&:not(.uploading) .cancel
display: none
@ -39,6 +41,9 @@ $cancel-button-color = tomato
.skip-duplicates
margin-left: 1em
.always-upload-similar
margin-left: 1em
form>.messages
margin-top: 1em

View file

@ -13,6 +13,14 @@
}) %>
</span>
<span class='always-upload-similar'>
<%= ctx.makeCheckbox({
text: 'Always upload similar',
name: 'always-upload-similar',
checked: false,
}) %>
</span>
<input type='button' value='Cancel' class='cancel'/>
</div>

View file

@ -12,7 +12,7 @@ const PostUploadView = require("../views/post_upload_view.js");
const EmptyView = require("../views/empty_view.js");
const genericErrorMessage =
"One of the posts needs your attention; " +
"One or more posts needs your attention; " +
'click "resume upload" when you\'re ready.';
class PostUploadController {
@ -55,6 +55,7 @@ class PostUploadController {
_evtSubmit(e) {
this._view.disableForm();
this._view.clearMessages();
let anyFailures = false;
e.detail.uploadables
.reduce(
@ -62,44 +63,51 @@ class PostUploadController {
promise.then(() =>
this._uploadSinglePost(
uploadable,
e.detail.skipDuplicates
)
),
Promise.resolve()
)
.then(
() => {
this._view.clearMessages();
misc.disableExitConfirmation();
const ctx = router.show(uri.formatClientLink("posts"));
ctx.controller.showSuccess("Posts uploaded.");
},
(error) => {
e.detail.skipDuplicates,
e.detail.alwaysUploadSimilar
).catch((error) => {
anyFailures = true;
if (error.uploadable) {
if (error.similarPosts) {
error.uploadable.lookalikes = error.similarPosts;
this._view.updateUploadable(error.uploadable);
this._view.showInfo(genericErrorMessage);
error.uploadable.lookalikes =
error.similarPosts;
this._view.updateUploadable(
error.uploadable
);
this._view.showInfo(
error.message,
error.uploadable
);
} else {
this._view.showError(genericErrorMessage);
this._view.showError(
error.message,
error.uploadable
);
}
} else {
this._view.showError(error.message);
}
this._view.enableForm();
}
this._view.showError(
error.message,
uploadable
);
}
})
),
Promise.resolve()
)
.then(() => {
if (anyFailures) {
this._view.showError(genericErrorMessage);
this._view.enableForm();
} else {
this._view.clearMessages();
misc.disableExitConfirmation();
const ctx = router.show(uri.formatClientLink("posts"));
ctx.controller.showSuccess("Posts uploaded.");
}
});
}
_uploadSinglePost(uploadable, skipDuplicates) {
_uploadSinglePost(uploadable, skipDuplicates, alwaysUploadSimilar) {
progress.start();
let reverseSearchPromise = Promise.resolve();
if (!uploadable.lookalikesConfirmed) {
@ -128,7 +136,10 @@ class PostUploadController {
}
// notify about similar posts
if (searchResult.similarPosts.length) {
if (
searchResult.similarPosts.length &&
!alwaysUploadSimilar
) {
let error = new Error(
`Found ${searchResult.similarPosts.length} similar ` +
"posts.\nYou can resume or discard this upload."

View file

@ -358,6 +358,8 @@ class PostUploadView extends events.EventTarget {
detail: {
uploadables: this._uploadables,
skipDuplicates: this._skipDuplicatesCheckboxNode.checked,
alwaysUploadSimilar: this._alwaysUploadSimilarCheckboxNode
.checked,
},
})
);
@ -421,6 +423,12 @@ class PostUploadView extends events.EventTarget {
return this._hostNode.querySelector("form [name=skip-duplicates]");
}
get _alwaysUploadSimilarCheckboxNode() {
return this._hostNode.querySelector(
"form [name=always-upload-similar]"
);
}
get _submitButtonNode() {
return this._hostNode.querySelector("form [type=submit]");
}