DEV: refactor bootbox alerts (#18292)

This commit is contained in:
Penar Musaraj 2022-09-27 14:47:13 -04:00 committed by GitHub
parent 5dea425ee9
commit cc4af80c7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 243 additions and 186 deletions

View File

@ -1,12 +1,13 @@
import Component from "@ember/component";
import { alias, equal } from "@ember/object/computed";
import bootbox from "bootbox";
import discourseComputed from "discourse-common/utils/decorators";
import { action } from "@ember/object";
import I18n from "I18n";
import { inject as service } from "@ember/service";
export default Component.extend({
classNames: ["watched-word"],
dialog: service(),
isReplace: equal("actionKey", "replace"),
isTag: equal("actionKey", "tag"),
@ -26,7 +27,7 @@ export default Component.extend({
this.action(this.word);
})
.catch((e) => {
bootbox.alert(
this.dialog.alert(
I18n.t("generic_error_with_reason", {
error: `http: ${e.status} - ${e.body}`,
})

View File

@ -1,14 +1,15 @@
import Component from "@ember/component";
import I18n from "I18n";
import Permalink from "admin/models/permalink";
import bootbox from "bootbox";
import discourseComputed, { bind } from "discourse-common/utils/decorators";
import { fmt } from "discourse/lib/computed";
import { schedule } from "@ember/runloop";
import { action } from "@ember/object";
import { inject as service } from "@ember/service";
export default Component.extend({
tagName: "",
dialog: service(),
formSubmitted: false,
permalinkType: "topic_id",
permalinkTypePlaceholder: fmt("permalinkType", "admin.permalink.%@"),
@ -29,7 +30,7 @@ export default Component.extend({
@bind
focusPermalink() {
schedule("afterRender", () =>
this.element.querySelector(".permalink-url")?.focus()
document.querySelector(".permalink-url")?.focus()
);
},
@ -74,7 +75,12 @@ export default Component.extend({
} else {
error = I18n.t("generic_error");
}
bootbox.alert(error, this.focusPermalink);
this.dialog.alert({
message: error,
didConfirm: () => this.focusPermalink(),
didCancel: () => this.focusPermalink(),
});
}
);
}

View File

@ -2,8 +2,8 @@ import discourseComputed from "discourse-common/utils/decorators";
import Component from "@ember/component";
import I18n from "I18n";
import ScreenedIpAddress from "admin/models/screened-ip-address";
import bootbox from "bootbox";
import { schedule } from "@ember/runloop";
import { inject as service } from "@ember/service";
/**
A form to create an IP address that will be blocked or allowed.
@ -18,6 +18,7 @@ import { schedule } from "@ember/runloop";
export default Component.extend({
tagName: "form",
dialog: service(),
classNames: ["screened-ip-address-form", "inline-form"],
formSubmitted: false,
actionName: "block",
@ -47,6 +48,12 @@ export default Component.extend({
}
},
focusInput() {
schedule("afterRender", () => {
this.element.querySelector("input").focus();
});
},
actions: {
submit() {
if (!this.formSubmitted) {
@ -60,22 +67,20 @@ export default Component.extend({
.then((result) => {
this.setProperties({ ip_address: "", formSubmitted: false });
this.action(ScreenedIpAddress.create(result.screened_ip_address));
schedule("afterRender", () =>
this.element.querySelector("input").focus()
);
this.focusInput();
})
.catch((e) => {
this.set("formSubmitted", false);
const msg = e.jqXHR.responseJSON?.errors
const message = e.jqXHR.responseJSON?.errors
? I18n.t("generic_error_with_reason", {
error: e.jqXHR.responseJSON.errors.join(". "),
})
: I18n.t("generic_error");
bootbox.alert(msg, () =>
schedule("afterRender", () =>
this.element.querySelector("input").focus()
)
);
this.dialog.alert({
message,
didConfirm: () => this.focusInput(),
didCancel: () => this.focusInput(),
});
});
}
},

View File

@ -2,10 +2,11 @@ import Component from "@ember/component";
import I18n from "I18n";
import UppyUploadMixin from "discourse/mixins/uppy-upload";
import { alias } from "@ember/object/computed";
import bootbox from "bootbox";
import { inject as service } from "@ember/service";
export default Component.extend(UppyUploadMixin, {
type: "csv",
dialog: service(),
uploadUrl: "/tags/upload",
addDisabled: alias("uploading"),
elementId: "tag-uploader",
@ -16,9 +17,8 @@ export default Component.extend(UppyUploadMixin, {
},
uploadDone() {
bootbox.alert(I18n.t("tagging.upload_successful"), () => {
this.refresh();
this.closeModal();
});
this.refresh();
this.dialog.alert(I18n.t("tagging.upload_successful"));
},
});

View File

@ -2,13 +2,14 @@ import discourseComputed, { observes } from "discourse-common/utils/decorators";
import Component from "@ember/component";
import I18n from "I18n";
import WatchedWord from "admin/models/watched-word";
import bootbox from "bootbox";
import { equal } from "@ember/object/computed";
import { isEmpty } from "@ember/utils";
import { schedule } from "@ember/runloop";
import { inject as service } from "@ember/service";
export default Component.extend({
tagName: "form",
dialog: service(),
classNames: ["watched-word-form"],
formSubmitted: false,
actionKey: null,
@ -55,6 +56,10 @@ export default Component.extend({
});
},
focusInput() {
schedule("afterRender", () => this.element.querySelector("input").focus());
},
actions: {
changeSelectedTags(tags) {
this.setProperties({
@ -98,22 +103,20 @@ export default Component.extend({
isCaseSensitive: false,
});
this.action(WatchedWord.create(result));
schedule("afterRender", () =>
this.element.querySelector("input").focus()
);
this.focusInput();
})
.catch((e) => {
this.set("formSubmitted", false);
const msg = e.jqXHR.responseJSON?.errors
const message = e.jqXHR.responseJSON?.errors
? I18n.t("generic_error_with_reason", {
error: e.jqXHR.responseJSON.errors.join(". "),
})
: I18n.t("generic_error");
bootbox.alert(msg, () =>
schedule("afterRender", () =>
this.element.querySelector("input").focus()
)
);
this.dialog.alert({
message,
didConfirm: () => this.focusInput(),
didCancel: () => this.focusInput(),
});
});
}
},

View File

@ -2,7 +2,7 @@ import Component from "@ember/component";
import I18n from "I18n";
import UppyUploadMixin from "discourse/mixins/uppy-upload";
import { alias } from "@ember/object/computed";
import bootbox from "bootbox";
import { dialog } from "discourse/lib/uploads";
export default Component.extend(UppyUploadMixin, {
type: "txt",
@ -21,7 +21,7 @@ export default Component.extend(UppyUploadMixin, {
uploadDone() {
if (this) {
bootbox.alert(I18n.t("admin.watched_words.form.upload_successful"));
dialog.alert(I18n.t("admin.watched_words.form.upload_successful"));
this.done();
}
},

View File

@ -1,12 +1,13 @@
import Controller from "@ember/controller";
import I18n from "I18n";
import { ajax } from "discourse/lib/ajax";
import bootbox from "bootbox";
import { extractError } from "discourse/lib/ajax-error";
import { action } from "@ember/object";
import { tracked } from "@glimmer/tracking";
import { inject as service } from "@ember/service";
export default class AdminBadgesAwardController extends Controller {
@service dialog;
@tracked saving = false;
@tracked replaceBadgeOwners = false;
@tracked grantExistingHolders = false;
@ -84,7 +85,7 @@ export default class AdminBadgesAwardController extends Controller {
})
.finally(() => (this.saving = false));
} else {
bootbox.alert(I18n.t("admin.badges.mass_award.aborted"));
this.dialog.alert(I18n.t("admin.badges.mass_award.aborted"));
}
}
}

View File

@ -1,9 +1,11 @@
import Controller from "@ember/controller";
import I18n from "I18n";
import bootbox from "bootbox";
import discourseComputed from "discourse-common/utils/decorators";
import { inject as service } from "@ember/service";
export default Controller.extend({
dialog: service(),
@discourseComputed("model.isSaving")
saveButtonText(isSaving) {
return isSaving ? I18n.t("saving") : I18n.t("admin.customize.save");
@ -27,7 +29,7 @@ export default Controller.extend({
error: e.jqXHR.responseJSON.errors.join(". "),
})
: I18n.t("generic_error");
bootbox.alert(msg);
this.dialog.alert(msg);
})
.finally(() => this.set("model.changed", false));
}

View File

@ -1,14 +1,14 @@
import { empty, notEmpty, or } from "@ember/object/computed";
import Controller from "@ember/controller";
import EmailPreview from "admin/models/email-preview";
import bootbox from "bootbox";
import { get } from "@ember/object";
import { popupAjaxError } from "discourse/lib/ajax-error";
import { inject as service } from "@ember/service";
export default Controller.extend({
dialog: service(),
username: null,
lastSeen: null,
emailEmpty: empty("email"),
sendEmailDisabled: or("emailEmpty", "sendingEmail"),
showSendEmailForm: notEmpty("model.html_content"),
@ -50,7 +50,7 @@ export default Controller.extend({
EmailPreview.sendDigest(this.username, this.lastSeen, this.email)
.then((result) => {
if (result.errors) {
bootbox.alert(result.errors);
this.dialog.alert(result.errors);
} else {
this.set("sentEmail", true);
}

View File

@ -3,10 +3,12 @@ import Controller from "@ember/controller";
import I18n from "I18n";
import ModalFunctionality from "discourse/mixins/modal-functionality";
import { ajax } from "discourse/lib/ajax";
import bootbox from "bootbox";
import { observes } from "discourse-common/utils/decorators";
import { inject as service } from "@ember/service";
export default Controller.extend(ModalFunctionality, {
dialog: service(),
@observes("model")
modelChanged() {
const model = this.model;
@ -78,7 +80,7 @@ export default Controller.extend(ModalFunctionality, {
this.setProperties({ model: null, workingCopy: null });
this.send("closeModal");
},
() => bootbox.alert(I18n.t("generic_error"))
() => this.dialog.alert(I18n.t("generic_error"))
);
},
},

View File

@ -2,9 +2,10 @@ import Controller from "@ember/controller";
import I18n from "I18n";
import ModalFunctionality from "discourse/mixins/modal-functionality";
import { ajax } from "discourse/lib/ajax";
import bootbox from "bootbox";
import { inject as service } from "@ember/service";
export default Controller.extend(ModalFunctionality, {
dialog: service(),
loading: true,
reseeding: false,
categories: null,
@ -35,11 +36,11 @@ export default Controller.extend(ModalFunctionality, {
},
type: "POST",
})
.then(
() => this.send("closeModal"),
() => bootbox.alert(I18n.t("generic_error"))
)
.finally(() => this.set("reseeding", false));
.catch(() => this.dialog.alert(I18n.t("generic_error")))
.finally(() => {
this.set("reseeding", false);
this.send("closeModal");
});
},
},
});

View File

@ -2,11 +2,13 @@ import Badge from "discourse/models/badge";
import I18n from "I18n";
import Route from "@ember/routing/route";
import { ajax } from "discourse/lib/ajax";
import bootbox from "bootbox";
import { action, get } from "@ember/object";
import showModal from "discourse/lib/show-modal";
import { inject as service } from "@ember/service";
export default class AdminBadgesShowRoute extends Route {
@service dialog;
serialize(m) {
return { badge_id: get(m, "id") || "new" };
}
@ -58,7 +60,7 @@ export default class AdminBadgesShowRoute extends Route {
badge.set("preview_loading", false);
// eslint-disable-next-line no-console
console.error(error);
bootbox.alert("Network error");
this.dialog.alert("Network error");
});
}
}

View File

@ -1,7 +1,7 @@
import AdminUser from "admin/models/admin-user";
import I18n from "I18n";
import { Promise } from "rsvp";
import Service from "@ember/service";
import Service, { inject as service } from "@ember/service";
import { ajax } from "discourse/lib/ajax";
import bootbox from "bootbox";
import { getOwner } from "discourse-common/lib/get-owner";
@ -12,6 +12,8 @@ import showModal from "discourse/lib/show-modal";
// and the admin application. Use this if you need front end code to access admin
// modules. Inject it optionally, and if it exists go to town!
export default Service.extend({
dialog: service(),
showActionLogs(target, filters) {
const controller = getOwner(target).lookup(
"controller:adminLogs.staffActionLogs"
@ -120,7 +122,7 @@ export default Service.extend({
}
})
.catch(() => {
bootbox.alert(I18n.t("admin.user.delete_failed"));
this.dialog.alert(I18n.t("admin.user.delete_failed"));
reject();
});
},

View File

@ -2,13 +2,12 @@ import Component from "@ember/component";
import { action } from "@ember/object";
import I18n from "I18n";
import { ajax } from "discourse/lib/ajax";
import bootbox from "bootbox";
import { inject as service } from "@ember/service";
export default Component.extend({
dialog: service(),
tagName: "",
selectableUserBadges: null,
_selectedUserBadgeId: null,
_isSaved: false,
_isSaving: false,
@ -42,7 +41,7 @@ export default Component.extend({
this.currentUser.set("title", selectedUserBadge?.badge?.name || "");
},
() => {
bootbox.alert(I18n.t("generic_error"));
this.dialog.alert(I18n.t("generic_error"));
}
)
.finally(() => this.set("_isSaving", false));

View File

@ -18,14 +18,16 @@ import { and, notEmpty } from "@ember/object/computed";
import { popupAjaxError } from "discourse/lib/ajax-error";
import discourseLater from "discourse-common/lib/later";
import { inject as service } from "@ember/service";
const BOOKMARK_BINDINGS = {
enter: { handler: "saveAndClose" },
"d d": { handler: "delete" },
};
export default Component.extend({
dialog: service(),
tagName: "",
errorMessage: null,
selectedReminderType: null,
_closeWithoutSaving: null,
@ -227,7 +229,7 @@ export default Component.extend({
_handleSaveError(e) {
this._savingBookmarkManually = false;
if (typeof e === "string") {
bootbox.alert(e);
this.dialog.alert(e);
} else {
popupAjaxError(e);
}

View File

@ -1,7 +1,6 @@
import Component from "@ember/component";
import FilterModeMixin from "discourse/mixins/filter-mode";
import NavItem from "discourse/models/nav-item";
import bootbox from "bootbox";
import discourseComputed from "discourse-common/utils/decorators";
import { NotificationLevels } from "discourse/lib/notification-levels";
import { getOwner } from "discourse-common/lib/get-owner";
@ -9,7 +8,7 @@ import { inject as service } from "@ember/service";
export default Component.extend(FilterModeMixin, {
router: service(),
dialog: service(),
tagName: "",
// Should be a `readOnly` instead but some themes/plugins still pass
@ -158,7 +157,7 @@ export default Component.extend(FilterModeMixin, {
clickCreateTopicButton() {
if (this.categoryReadOnlyBanner && !this.hasDraft) {
bootbox.alert(this.categoryReadOnlyBanner);
this.dialog.alert(this.categoryReadOnlyBanner);
} else {
this.createTopic();
}

View File

@ -2,11 +2,12 @@ import Component from "@ember/component";
import { isEmpty } from "@ember/utils";
import discourseComputed, { on } from "discourse-common/utils/decorators";
import I18n from "I18n";
import bootbox from "bootbox";
import { inject as service } from "@ember/service";
import { action } from "@ember/object";
export default Component.extend({
tagName: "",
dialog: service(),
imapSettingsValid: false,
smtpSettingsValid: false,
@ -71,16 +72,11 @@ export default Component.extend({
this.group.smtp_enabled &&
this._anySmtpFieldsFilled()
) {
bootbox.confirm(
I18n.t("groups.manage.email.smtp_disable_confirm"),
(result) => {
if (!result) {
this.group.set("smtp_enabled", true);
} else {
this.group.set("imap_enabled", false);
}
}
);
this.dialog.confirm({
message: I18n.t("groups.manage.email.smtp_disable_confirm"),
didConfirm: () => this.group.set("smtp_enabled", true),
didCancel: () => this.group.set("imap_enabled", false),
});
}
this.group.set("smtp_enabled", event.target.checked);
@ -93,14 +89,10 @@ export default Component.extend({
this.group.imap_enabled &&
this._anyImapFieldsFilled()
) {
bootbox.confirm(
I18n.t("groups.manage.email.imap_disable_confirm"),
(result) => {
if (!result) {
this.group.set("imap_enabled", true);
}
}
);
this.dialog.confirm({
message: I18n.t("groups.manage.email.imap_disable_confirm"),
didConfirm: () => this.group.set("imap_enabled", true),
});
}
this.group.set("imap_enabled", event.target.checked);

View File

@ -1,5 +1,4 @@
import Component from "@ember/component";
import bootbox from "bootbox";
import { isBlank } from "@ember/utils";
import {
authorizedExtensions,
@ -8,6 +7,7 @@ import {
import { action } from "@ember/object";
import discourseComputed, { bind } from "discourse-common/utils/decorators";
import I18n from "I18n";
import { inject as service } from "@ember/service";
// This picker is intended to be used with UppyUploadMixin or with
// ComposerUploadUppy, which is why there are no change events registered
@ -18,6 +18,7 @@ import I18n from "I18n";
// is sometimes useful if you need to do something outside the uppy upload with
// the file, such as directly using JSON or CSV data from a file in JS.
export default Component.extend({
dialog: service(),
fileInputId: null,
fileInputClass: null,
fileInputDisabled: false,
@ -87,7 +88,7 @@ export default Component.extend({
const message = I18n.t("pick_files_button.unsupported_file_picked", {
types: this.acceptedFileTypesString,
});
bootbox.alert(message);
this.dialog.alert(message);
return;
}
this.onFilesPicked(files);

View File

@ -9,6 +9,7 @@ import { popupAjaxError } from "discourse/lib/ajax-error";
import { inject as service } from "@ember/service";
export default Component.extend({
dialog: service(),
tagName: "",
loading: false,
tagInfo: null,
@ -159,13 +160,13 @@ export default Component.extend({
this.set("newSynonyms", null);
this.loadTagInfo();
} else if (response.failed_tags) {
bootbox.alert(
this.dialog.alert(
I18n.t("tagging.add_synonyms_failed", {
tag_names: Object.keys(response.failed_tags).join(", "),
})
);
} else {
bootbox.alert(I18n.t("generic_error"));
this.dialog.alert(I18n.t("generic_error"));
}
})
.catch(popupAjaxError);

View File

@ -2,9 +2,9 @@ import Controller from "@ember/controller";
import I18n from "I18n";
import { action } from "@ember/object";
import { ajax } from "discourse/lib/ajax";
import bootbox from "bootbox";
import { popupAjaxError } from "discourse/lib/ajax-error";
import discourseComputed from "discourse-common/utils/decorators";
import { inject as service } from "@ember/service";
export function popupAutomaticMembershipAlert(group_id, email_domains) {
if (!email_domains) {
@ -25,7 +25,7 @@ export function popupAutomaticMembershipAlert(group_id, email_domains) {
const count = result.user_count;
if (count > 0) {
bootbox.alert(
this.dialog.alert(
I18n.t(
"admin.groups.manage.membership.automatic_membership_user_count",
{ count }
@ -36,6 +36,7 @@ export function popupAutomaticMembershipAlert(group_id, email_domains) {
}
export default Controller.extend({
dialog: service(),
saving: null,
@discourseComputed("model.ownerUsernames")

View File

@ -9,10 +9,10 @@ import Controller from "@ember/controller";
import I18n from "I18n";
import ModalFunctionality from "discourse/mixins/modal-functionality";
import Post from "discourse/models/post";
import bootbox from "bootbox";
import { categoryBadgeHTML } from "discourse/helpers/category-link";
import { iconHTML } from "discourse-common/lib/icon-library";
import { sanitizeAsync } from "discourse/lib/text";
import { inject as service } from "@ember/service";
function customTagArray(val) {
if (!val) {
@ -26,6 +26,7 @@ function customTagArray(val) {
// This controller handles displaying of history
export default Controller.extend(ModalFunctionality, {
dialog: service(),
loading: true,
viewMode: "side_by_side",
@ -139,7 +140,7 @@ export default Controller.extend(ModalFunctionality, {
e.jqXHR.responseJSON.errors &&
e.jqXHR.responseJSON.errors[0]
) {
bootbox.alert(e.jqXHR.responseJSON.errors[0]);
this.dialog.alert(e.jqXHR.responseJSON.errors[0]);
}
});
},

View File

@ -8,7 +8,6 @@ import I18n from "I18n";
import ModalFunctionality from "discourse/mixins/modal-functionality";
import { SECOND_FACTOR_METHODS } from "discourse/models/user";
import { ajax } from "discourse/lib/ajax";
import bootbox from "bootbox";
import discourseComputed from "discourse-common/utils/decorators";
import { escape } from "pretty-text/sanitizer";
import { extractError } from "discourse/lib/ajax-error";
@ -19,6 +18,7 @@ import { isEmpty } from "@ember/utils";
import { setting } from "discourse/lib/computed";
import showModal from "discourse/lib/show-modal";
import { wavingHandURL } from "discourse/lib/waving-hand-url";
import { inject as service } from "@ember/service";
// This is happening outside of the app via popup
const AuthErrors = [
@ -33,6 +33,7 @@ export default Controller.extend(ModalFunctionality, {
createAccount: controller(),
forgotPassword: controller(),
application: controller(),
dialog: service(),
loggingIn: false,
loggedIn: false,
@ -199,7 +200,7 @@ export default Controller.extend(ModalFunctionality, {
});
} else if (result.reason === "suspended") {
this.send("closeModal");
bootbox.alert(result.error);
this.dialog.alert(result.error);
} else {
this.flash(result.error, "error");
}

View File

@ -10,12 +10,14 @@ import { readOnly } from "@ember/object/computed";
import bootbox from "bootbox";
import { endWith } from "discourse/lib/computed";
import { action } from "@ember/object";
import { inject as service } from "@ember/service";
export default DiscoverySortableController.extend(
BulkTopicSelection,
FilterModeMixin,
{
application: controller(),
dialog: service(),
tag: null,
additionalTags: null,
@ -172,7 +174,7 @@ export default DiscoverySortableController.extend(
this.tag
.destroyRecord()
.then(() => this.transitionToRoute("tags.index"))
.catch(() => bootbox.alert(I18n.t("generic_error")));
.catch(() => this.dialog.alert(I18n.t("generic_error")));
});
},

View File

@ -7,10 +7,12 @@ import discourseComputed from "discourse-common/utils/decorators";
import { popupAjaxError } from "discourse/lib/ajax-error";
import showModal from "discourse/lib/show-modal";
import { inject as service } from "@ember/service";
export default Controller.extend({
dialog: service(),
sortedByCount: true,
sortedByName: false,
canAdminTags: alias("currentUser.staff"),
groupedByCategory: notEmpty("model.extras.categories"),
groupedByTagGroup: notEmpty("model.extras.tag_groups"),
@ -67,7 +69,7 @@ export default Controller.extend({
const tags = result["tags"];
if (tags.length === 0) {
bootbox.alert(I18n.t("tagging.delete_no_unused_tags"));
this.dialog.alert(I18n.t("tagging.delete_no_unused_tags"));
return;
}

View File

@ -6,6 +6,8 @@ import { Promise } from "rsvp";
import Topic from "discourse/models/topic";
import bootbox from "bootbox";
import { inject as service } from "@ember/service";
const _buttons = [];
const alwaysTrue = () => true;
@ -118,7 +120,7 @@ addBulkButton("deleteTopics", "delete", {
// Modal for performing bulk actions on topics
export default Controller.extend(ModalFunctionality, {
userPrivateMessages: controller("user-private-messages"),
dialog: service(),
tags: null,
emptyTags: empty("tags"),
categoryId: alias("model.category.id"),
@ -151,7 +153,7 @@ export default Controller.extend(ModalFunctionality, {
return this._processChunks(operation)
.catch(() => {
bootbox.alert(I18n.t("generic_error"));
this.dialog.alert(I18n.t("generic_error"));
})
.finally(() => {
this.set("loading", false);

View File

@ -3,7 +3,6 @@ import ModalFunctionality from "discourse/mixins/modal-functionality";
import { action } from "@ember/object";
import { inject as service } from "@ember/service";
import { popupAjaxError } from "discourse/lib/ajax-error";
import bootbox from "bootbox";
import discourseComputed from "discourse-common/utils/decorators";
import ItsATrap from "@discourse/itsatrap";
import {
@ -90,7 +89,7 @@ export default Controller.extend(ModalFunctionality, {
_handleError(e) {
if (typeof e === "string") {
bootbox.alert(e);
this.dialog.alert(e);
} else {
popupAjaxError(e);
}

View File

@ -1,5 +1,5 @@
import I18n from "I18n";
import bootbox from "bootbox";
import { getOwner } from "discourse-common/lib/get-owner";
export function extractError(error, defaultMessage) {
if (error instanceof Error) {
@ -64,5 +64,6 @@ export function throwAjaxError(undoCallback) {
}
export function popupAjaxError(error) {
bootbox.alert(extractError(error));
const dialog = getOwner(this).lookup("service:dialog");
dialog.alert(extractError(error));
}

View File

@ -3,13 +3,13 @@ import I18n from "I18n";
import { Promise } from "rsvp";
import User from "discourse/models/user";
import { ajax } from "discourse/lib/ajax";
import bootbox from "bootbox";
import getURL, { samePrefix } from "discourse-common/lib/get-url";
import { isTesting } from "discourse-common/config/environment";
import discourseLater from "discourse-common/lib/later";
import { selectedText } from "discourse/lib/utilities";
import { wantsNewWindow } from "discourse/lib/intercept-click";
import deprecated from "discourse-common/lib/deprecated";
import { getOwner } from "discourse-common/lib/get-owner";
export function isValidLink(link) {
// eslint-disable-next-line no-undef
@ -121,7 +121,8 @@ export default {
siteSettings?.prevent_anons_from_downloading_files &&
!User.current()
) {
bootbox.alert(I18n.t("post.errors.attachment_download_requires_login"));
const dialog = getOwner(this).lookup("service:dialog");
dialog.alert(I18n.t("post.errors.attachment_download_requires_login"));
} else if (wantsNewWindow(e)) {
const newWindow = window.open(href, "_blank");
newWindow.opener = null;

View File

@ -1,10 +1,12 @@
import I18n from "I18n";
import bootbox from "bootbox";
import { getOwner } from "discourse-common/lib/get-owner";
export function outputExportResult(result) {
const dialog = getOwner(this).lookup("service:dialog");
if (result.success) {
bootbox.alert(I18n.t("admin.export_csv.success"));
dialog.alert(I18n.t("admin.export_csv.success"));
} else {
bootbox.alert(I18n.t("admin.export_csv.failed"));
dialog.alert(I18n.t("admin.export_csv.failed"));
}
}

View File

@ -1,7 +1,7 @@
import I18n from "I18n";
import deprecated from "discourse-common/lib/deprecated";
import bootbox from "bootbox";
import { isAppleDevice } from "discourse/lib/utilities";
import { getOwner } from "discourse-common/lib/get-owner";
function isGUID(value) {
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(
@ -9,6 +9,14 @@ function isGUID(value) {
);
}
// This wrapper simplifies unit testing the dialog service
export const dialog = {
alert(msg) {
const dg = getOwner(this).lookup("service:dialog");
dg.alert(msg);
},
};
export function markdownNameFromFileName(fileName) {
let name = fileName.slice(0, fileName.lastIndexOf("."));
@ -25,7 +33,7 @@ export function validateUploadedFiles(files, opts) {
}
if (files.length > 1) {
bootbox.alert(I18n.t("post.errors.too_many_uploads"));
dialog.alert(I18n.t("post.errors.too_many_uploads"));
return false;
}
@ -74,7 +82,7 @@ export function validateUploadedFile(file, opts) {
if (opts.imagesOnly) {
if (!isImage(name) && !isAuthorizedImage(name, staff, opts.siteSettings)) {
bootbox.alert(
dialog.alert(
I18n.t("post.errors.upload_not_authorized", {
authorized_extensions: authorizedImagesExtensions(
staff,
@ -86,7 +94,7 @@ export function validateUploadedFile(file, opts) {
}
} else if (opts.csvOnly) {
if (!/\.csv$/i.test(name)) {
bootbox.alert(I18n.t("user.invited.bulk_invite.error"));
dialog.alert(I18n.t("user.invited.bulk_invite.error"));
return false;
}
} else {
@ -94,7 +102,7 @@ export function validateUploadedFile(file, opts) {
!authorizesAllExtensions(staff, opts.siteSettings) &&
!isAuthorizedFile(name, staff, opts.siteSettings)
) {
bootbox.alert(
dialog.alert(
I18n.t("post.errors.upload_not_authorized", {
authorized_extensions: authorizedExtensions(
staff,
@ -109,7 +117,7 @@ export function validateUploadedFile(file, opts) {
if (!opts.bypassNewUserRestriction) {
// ensures that new users can upload a file
if (user && !user.isAllowedToUploadAFile(opts.type)) {
bootbox.alert(
dialog.alert(
I18n.t(`post.errors.${opts.type}_upload_not_allowed_for_new_user`)
);
return false;
@ -119,7 +127,7 @@ export function validateUploadedFile(file, opts) {
if (file.size === 0) {
/* eslint-disable no-console */
console.warn("File with a 0 byte size detected, cancelling upload.", file);
bootbox.alert(I18n.t("post.errors.file_size_zero"));
dialog.alert(I18n.t("post.errors.file_size_zero"));
return false;
}
@ -321,26 +329,26 @@ export function displayErrorForUpload(data, siteSettings, fileName) {
return;
}
} else if (data.errors && data.errors.length > 0) {
bootbox.alert(data.errors.join("\n"));
dialog.alert(data.errors.join("\n"));
return;
}
// otherwise, display a generic error message
bootbox.alert(I18n.t("post.errors.upload"));
dialog.alert(I18n.t("post.errors.upload"));
}
function displayErrorByResponseStatus(status, body, fileName, siteSettings) {
switch (status) {
// didn't get headers from server, or browser refuses to tell us
case 0:
bootbox.alert(I18n.t("post.errors.upload"));
dialog.alert(I18n.t("post.errors.upload"));
return true;
// entity too large, usually returned from the web server
case 413:
const type = uploadTypeFromFileName(fileName);
const max_size_kb = siteSettings[`max_${type}_size_kb`];
bootbox.alert(
dialog.alert(
I18n.t("post.errors.file_too_large_humanized", {
max_size: I18n.toHumanSize(max_size_kb * 1024),
})
@ -350,9 +358,9 @@ function displayErrorByResponseStatus(status, body, fileName, siteSettings) {
// the error message is provided by the server
case 422:
if (body.message) {
bootbox.alert(body.message);
dialog.alert(body.message);
} else {
bootbox.alert(body.errors.join("\n"));
dialog.alert(body.errors.join("\n"));
}
return true;
}

View File

@ -19,7 +19,7 @@ import {
validateUploadedFile,
} from "discourse/lib/uploads";
import { cacheShortUploadUrl } from "pretty-text/upload-short-url";
import bootbox from "bootbox";
import { inject as service } from "@ember/service";
import { run } from "@ember/runloop";
import escapeRegExp from "discourse-common/utils/escape-regexp";
@ -36,6 +36,7 @@ import escapeRegExp from "discourse-common/utils/escape-regexp";
// functionality and event binding.
//
export default Mixin.create(ExtendableUploader, UppyS3Multipart, {
dialog: service(),
uploadRootPath: "/uploads",
uploadTargetBound: false,
useUploadPlaceholders: true,
@ -186,7 +187,7 @@ export default Mixin.create(ExtendableUploader, UppyS3Multipart, {
// _not_ been handled by an upload handler.
const fileCount = Object.keys(unhandledFiles).length;
if (maxFiles > 0 && fileCount > maxFiles) {
bootbox.alert(
this.dialog.alert(
I18n.t("post.errors.too_many_dragged_and_dropped_files", {
count: maxFiles,
})

View File

@ -21,11 +21,12 @@ import UppyS3Multipart from "discourse/mixins/uppy-s3-multipart";
import UppyChunkedUploader from "discourse/lib/uppy-chunked-uploader-plugin";
import { bind, on } from "discourse-common/utils/decorators";
import { warn } from "@ember/debug";
import bootbox from "bootbox";
import { inject as service } from "@ember/service";
export const HUGE_FILE_THRESHOLD_BYTES = 104_857_600; // 100MB
export default Mixin.create(UppyS3Multipart, ExtendableUploader, {
dialog: service(),
uploading: false,
uploadProgress: 0,
_uppyInstance: null,
@ -130,7 +131,7 @@ export default Mixin.create(UppyS3Multipart, ExtendableUploader, {
}
if (tooMany) {
bootbox.alert(
this.dialog.alert(
I18n.t("post.errors.too_many_dragged_and_dropped_files", {
count: this.allowMultipleFiles ? maxFiles : 1,
})

View File

@ -5,7 +5,6 @@ import DiscourseRoute from "discourse/routes/discourse";
import I18n from "I18n";
import OpenComposer from "discourse/mixins/open-composer";
import { ajax } from "discourse/lib/ajax";
import bootbox from "bootbox";
import { findAll } from "discourse/models/login-method";
import { getOwner } from "discourse-common/lib/get-owner";
import getURL from "discourse-common/lib/get-url";
@ -18,7 +17,7 @@ import showModal from "discourse/lib/show-modal";
function unlessReadOnly(method, message) {
return function () {
if (this.site.isReadOnly) {
bootbox.alert(message);
this.dialog.alert(message);
} else {
this[method]();
}
@ -28,7 +27,7 @@ function unlessReadOnly(method, message) {
function unlessStrictlyReadOnly(method, message) {
return function () {
if (this.site.isReadOnly && !this.site.isStaffWritesOnly) {
bootbox.alert(message);
this.dialog.alert(message);
} else {
this[method]();
}
@ -39,6 +38,7 @@ const ApplicationRoute = DiscourseRoute.extend(OpenComposer, {
siteTitle: setting("title"),
shortSiteDescription: setting("short_site_description"),
documentTitle: service(),
dialog: service(),
actions: {
toggleAnonymous() {

View File

@ -1,11 +1,13 @@
import DiscourseRoute from "discourse/routes/discourse";
import Group from "discourse/models/group";
import I18n from "I18n";
import bootbox from "bootbox";
import cookie from "discourse/lib/cookie";
import { next } from "@ember/runloop";
import { inject as service } from "@ember/service";
export default DiscourseRoute.extend({
dialog: service(),
beforeModel(transition) {
const params = transition.to.queryParams;
@ -32,12 +34,12 @@ export default DiscourseRoute.extend({
})
);
} else {
bootbox.alert(
this.dialog.alert(
I18n.t("composer.cant_send_pm", { username: groupName })
);
}
})
.catch(() => bootbox.alert(I18n.t("generic_error")));
.catch(() => this.dialog.alert(I18n.t("generic_error")));
} else {
e.send("createNewMessageViaParams", {
topicTitle: params.title,

View File

@ -11,7 +11,6 @@ import I18n from "I18n";
import PostCooked from "discourse/widgets/post-cooked";
import { Promise } from "rsvp";
import RawHtml from "discourse/widgets/raw-html";
import bootbox from "bootbox";
import { dateNode } from "discourse/helpers/node";
import { h } from "virtual-dom";
import hbs from "discourse/widgets/hbs-compiler";
@ -814,6 +813,7 @@ export function addPostClassesCallback(callback) {
export default createWidget("post", {
buildKey: (attrs) => `post-${attrs.id}`,
services: ["dialog"],
shadowTree: true,
buildAttributes(attrs) {
@ -918,7 +918,7 @@ export default createWidget("post", {
const { remaining, max } = result;
const threshold = Math.ceil(max * 0.1);
if (remaining === threshold) {
bootbox.alert(I18n.t("post.few_likes_left"));
this.dialog.alert(I18n.t("post.few_likes_left"));
kvs.set({ key: "lastWarnedLikes", value: Date.now() });
}
},

View File

@ -44,7 +44,7 @@ acceptance("Category Banners", function (needs) {
await visit("/c/test-read-only-without-banner");
await click("#create-topic");
assert.ok(!visible(".bootbox.modal"), "it does not pop up a modal");
assert.ok(!visible(".dialog-body"), "it does not pop up a modal");
assert.ok(
!visible(".category-read-only-banner"),
"it does not show a banner"
@ -55,10 +55,10 @@ acceptance("Category Banners", function (needs) {
await visit("/c/test-read-only-with-banner");
await click("#create-topic");
assert.ok(visible(".bootbox.modal"), "it pops up a modal");
assert.ok(visible(".dialog-body"), "it pops up a modal");
await click(".modal-footer>.btn-primary");
assert.ok(!visible(".bootbox.modal"), "it closes the modal");
await click(".dialog-footer .btn-primary");
assert.ok(!visible(".dialog-body"), "it closes the modal");
assert.ok(visible(".category-read-only-banner"), "it shows a banner");
assert.strictEqual(
count(".category-read-only-banner .inner"),

View File

@ -6,8 +6,7 @@ import {
query,
} from "discourse/tests/helpers/qunit-helpers";
import { withPluginApi } from "discourse/lib/plugin-api";
import bootbox from "bootbox";
import { authorizedExtensions } from "discourse/lib/uploads";
import { authorizedExtensions, dialog } from "discourse/lib/uploads";
import { click, fillIn, settled, visit } from "@ember/test-helpers";
import I18n from "I18n";
import { skip, test } from "qunit";
@ -125,15 +124,16 @@ acceptance("Uppy Composer Attachment - Upload Placeholder", function (needs) {
const image2 = createFile("avatar2.png");
const done = assert.async();
appEvents.on("composer:uploads-aborted", async () => {
await settled();
assert.strictEqual(
query(".bootbox .modal-body").innerHTML,
query(".dialog-body").textContent.trim(),
I18n.t("post.errors.too_many_dragged_and_dropped_files", {
count: 2,
}),
"it should warn about too many files added"
);
await click(".modal-footer .btn-primary");
await click(".dialog-footer .btn-primary");
done();
});
@ -149,8 +149,9 @@ acceptance("Uppy Composer Attachment - Upload Placeholder", function (needs) {
const done = assert.async();
appEvents.on("composer:uploads-aborted", async () => {
await settled();
assert.strictEqual(
query(".bootbox .modal-body").innerHTML,
query(".dialog-body").textContent.trim(),
I18n.t("post.errors.upload_not_authorized", {
authorized_extensions: authorizedExtensions(
false,
@ -160,7 +161,7 @@ acceptance("Uppy Composer Attachment - Upload Placeholder", function (needs) {
"it should warn about unauthorized extensions"
);
await click(".modal-footer .btn-primary");
await click(".dialog-footer .btn-primary");
done();
});
@ -438,14 +439,14 @@ acceptance("Uppy Composer Attachment - Upload Error", function (needs) {
appEvents.on("composer:upload-error", async () => {
sinon.assert.calledOnce(stub);
await settled();
assert.strictEqual(
query(".bootbox .modal-body").innerHTML,
query(".dialog-body").textContent.trim(),
"There was an error uploading the file, the gif was way too cool.",
"it should show the error message from the server"
);
await click(".modal-footer .btn-primary");
await click(".dialog-footer .btn-primary");
done();
});
@ -465,7 +466,7 @@ acceptance("Uppy Composer Attachment - Upload Handler", function (needs) {
api.addComposerUploadHandler(["png"], (files) => {
const file = files[0];
const isNativeFile = file instanceof File ? "WAS" : "WAS NOT";
bootbox.alert(
dialog.alert(
`This is an upload handler test for ${file.name}. The file ${isNativeFile} a native file object.`
);
});
@ -480,12 +481,13 @@ acceptance("Uppy Composer Attachment - Upload Handler", function (needs) {
const done = assert.async();
appEvents.on("composer:uploads-aborted", async () => {
await settled();
assert.strictEqual(
query(".bootbox .modal-body").innerHTML,
query(".dialog-body").textContent.trim(),
"This is an upload handler test for handler-test.png. The file WAS a native file object.",
"it should show the bootbox triggered by the upload handler"
"it should show the dialog triggered by the upload handler"
);
await click(".modal-footer .btn");
await click(".dialog-footer .btn-primary");
done();
});

View File

@ -126,12 +126,12 @@ acceptance(
await click("#enable_smtp");
assert.strictEqual(
query(".modal-body").innerText,
query(".dialog-body").innerText.trim(),
I18n.t("groups.manage.email.smtp_disable_confirm"),
"shows a confirm dialogue warning SMTP settings will be wiped"
);
await click(".modal-footer .btn.btn-primary");
await click(".dialog-footer .btn-primary");
});
test("enabling IMAP, testing, and saving", async function (assert) {
@ -202,11 +202,11 @@ acceptance(
await click("#enable_imap");
assert.strictEqual(
query(".modal-body").innerText,
query(".dialog-body").innerText.trim(),
I18n.t("groups.manage.email.imap_disable_confirm"),
"shows a confirm dialogue warning IMAP settings will be wiped"
);
await click(".modal-footer .btn.btn-primary");
await click(".dialog-footer .btn-primary");
});
}
);
@ -362,11 +362,11 @@ acceptance(
await click(".test-smtp-settings");
assert.strictEqual(
query(".modal-body").innerText,
query(".dialog-body").innerText.trim(),
"There was an issue with the SMTP credentials provided, check the username and password and try again.",
"shows a dialogue with the error message from the server"
);
await click(".modal-footer .btn.btn-primary");
await click(".dialog-footer .btn-primary");
});
}
);

View File

@ -84,9 +84,9 @@ acceptance("User Preferences - Sidebar", function (needs) {
"contains the right request body to update user's sidebar category links"
);
assert.ok(exists(".modal-body"), "error message is displayed");
assert.ok(exists(".dialog-body"), "error message is displayed");
await click(".modal .d-button-label");
await click(".dialog-footer .btn-primary");
assert.ok(
!exists(".sidebar-section-categories .sidebar-section-link-howto"),
@ -152,9 +152,9 @@ acceptance("User Preferences - Sidebar", function (needs) {
"contains the right request body to update user's sidebar tag links"
);
assert.ok(exists(".modal-body"), "error message is displayed");
assert.ok(exists(".dialog-body"), "error message is displayed");
await click(".modal .d-button-label");
await click(".dialog-footer .btn-primary");
assert.ok(
!exists(".sidebar-section-tags .sidebar-section-link-gazelle"),

View File

@ -1,9 +1,12 @@
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import { click, render, waitFor } from "@ember/test-helpers";
import { render } from "@ember/test-helpers";
import { createFile } from "discourse/tests/helpers/qunit-helpers";
import { hbs } from "ember-cli-htmlbars";
import pretender, { response } from "discourse/tests/helpers/create-pretender";
import sinon from "sinon";
import I18n from "I18n";
import { dialog } from "discourse/lib/uploads";
module("Integration | Component | watched-word-uploader", function (hooks) {
setupRenderingTest(hooks);
@ -15,6 +18,8 @@ module("Integration | Component | watched-word-uploader", function (hooks) {
});
test("sets the proper action key on uploads", async function (assert) {
sinon.stub(dialog, "alert");
const done = assert.async();
this.set("actionNameKey", "flag");
this.set("doneUpload", function () {
@ -23,6 +28,12 @@ module("Integration | Component | watched-word-uploader", function (hooks) {
.action_key,
"flag"
);
assert.ok(
dialog.alert.calledWith(
I18n.t("admin.watched_words.form.upload_successful")
),
"alert shown"
);
done();
});
@ -38,8 +49,5 @@ module("Integration | Component | watched-word-uploader", function (hooks) {
await this.container
.lookup("service:app-events")
.trigger("upload-mixin:watched-word-uploader:add-files", words);
await waitFor(".bootbox span.d-button-label");
await click(".bootbox span.d-button-label");
});
});

View File

@ -3,6 +3,7 @@ import {
allowsAttachments,
allowsImages,
authorizedExtensions,
dialog,
displayErrorForUpload,
getUploadMarkdown,
isImage,
@ -10,7 +11,6 @@ import {
} from "discourse/lib/uploads";
import I18n from "I18n";
import User from "discourse/models/user";
import bootbox from "bootbox";
import { discourseModule } from "discourse/tests/helpers/qunit-helpers";
import sinon from "sinon";
import { test } from "qunit";
@ -32,17 +32,17 @@ discourseModule("Unit | Utility | uploads", function () {
});
test("uploading one file", function (assert) {
sinon.stub(bootbox, "alert");
sinon.stub(dialog, "alert");
assert.notOk(
validateUploadedFiles([1, 2], { siteSettings: this.siteSettings })
);
assert.ok(bootbox.alert.calledWith(I18n.t("post.errors.too_many_uploads")));
assert.ok(dialog.alert.calledWith(I18n.t("post.errors.too_many_uploads")));
});
test("new user cannot upload images", function (assert) {
this.siteSettings.newuser_max_embedded_media = 0;
sinon.stub(bootbox, "alert");
sinon.stub(dialog, "alert");
assert.notOk(
validateUploadedFiles([{ name: "image.png" }], {
@ -52,7 +52,7 @@ discourseModule("Unit | Utility | uploads", function () {
"the upload is not valid"
);
assert.ok(
bootbox.alert.calledWith(
dialog.alert.calledWith(
I18n.t("post.errors.image_upload_not_allowed_for_new_user")
),
"the alert is called"
@ -62,7 +62,7 @@ discourseModule("Unit | Utility | uploads", function () {
test("new user can upload images if allowed", function (assert) {
this.siteSettings.newuser_max_embedded_media = 1;
this.siteSettings.default_trust_level = 0;
sinon.stub(bootbox, "alert");
sinon.stub(dialog, "alert");
assert.ok(
validateUploadedFiles([{ name: "image.png" }], {
@ -74,7 +74,7 @@ discourseModule("Unit | Utility | uploads", function () {
test("TL1 can upload images", function (assert) {
this.siteSettings.newuser_max_embedded_media = 0;
sinon.stub(bootbox, "alert");
sinon.stub(dialog, "alert");
assert.ok(
validateUploadedFiles([{ name: "image.png" }], {
@ -86,7 +86,7 @@ discourseModule("Unit | Utility | uploads", function () {
test("new user cannot upload attachments", function (assert) {
this.siteSettings.newuser_max_attachments = 0;
sinon.stub(bootbox, "alert");
sinon.stub(dialog, "alert");
assert.notOk(
validateUploadedFiles([{ name: "roman.txt" }], {
@ -95,21 +95,21 @@ discourseModule("Unit | Utility | uploads", function () {
})
);
assert.ok(
bootbox.alert.calledWith(
dialog.alert.calledWith(
I18n.t("post.errors.attachment_upload_not_allowed_for_new_user")
)
);
});
test("ensures an authorized upload", function (assert) {
sinon.stub(bootbox, "alert");
sinon.stub(dialog, "alert");
assert.notOk(
validateUploadedFiles([{ name: "unauthorized.html" }], {
siteSettings: this.siteSettings,
})
);
assert.ok(
bootbox.alert.calledWith(
dialog.alert.calledWith(
I18n.t("post.errors.upload_not_authorized", {
authorized_extensions: authorizedExtensions(
false,
@ -122,7 +122,7 @@ discourseModule("Unit | Utility | uploads", function () {
test("skipping validation works", function (assert) {
const files = [{ name: "backup.tar.gz" }];
sinon.stub(bootbox, "alert");
sinon.stub(dialog, "alert");
assert.notOk(
validateUploadedFiles(files, {
@ -141,7 +141,7 @@ discourseModule("Unit | Utility | uploads", function () {
test("staff can upload anything in PM", function (assert) {
const files = [{ name: "some.docx" }];
this.siteSettings.authorized_extensions = "jpeg";
sinon.stub(bootbox, "alert");
sinon.stub(dialog, "alert");
let user = User.create({ moderator: true });
assert.notOk(
@ -175,7 +175,7 @@ discourseModule("Unit | Utility | uploads", function () {
};
test("allows valid uploads to go through", function (assert) {
sinon.stub(bootbox, "alert");
sinon.stub(dialog, "alert");
let user = User.create({ trust_level: 1 });
@ -193,7 +193,7 @@ discourseModule("Unit | Utility | uploads", function () {
})
);
assert.notOk(bootbox.alert.calledOnce);
assert.notOk(dialog.alert.calledOnce);
});
test("isImage", function (assert) {
@ -315,7 +315,7 @@ discourseModule("Unit | Utility | uploads", function () {
});
test("displayErrorForUpload - jquery file upload - jqXHR present", function (assert) {
sinon.stub(bootbox, "alert");
sinon.stub(dialog, "alert");
displayErrorForUpload(
{
jqXHR: { status: 422, responseJSON: { message: "upload failed" } },
@ -323,11 +323,11 @@ discourseModule("Unit | Utility | uploads", function () {
{ max_attachment_size_kb: 1024, max_image_size_kb: 1024 },
"test.png"
);
assert.ok(bootbox.alert.calledWith("upload failed"), "the alert is called");
assert.ok(dialog.alert.calledWith("upload failed"), "the alert is called");
});
test("displayErrorForUpload - jquery file upload - jqXHR missing, errors present", function (assert) {
sinon.stub(bootbox, "alert");
sinon.stub(dialog, "alert");
displayErrorForUpload(
{
errors: ["upload failed"],
@ -335,11 +335,11 @@ discourseModule("Unit | Utility | uploads", function () {
{ max_attachment_size_kb: 1024, max_image_size_kb: 1024 },
"test.png"
);
assert.ok(bootbox.alert.calledWith("upload failed"), "the alert is called");
assert.ok(dialog.alert.calledWith("upload failed"), "the alert is called");
});
test("displayErrorForUpload - jquery file upload - no errors", function (assert) {
sinon.stub(bootbox, "alert");
sinon.stub(dialog, "alert");
displayErrorForUpload(
{},
{
@ -349,13 +349,13 @@ discourseModule("Unit | Utility | uploads", function () {
"test.png"
);
assert.ok(
bootbox.alert.calledWith(I18n.t("post.errors.upload")),
dialog.alert.calledWith(I18n.t("post.errors.upload")),
"the alert is called"
);
});
test("displayErrorForUpload - uppy - with response status and body", function (assert) {
sinon.stub(bootbox, "alert");
sinon.stub(dialog, "alert");
displayErrorForUpload(
{
status: 422,
@ -364,6 +364,6 @@ discourseModule("Unit | Utility | uploads", function () {
"test.png",
{ max_attachment_size_kb: 1024, max_image_size_kb: 1024 }
);
assert.ok(bootbox.alert.calledWith("upload failed"), "the alert is called");
assert.ok(dialog.alert.calledWith("upload failed"), "the alert is called");
});
});

View File

@ -8,9 +8,11 @@ import getUrl from "discourse-common/lib/get-url";
import Uppy from "@uppy/core";
import DropTarget from "@uppy/drop-target";
import XHRUpload from "@uppy/xhr-upload";
import { inject as service } from "@ember/service";
export default Component.extend({
classNames: ["wizard-container__image-upload"],
dialog: service(),
uploading: false,
@discourseComputed("field.id")
@ -57,7 +59,7 @@ export default Component.extend({
message = response.body.errors.join("\n");
}
window.bootbox.alert(message);
this.dialog.alert(message);
this.set("uploading", false);
});

View File

@ -8,7 +8,7 @@
}
.dialog-container {
z-index: z("modal", "overlay");
z-index: z("modal", "dialog");
display: flex;
}

View File

@ -79,6 +79,7 @@ $line-height-large: var(--line-height-large) !default;
$z-layers: (
"max": 9999,
"modal": (
"dialog": 1700,
"tooltip": 1600,
"popover": 1500,
"dropdown": 1400,

View File

@ -8,9 +8,10 @@ import discourseComputed from "discourse-common/utils/decorators";
import { htmlSafe } from "@ember/template";
import loadScript from "discourse/lib/load-script";
import { popupAjaxError } from "discourse/lib/ajax-error";
import bootbox from "bootbox";
import { inject as service } from "@ember/service";
export default Controller.extend(ModalFunctionality, {
dialog: service(),
model: null,
charts: null,
groupedBy: null,
@ -64,7 +65,7 @@ export default Controller.extend(ModalFunctionality, {
if (error) {
popupAjaxError(error);
} else {
bootbox.alert(I18n.t("poll.error_while_fetching_voters"));
this.dialog.alert(I18n.t("poll.error_while_fetching_voters"));
}
})
.then((result) => {