mirror of
https://github.com/discourse/discourse.git
synced 2024-11-27 06:03:38 +08:00
FEATURE: Buffer file names of failed uploads when bulk uploading (#25068)
Currently, when bulk uploading and multiple uploads fail, we show a number of dialogs in quick succession. This is of course a terrible user experience. With this change, we buffer the error messages until there are no more pending uploads. Then we combine the buffered errors and display a single dialog with a list of failed files.
This commit is contained in:
parent
b4a89ea610
commit
a0fbce996a
|
@ -4,6 +4,7 @@ import { sanitize as textSanitize } from "pretty-text/sanitizer";
|
|||
import deprecated from "discourse-common/lib/deprecated";
|
||||
import { getURLWithCDN } from "discourse-common/lib/get-url";
|
||||
import { helperContext } from "discourse-common/lib/helpers";
|
||||
import I18n from "discourse-i18n";
|
||||
|
||||
async function withEngine(name, ...args) {
|
||||
const engine = await import("discourse/static/markdown-it");
|
||||
|
@ -136,3 +137,18 @@ export function excerpt(cooked, length) {
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
export function humanizeList(listItems) {
|
||||
const items = Array.from(listItems);
|
||||
const last = items.pop();
|
||||
|
||||
if (items.length === 0) {
|
||||
return last;
|
||||
} else {
|
||||
return [
|
||||
items.join(I18n.t("word_connector.comma")),
|
||||
I18n.t("word_connector.last_item"),
|
||||
last,
|
||||
].join(" ");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { humanizeList } from "discourse/lib/text";
|
||||
import { isAppleDevice } from "discourse/lib/utilities";
|
||||
import deprecated from "discourse-common/lib/deprecated";
|
||||
import { getOwnerWithFallback } from "discourse-common/lib/get-owner";
|
||||
|
@ -302,6 +303,12 @@ export function getUploadMarkdown(upload) {
|
|||
}
|
||||
}
|
||||
|
||||
export function displayErrorForBulkUpload(errors) {
|
||||
const fileNames = humanizeList(errors.mapBy("fileName"));
|
||||
|
||||
dialog.alert(I18n.t("post.errors.upload", { file_name: fileNames }));
|
||||
}
|
||||
|
||||
export function displayErrorForUpload(data, siteSettings, fileName) {
|
||||
if (!fileName) {
|
||||
deprecated(
|
||||
|
|
|
@ -11,6 +11,7 @@ import { cacheShortUploadUrl } from "pretty-text/upload-short-url";
|
|||
import { updateCsrfToken } from "discourse/lib/ajax";
|
||||
import {
|
||||
bindFileInputChangeListener,
|
||||
displayErrorForBulkUpload,
|
||||
displayErrorForUpload,
|
||||
getUploadMarkdown,
|
||||
validateUploadedFile,
|
||||
|
@ -99,6 +100,7 @@ export default Mixin.create(ExtendableUploader, UppyS3Multipart, {
|
|||
|
||||
_bindUploadTarget() {
|
||||
this.set("inProgressUploads", []);
|
||||
this.set("bufferedUploadErrors", []);
|
||||
this.placeholders = {};
|
||||
this._preProcessorStatus = {};
|
||||
this.editorEl = this.element.querySelector(this.editorClass);
|
||||
|
@ -352,6 +354,7 @@ export default Mixin.create(ExtendableUploader, UppyS3Multipart, {
|
|||
this.appEvents.trigger(
|
||||
`${this.composerEventPrefix}:all-uploads-complete`
|
||||
);
|
||||
this._displayBufferedErrors();
|
||||
this._reset();
|
||||
}
|
||||
}
|
||||
|
@ -403,11 +406,11 @@ export default Mixin.create(ExtendableUploader, UppyS3Multipart, {
|
|||
file.meta.error = error;
|
||||
|
||||
if (!this.userCancelled) {
|
||||
displayErrorForUpload(response || error, this.siteSettings, file.name);
|
||||
this._bufferUploadError(response || error, file.name);
|
||||
this.appEvents.trigger(`${this.composerEventPrefix}:upload-error`, file);
|
||||
}
|
||||
|
||||
if (this.inProgressUploads.length === 0) {
|
||||
this._displayBufferedErrors();
|
||||
this._reset();
|
||||
}
|
||||
},
|
||||
|
@ -419,6 +422,24 @@ export default Mixin.create(ExtendableUploader, UppyS3Multipart, {
|
|||
);
|
||||
},
|
||||
|
||||
_displayBufferedErrors() {
|
||||
if (this.bufferedUploadErrors.length === 0) {
|
||||
return;
|
||||
} else if (this.bufferedUploadErrors.length === 1) {
|
||||
displayErrorForUpload(
|
||||
this.bufferedUploadErrors[0].data,
|
||||
this.siteSettings,
|
||||
this.bufferedUploadErrors[0].fileName
|
||||
);
|
||||
} else {
|
||||
displayErrorForBulkUpload(this.bufferedUploadErrors);
|
||||
}
|
||||
},
|
||||
|
||||
_bufferUploadError(data, fileName) {
|
||||
this.bufferedUploadErrors.push({ data, fileName });
|
||||
},
|
||||
|
||||
_setupPreProcessors() {
|
||||
const checksumPreProcessor = {
|
||||
pluginClass: UppyChecksum,
|
||||
|
@ -561,6 +582,7 @@ export default Mixin.create(ExtendableUploader, UppyS3Multipart, {
|
|||
isProcessingUpload: false,
|
||||
isCancellable: false,
|
||||
inProgressUploads: [],
|
||||
bufferedUploadErrors: [],
|
||||
});
|
||||
this._resetPreProcessors();
|
||||
this.fileInputEl.value = "";
|
||||
|
|
|
@ -530,6 +530,53 @@ acceptance("Uppy Composer Attachment - Upload Error", function (needs) {
|
|||
});
|
||||
});
|
||||
|
||||
acceptance(
|
||||
"Uppy Composer Attachment - Multiple Upload Errors",
|
||||
function (needs) {
|
||||
needs.user();
|
||||
needs.pretender((server, helper) => {
|
||||
server.post("/uploads.json", () => {
|
||||
return helper.response(500, {
|
||||
success: false,
|
||||
});
|
||||
});
|
||||
});
|
||||
needs.settings({
|
||||
simultaneous_uploads: 2,
|
||||
allow_uncategorized_topics: true,
|
||||
});
|
||||
|
||||
test("should show a consolidated message for multiple failed uploads", async function (assert) {
|
||||
await visit("/");
|
||||
await click("#create-topic");
|
||||
const appEvents = loggedInUser().appEvents;
|
||||
const image = createFile("meme1.png");
|
||||
const image1 = createFile("meme2.png");
|
||||
const done = assert.async();
|
||||
|
||||
appEvents.on("composer:upload-error", async () => {
|
||||
await settled();
|
||||
|
||||
if (!query(".dialog-body")) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert.strictEqual(
|
||||
query(".dialog-body").textContent.trim(),
|
||||
"Sorry, there was an error uploading meme1.png and meme2.png. Please try again.",
|
||||
"it should show a consolidated error dialog"
|
||||
);
|
||||
|
||||
await click(".dialog-footer .btn-primary");
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
appEvents.trigger("composer:add-files", [image, image1]);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
acceptance("Uppy Composer Attachment - Upload Handler", function (needs) {
|
||||
needs.user();
|
||||
needs.pretender(pretender);
|
||||
|
|
|
@ -163,6 +163,7 @@ en:
|
|||
|
||||
word_connector:
|
||||
comma: ", "
|
||||
last_item: "and"
|
||||
|
||||
action_codes:
|
||||
public_topic: "Made this topic public %{when}"
|
||||
|
|
Loading…
Reference in New Issue
Block a user