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

View File

@ -1,14 +1,15 @@
import Component from "@ember/component"; import Component from "@ember/component";
import I18n from "I18n"; import I18n from "I18n";
import Permalink from "admin/models/permalink"; import Permalink from "admin/models/permalink";
import bootbox from "bootbox";
import discourseComputed, { bind } from "discourse-common/utils/decorators"; import discourseComputed, { bind } from "discourse-common/utils/decorators";
import { fmt } from "discourse/lib/computed"; import { fmt } from "discourse/lib/computed";
import { schedule } from "@ember/runloop"; import { schedule } from "@ember/runloop";
import { action } from "@ember/object"; import { action } from "@ember/object";
import { inject as service } from "@ember/service";
export default Component.extend({ export default Component.extend({
tagName: "", tagName: "",
dialog: service(),
formSubmitted: false, formSubmitted: false,
permalinkType: "topic_id", permalinkType: "topic_id",
permalinkTypePlaceholder: fmt("permalinkType", "admin.permalink.%@"), permalinkTypePlaceholder: fmt("permalinkType", "admin.permalink.%@"),
@ -29,7 +30,7 @@ export default Component.extend({
@bind @bind
focusPermalink() { focusPermalink() {
schedule("afterRender", () => schedule("afterRender", () =>
this.element.querySelector(".permalink-url")?.focus() document.querySelector(".permalink-url")?.focus()
); );
}, },
@ -74,7 +75,12 @@ export default Component.extend({
} else { } else {
error = I18n.t("generic_error"); 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 Component from "@ember/component";
import I18n from "I18n"; import I18n from "I18n";
import ScreenedIpAddress from "admin/models/screened-ip-address"; import ScreenedIpAddress from "admin/models/screened-ip-address";
import bootbox from "bootbox";
import { schedule } from "@ember/runloop"; 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. 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({ export default Component.extend({
tagName: "form", tagName: "form",
dialog: service(),
classNames: ["screened-ip-address-form", "inline-form"], classNames: ["screened-ip-address-form", "inline-form"],
formSubmitted: false, formSubmitted: false,
actionName: "block", actionName: "block",
@ -47,6 +48,12 @@ export default Component.extend({
} }
}, },
focusInput() {
schedule("afterRender", () => {
this.element.querySelector("input").focus();
});
},
actions: { actions: {
submit() { submit() {
if (!this.formSubmitted) { if (!this.formSubmitted) {
@ -60,22 +67,20 @@ export default Component.extend({
.then((result) => { .then((result) => {
this.setProperties({ ip_address: "", formSubmitted: false }); this.setProperties({ ip_address: "", formSubmitted: false });
this.action(ScreenedIpAddress.create(result.screened_ip_address)); this.action(ScreenedIpAddress.create(result.screened_ip_address));
schedule("afterRender", () => this.focusInput();
this.element.querySelector("input").focus()
);
}) })
.catch((e) => { .catch((e) => {
this.set("formSubmitted", false); this.set("formSubmitted", false);
const msg = e.jqXHR.responseJSON?.errors const message = e.jqXHR.responseJSON?.errors
? I18n.t("generic_error_with_reason", { ? I18n.t("generic_error_with_reason", {
error: e.jqXHR.responseJSON.errors.join(". "), error: e.jqXHR.responseJSON.errors.join(". "),
}) })
: I18n.t("generic_error"); : I18n.t("generic_error");
bootbox.alert(msg, () => this.dialog.alert({
schedule("afterRender", () => message,
this.element.querySelector("input").focus() didConfirm: () => this.focusInput(),
) didCancel: () => this.focusInput(),
); });
}); });
} }
}, },

View File

@ -2,10 +2,11 @@ import Component from "@ember/component";
import I18n from "I18n"; import I18n from "I18n";
import UppyUploadMixin from "discourse/mixins/uppy-upload"; import UppyUploadMixin from "discourse/mixins/uppy-upload";
import { alias } from "@ember/object/computed"; import { alias } from "@ember/object/computed";
import bootbox from "bootbox"; import { inject as service } from "@ember/service";
export default Component.extend(UppyUploadMixin, { export default Component.extend(UppyUploadMixin, {
type: "csv", type: "csv",
dialog: service(),
uploadUrl: "/tags/upload", uploadUrl: "/tags/upload",
addDisabled: alias("uploading"), addDisabled: alias("uploading"),
elementId: "tag-uploader", elementId: "tag-uploader",
@ -16,9 +17,8 @@ export default Component.extend(UppyUploadMixin, {
}, },
uploadDone() { uploadDone() {
bootbox.alert(I18n.t("tagging.upload_successful"), () => {
this.refresh();
this.closeModal(); 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 Component from "@ember/component";
import I18n from "I18n"; import I18n from "I18n";
import WatchedWord from "admin/models/watched-word"; import WatchedWord from "admin/models/watched-word";
import bootbox from "bootbox";
import { equal } from "@ember/object/computed"; import { equal } from "@ember/object/computed";
import { isEmpty } from "@ember/utils"; import { isEmpty } from "@ember/utils";
import { schedule } from "@ember/runloop"; import { schedule } from "@ember/runloop";
import { inject as service } from "@ember/service";
export default Component.extend({ export default Component.extend({
tagName: "form", tagName: "form",
dialog: service(),
classNames: ["watched-word-form"], classNames: ["watched-word-form"],
formSubmitted: false, formSubmitted: false,
actionKey: null, actionKey: null,
@ -55,6 +56,10 @@ export default Component.extend({
}); });
}, },
focusInput() {
schedule("afterRender", () => this.element.querySelector("input").focus());
},
actions: { actions: {
changeSelectedTags(tags) { changeSelectedTags(tags) {
this.setProperties({ this.setProperties({
@ -98,22 +103,20 @@ export default Component.extend({
isCaseSensitive: false, isCaseSensitive: false,
}); });
this.action(WatchedWord.create(result)); this.action(WatchedWord.create(result));
schedule("afterRender", () => this.focusInput();
this.element.querySelector("input").focus()
);
}) })
.catch((e) => { .catch((e) => {
this.set("formSubmitted", false); this.set("formSubmitted", false);
const msg = e.jqXHR.responseJSON?.errors const message = e.jqXHR.responseJSON?.errors
? I18n.t("generic_error_with_reason", { ? I18n.t("generic_error_with_reason", {
error: e.jqXHR.responseJSON.errors.join(". "), error: e.jqXHR.responseJSON.errors.join(". "),
}) })
: I18n.t("generic_error"); : I18n.t("generic_error");
bootbox.alert(msg, () => this.dialog.alert({
schedule("afterRender", () => message,
this.element.querySelector("input").focus() didConfirm: () => this.focusInput(),
) didCancel: () => this.focusInput(),
); });
}); });
} }
}, },

View File

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

View File

@ -1,12 +1,13 @@
import Controller from "@ember/controller"; import Controller from "@ember/controller";
import I18n from "I18n"; import I18n from "I18n";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import bootbox from "bootbox";
import { extractError } from "discourse/lib/ajax-error"; import { extractError } from "discourse/lib/ajax-error";
import { action } from "@ember/object"; import { action } from "@ember/object";
import { tracked } from "@glimmer/tracking"; import { tracked } from "@glimmer/tracking";
import { inject as service } from "@ember/service";
export default class AdminBadgesAwardController extends Controller { export default class AdminBadgesAwardController extends Controller {
@service dialog;
@tracked saving = false; @tracked saving = false;
@tracked replaceBadgeOwners = false; @tracked replaceBadgeOwners = false;
@tracked grantExistingHolders = false; @tracked grantExistingHolders = false;
@ -84,7 +85,7 @@ export default class AdminBadgesAwardController extends Controller {
}) })
.finally(() => (this.saving = false)); .finally(() => (this.saving = false));
} else { } 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 Controller from "@ember/controller";
import I18n from "I18n"; import I18n from "I18n";
import bootbox from "bootbox";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
import { inject as service } from "@ember/service";
export default Controller.extend({ export default Controller.extend({
dialog: service(),
@discourseComputed("model.isSaving") @discourseComputed("model.isSaving")
saveButtonText(isSaving) { saveButtonText(isSaving) {
return isSaving ? I18n.t("saving") : I18n.t("admin.customize.save"); return isSaving ? I18n.t("saving") : I18n.t("admin.customize.save");
@ -27,7 +29,7 @@ export default Controller.extend({
error: e.jqXHR.responseJSON.errors.join(". "), error: e.jqXHR.responseJSON.errors.join(". "),
}) })
: I18n.t("generic_error"); : I18n.t("generic_error");
bootbox.alert(msg); this.dialog.alert(msg);
}) })
.finally(() => this.set("model.changed", false)); .finally(() => this.set("model.changed", false));
} }

View File

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

View File

@ -3,10 +3,12 @@ import Controller from "@ember/controller";
import I18n from "I18n"; import I18n from "I18n";
import ModalFunctionality from "discourse/mixins/modal-functionality"; import ModalFunctionality from "discourse/mixins/modal-functionality";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import bootbox from "bootbox";
import { observes } from "discourse-common/utils/decorators"; import { observes } from "discourse-common/utils/decorators";
import { inject as service } from "@ember/service";
export default Controller.extend(ModalFunctionality, { export default Controller.extend(ModalFunctionality, {
dialog: service(),
@observes("model") @observes("model")
modelChanged() { modelChanged() {
const model = this.model; const model = this.model;
@ -78,7 +80,7 @@ export default Controller.extend(ModalFunctionality, {
this.setProperties({ model: null, workingCopy: null }); this.setProperties({ model: null, workingCopy: null });
this.send("closeModal"); 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 I18n from "I18n";
import ModalFunctionality from "discourse/mixins/modal-functionality"; import ModalFunctionality from "discourse/mixins/modal-functionality";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import bootbox from "bootbox"; import { inject as service } from "@ember/service";
export default Controller.extend(ModalFunctionality, { export default Controller.extend(ModalFunctionality, {
dialog: service(),
loading: true, loading: true,
reseeding: false, reseeding: false,
categories: null, categories: null,
@ -35,11 +36,11 @@ export default Controller.extend(ModalFunctionality, {
}, },
type: "POST", type: "POST",
}) })
.then( .catch(() => this.dialog.alert(I18n.t("generic_error")))
() => this.send("closeModal"), .finally(() => {
() => bootbox.alert(I18n.t("generic_error")) this.set("reseeding", false);
) this.send("closeModal");
.finally(() => this.set("reseeding", false)); });
}, },
}, },
}); });

View File

@ -2,11 +2,13 @@ import Badge from "discourse/models/badge";
import I18n from "I18n"; import I18n from "I18n";
import Route from "@ember/routing/route"; import Route from "@ember/routing/route";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import bootbox from "bootbox";
import { action, get } from "@ember/object"; import { action, get } from "@ember/object";
import showModal from "discourse/lib/show-modal"; import showModal from "discourse/lib/show-modal";
import { inject as service } from "@ember/service";
export default class AdminBadgesShowRoute extends Route { export default class AdminBadgesShowRoute extends Route {
@service dialog;
serialize(m) { serialize(m) {
return { badge_id: get(m, "id") || "new" }; return { badge_id: get(m, "id") || "new" };
} }
@ -58,7 +60,7 @@ export default class AdminBadgesShowRoute extends Route {
badge.set("preview_loading", false); badge.set("preview_loading", false);
// eslint-disable-next-line no-console // eslint-disable-next-line no-console
console.error(error); 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 AdminUser from "admin/models/admin-user";
import I18n from "I18n"; import I18n from "I18n";
import { Promise } from "rsvp"; import { Promise } from "rsvp";
import Service from "@ember/service"; import Service, { inject as service } from "@ember/service";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import bootbox from "bootbox"; import bootbox from "bootbox";
import { getOwner } from "discourse-common/lib/get-owner"; 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 // 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! // modules. Inject it optionally, and if it exists go to town!
export default Service.extend({ export default Service.extend({
dialog: service(),
showActionLogs(target, filters) { showActionLogs(target, filters) {
const controller = getOwner(target).lookup( const controller = getOwner(target).lookup(
"controller:adminLogs.staffActionLogs" "controller:adminLogs.staffActionLogs"
@ -120,7 +122,7 @@ export default Service.extend({
} }
}) })
.catch(() => { .catch(() => {
bootbox.alert(I18n.t("admin.user.delete_failed")); this.dialog.alert(I18n.t("admin.user.delete_failed"));
reject(); reject();
}); });
}, },

View File

@ -2,13 +2,12 @@ import Component from "@ember/component";
import { action } from "@ember/object"; import { action } from "@ember/object";
import I18n from "I18n"; import I18n from "I18n";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import bootbox from "bootbox"; import { inject as service } from "@ember/service";
export default Component.extend({ export default Component.extend({
dialog: service(),
tagName: "", tagName: "",
selectableUserBadges: null, selectableUserBadges: null,
_selectedUserBadgeId: null, _selectedUserBadgeId: null,
_isSaved: false, _isSaved: false,
_isSaving: false, _isSaving: false,
@ -42,7 +41,7 @@ export default Component.extend({
this.currentUser.set("title", selectedUserBadge?.badge?.name || ""); 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)); .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 { popupAjaxError } from "discourse/lib/ajax-error";
import discourseLater from "discourse-common/lib/later"; import discourseLater from "discourse-common/lib/later";
import { inject as service } from "@ember/service";
const BOOKMARK_BINDINGS = { const BOOKMARK_BINDINGS = {
enter: { handler: "saveAndClose" }, enter: { handler: "saveAndClose" },
"d d": { handler: "delete" }, "d d": { handler: "delete" },
}; };
export default Component.extend({ export default Component.extend({
dialog: service(),
tagName: "", tagName: "",
errorMessage: null, errorMessage: null,
selectedReminderType: null, selectedReminderType: null,
_closeWithoutSaving: null, _closeWithoutSaving: null,
@ -227,7 +229,7 @@ export default Component.extend({
_handleSaveError(e) { _handleSaveError(e) {
this._savingBookmarkManually = false; this._savingBookmarkManually = false;
if (typeof e === "string") { if (typeof e === "string") {
bootbox.alert(e); this.dialog.alert(e);
} else { } else {
popupAjaxError(e); popupAjaxError(e);
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -9,10 +9,10 @@ import Controller from "@ember/controller";
import I18n from "I18n"; import I18n from "I18n";
import ModalFunctionality from "discourse/mixins/modal-functionality"; import ModalFunctionality from "discourse/mixins/modal-functionality";
import Post from "discourse/models/post"; import Post from "discourse/models/post";
import bootbox from "bootbox";
import { categoryBadgeHTML } from "discourse/helpers/category-link"; import { categoryBadgeHTML } from "discourse/helpers/category-link";
import { iconHTML } from "discourse-common/lib/icon-library"; import { iconHTML } from "discourse-common/lib/icon-library";
import { sanitizeAsync } from "discourse/lib/text"; import { sanitizeAsync } from "discourse/lib/text";
import { inject as service } from "@ember/service";
function customTagArray(val) { function customTagArray(val) {
if (!val) { if (!val) {
@ -26,6 +26,7 @@ function customTagArray(val) {
// This controller handles displaying of history // This controller handles displaying of history
export default Controller.extend(ModalFunctionality, { export default Controller.extend(ModalFunctionality, {
dialog: service(),
loading: true, loading: true,
viewMode: "side_by_side", viewMode: "side_by_side",
@ -139,7 +140,7 @@ export default Controller.extend(ModalFunctionality, {
e.jqXHR.responseJSON.errors && e.jqXHR.responseJSON.errors &&
e.jqXHR.responseJSON.errors[0] 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 ModalFunctionality from "discourse/mixins/modal-functionality";
import { SECOND_FACTOR_METHODS } from "discourse/models/user"; import { SECOND_FACTOR_METHODS } from "discourse/models/user";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import bootbox from "bootbox";
import discourseComputed from "discourse-common/utils/decorators"; import discourseComputed from "discourse-common/utils/decorators";
import { escape } from "pretty-text/sanitizer"; import { escape } from "pretty-text/sanitizer";
import { extractError } from "discourse/lib/ajax-error"; import { extractError } from "discourse/lib/ajax-error";
@ -19,6 +18,7 @@ import { isEmpty } from "@ember/utils";
import { setting } from "discourse/lib/computed"; import { setting } from "discourse/lib/computed";
import showModal from "discourse/lib/show-modal"; import showModal from "discourse/lib/show-modal";
import { wavingHandURL } from "discourse/lib/waving-hand-url"; import { wavingHandURL } from "discourse/lib/waving-hand-url";
import { inject as service } from "@ember/service";
// This is happening outside of the app via popup // This is happening outside of the app via popup
const AuthErrors = [ const AuthErrors = [
@ -33,6 +33,7 @@ export default Controller.extend(ModalFunctionality, {
createAccount: controller(), createAccount: controller(),
forgotPassword: controller(), forgotPassword: controller(),
application: controller(), application: controller(),
dialog: service(),
loggingIn: false, loggingIn: false,
loggedIn: false, loggedIn: false,
@ -199,7 +200,7 @@ export default Controller.extend(ModalFunctionality, {
}); });
} else if (result.reason === "suspended") { } else if (result.reason === "suspended") {
this.send("closeModal"); this.send("closeModal");
bootbox.alert(result.error); this.dialog.alert(result.error);
} else { } else {
this.flash(result.error, "error"); this.flash(result.error, "error");
} }

View File

@ -10,12 +10,14 @@ import { readOnly } from "@ember/object/computed";
import bootbox from "bootbox"; import bootbox from "bootbox";
import { endWith } from "discourse/lib/computed"; import { endWith } from "discourse/lib/computed";
import { action } from "@ember/object"; import { action } from "@ember/object";
import { inject as service } from "@ember/service";
export default DiscoverySortableController.extend( export default DiscoverySortableController.extend(
BulkTopicSelection, BulkTopicSelection,
FilterModeMixin, FilterModeMixin,
{ {
application: controller(), application: controller(),
dialog: service(),
tag: null, tag: null,
additionalTags: null, additionalTags: null,
@ -172,7 +174,7 @@ export default DiscoverySortableController.extend(
this.tag this.tag
.destroyRecord() .destroyRecord()
.then(() => this.transitionToRoute("tags.index")) .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 { popupAjaxError } from "discourse/lib/ajax-error";
import showModal from "discourse/lib/show-modal"; import showModal from "discourse/lib/show-modal";
import { inject as service } from "@ember/service";
export default Controller.extend({ export default Controller.extend({
dialog: service(),
sortedByCount: true, sortedByCount: true,
sortedByName: false, sortedByName: false,
canAdminTags: alias("currentUser.staff"), canAdminTags: alias("currentUser.staff"),
groupedByCategory: notEmpty("model.extras.categories"), groupedByCategory: notEmpty("model.extras.categories"),
groupedByTagGroup: notEmpty("model.extras.tag_groups"), groupedByTagGroup: notEmpty("model.extras.tag_groups"),
@ -67,7 +69,7 @@ export default Controller.extend({
const tags = result["tags"]; const tags = result["tags"];
if (tags.length === 0) { if (tags.length === 0) {
bootbox.alert(I18n.t("tagging.delete_no_unused_tags")); this.dialog.alert(I18n.t("tagging.delete_no_unused_tags"));
return; return;
} }

View File

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

View File

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

View File

@ -1,5 +1,5 @@
import I18n from "I18n"; import I18n from "I18n";
import bootbox from "bootbox"; import { getOwner } from "discourse-common/lib/get-owner";
export function extractError(error, defaultMessage) { export function extractError(error, defaultMessage) {
if (error instanceof Error) { if (error instanceof Error) {
@ -64,5 +64,6 @@ export function throwAjaxError(undoCallback) {
} }
export function popupAjaxError(error) { 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 { Promise } from "rsvp";
import User from "discourse/models/user"; import User from "discourse/models/user";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import bootbox from "bootbox";
import getURL, { samePrefix } from "discourse-common/lib/get-url"; import getURL, { samePrefix } from "discourse-common/lib/get-url";
import { isTesting } from "discourse-common/config/environment"; import { isTesting } from "discourse-common/config/environment";
import discourseLater from "discourse-common/lib/later"; import discourseLater from "discourse-common/lib/later";
import { selectedText } from "discourse/lib/utilities"; import { selectedText } from "discourse/lib/utilities";
import { wantsNewWindow } from "discourse/lib/intercept-click"; import { wantsNewWindow } from "discourse/lib/intercept-click";
import deprecated from "discourse-common/lib/deprecated"; import deprecated from "discourse-common/lib/deprecated";
import { getOwner } from "discourse-common/lib/get-owner";
export function isValidLink(link) { export function isValidLink(link) {
// eslint-disable-next-line no-undef // eslint-disable-next-line no-undef
@ -121,7 +121,8 @@ export default {
siteSettings?.prevent_anons_from_downloading_files && siteSettings?.prevent_anons_from_downloading_files &&
!User.current() !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)) { } else if (wantsNewWindow(e)) {
const newWindow = window.open(href, "_blank"); const newWindow = window.open(href, "_blank");
newWindow.opener = null; newWindow.opener = null;

View File

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

View File

@ -19,7 +19,7 @@ import {
validateUploadedFile, validateUploadedFile,
} from "discourse/lib/uploads"; } from "discourse/lib/uploads";
import { cacheShortUploadUrl } from "pretty-text/upload-short-url"; 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 { run } from "@ember/runloop";
import escapeRegExp from "discourse-common/utils/escape-regexp"; import escapeRegExp from "discourse-common/utils/escape-regexp";
@ -36,6 +36,7 @@ import escapeRegExp from "discourse-common/utils/escape-regexp";
// functionality and event binding. // functionality and event binding.
// //
export default Mixin.create(ExtendableUploader, UppyS3Multipart, { export default Mixin.create(ExtendableUploader, UppyS3Multipart, {
dialog: service(),
uploadRootPath: "/uploads", uploadRootPath: "/uploads",
uploadTargetBound: false, uploadTargetBound: false,
useUploadPlaceholders: true, useUploadPlaceholders: true,
@ -186,7 +187,7 @@ export default Mixin.create(ExtendableUploader, UppyS3Multipart, {
// _not_ been handled by an upload handler. // _not_ been handled by an upload handler.
const fileCount = Object.keys(unhandledFiles).length; const fileCount = Object.keys(unhandledFiles).length;
if (maxFiles > 0 && fileCount > maxFiles) { if (maxFiles > 0 && fileCount > maxFiles) {
bootbox.alert( this.dialog.alert(
I18n.t("post.errors.too_many_dragged_and_dropped_files", { I18n.t("post.errors.too_many_dragged_and_dropped_files", {
count: maxFiles, 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 UppyChunkedUploader from "discourse/lib/uppy-chunked-uploader-plugin";
import { bind, on } from "discourse-common/utils/decorators"; import { bind, on } from "discourse-common/utils/decorators";
import { warn } from "@ember/debug"; 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 const HUGE_FILE_THRESHOLD_BYTES = 104_857_600; // 100MB
export default Mixin.create(UppyS3Multipart, ExtendableUploader, { export default Mixin.create(UppyS3Multipart, ExtendableUploader, {
dialog: service(),
uploading: false, uploading: false,
uploadProgress: 0, uploadProgress: 0,
_uppyInstance: null, _uppyInstance: null,
@ -130,7 +131,7 @@ export default Mixin.create(UppyS3Multipart, ExtendableUploader, {
} }
if (tooMany) { if (tooMany) {
bootbox.alert( this.dialog.alert(
I18n.t("post.errors.too_many_dragged_and_dropped_files", { I18n.t("post.errors.too_many_dragged_and_dropped_files", {
count: this.allowMultipleFiles ? maxFiles : 1, count: this.allowMultipleFiles ? maxFiles : 1,
}) })

View File

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

View File

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

View File

@ -11,7 +11,6 @@ import I18n from "I18n";
import PostCooked from "discourse/widgets/post-cooked"; import PostCooked from "discourse/widgets/post-cooked";
import { Promise } from "rsvp"; import { Promise } from "rsvp";
import RawHtml from "discourse/widgets/raw-html"; import RawHtml from "discourse/widgets/raw-html";
import bootbox from "bootbox";
import { dateNode } from "discourse/helpers/node"; import { dateNode } from "discourse/helpers/node";
import { h } from "virtual-dom"; import { h } from "virtual-dom";
import hbs from "discourse/widgets/hbs-compiler"; import hbs from "discourse/widgets/hbs-compiler";
@ -814,6 +813,7 @@ export function addPostClassesCallback(callback) {
export default createWidget("post", { export default createWidget("post", {
buildKey: (attrs) => `post-${attrs.id}`, buildKey: (attrs) => `post-${attrs.id}`,
services: ["dialog"],
shadowTree: true, shadowTree: true,
buildAttributes(attrs) { buildAttributes(attrs) {
@ -918,7 +918,7 @@ export default createWidget("post", {
const { remaining, max } = result; const { remaining, max } = result;
const threshold = Math.ceil(max * 0.1); const threshold = Math.ceil(max * 0.1);
if (remaining === threshold) { 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() }); 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 visit("/c/test-read-only-without-banner");
await click("#create-topic"); 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( assert.ok(
!visible(".category-read-only-banner"), !visible(".category-read-only-banner"),
"it does not show a 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 visit("/c/test-read-only-with-banner");
await click("#create-topic"); 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"); await click(".dialog-footer .btn-primary");
assert.ok(!visible(".bootbox.modal"), "it closes the modal"); assert.ok(!visible(".dialog-body"), "it closes the modal");
assert.ok(visible(".category-read-only-banner"), "it shows a banner"); assert.ok(visible(".category-read-only-banner"), "it shows a banner");
assert.strictEqual( assert.strictEqual(
count(".category-read-only-banner .inner"), count(".category-read-only-banner .inner"),

View File

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

View File

@ -126,12 +126,12 @@ acceptance(
await click("#enable_smtp"); await click("#enable_smtp");
assert.strictEqual( assert.strictEqual(
query(".modal-body").innerText, query(".dialog-body").innerText.trim(),
I18n.t("groups.manage.email.smtp_disable_confirm"), I18n.t("groups.manage.email.smtp_disable_confirm"),
"shows a confirm dialogue warning SMTP settings will be wiped" "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) { test("enabling IMAP, testing, and saving", async function (assert) {
@ -202,11 +202,11 @@ acceptance(
await click("#enable_imap"); await click("#enable_imap");
assert.strictEqual( assert.strictEqual(
query(".modal-body").innerText, query(".dialog-body").innerText.trim(),
I18n.t("groups.manage.email.imap_disable_confirm"), I18n.t("groups.manage.email.imap_disable_confirm"),
"shows a confirm dialogue warning IMAP settings will be wiped" "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"); await click(".test-smtp-settings");
assert.strictEqual( 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.", "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" "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" "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( assert.ok(
!exists(".sidebar-section-categories .sidebar-section-link-howto"), !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" "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( assert.ok(
!exists(".sidebar-section-tags .sidebar-section-link-gazelle"), !exists(".sidebar-section-tags .sidebar-section-link-gazelle"),

View File

@ -1,9 +1,12 @@
import { module, test } from "qunit"; import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test"; 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 { createFile } from "discourse/tests/helpers/qunit-helpers";
import { hbs } from "ember-cli-htmlbars"; import { hbs } from "ember-cli-htmlbars";
import pretender, { response } from "discourse/tests/helpers/create-pretender"; 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) { module("Integration | Component | watched-word-uploader", function (hooks) {
setupRenderingTest(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) { test("sets the proper action key on uploads", async function (assert) {
sinon.stub(dialog, "alert");
const done = assert.async(); const done = assert.async();
this.set("actionNameKey", "flag"); this.set("actionNameKey", "flag");
this.set("doneUpload", function () { this.set("doneUpload", function () {
@ -23,6 +28,12 @@ module("Integration | Component | watched-word-uploader", function (hooks) {
.action_key, .action_key,
"flag" "flag"
); );
assert.ok(
dialog.alert.calledWith(
I18n.t("admin.watched_words.form.upload_successful")
),
"alert shown"
);
done(); done();
}); });
@ -38,8 +49,5 @@ module("Integration | Component | watched-word-uploader", function (hooks) {
await this.container await this.container
.lookup("service:app-events") .lookup("service:app-events")
.trigger("upload-mixin:watched-word-uploader:add-files", words); .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, allowsAttachments,
allowsImages, allowsImages,
authorizedExtensions, authorizedExtensions,
dialog,
displayErrorForUpload, displayErrorForUpload,
getUploadMarkdown, getUploadMarkdown,
isImage, isImage,
@ -10,7 +11,6 @@ import {
} from "discourse/lib/uploads"; } from "discourse/lib/uploads";
import I18n from "I18n"; import I18n from "I18n";
import User from "discourse/models/user"; import User from "discourse/models/user";
import bootbox from "bootbox";
import { discourseModule } from "discourse/tests/helpers/qunit-helpers"; import { discourseModule } from "discourse/tests/helpers/qunit-helpers";
import sinon from "sinon"; import sinon from "sinon";
import { test } from "qunit"; import { test } from "qunit";
@ -32,17 +32,17 @@ discourseModule("Unit | Utility | uploads", function () {
}); });
test("uploading one file", function (assert) { test("uploading one file", function (assert) {
sinon.stub(bootbox, "alert"); sinon.stub(dialog, "alert");
assert.notOk( assert.notOk(
validateUploadedFiles([1, 2], { siteSettings: this.siteSettings }) 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) { test("new user cannot upload images", function (assert) {
this.siteSettings.newuser_max_embedded_media = 0; this.siteSettings.newuser_max_embedded_media = 0;
sinon.stub(bootbox, "alert"); sinon.stub(dialog, "alert");
assert.notOk( assert.notOk(
validateUploadedFiles([{ name: "image.png" }], { validateUploadedFiles([{ name: "image.png" }], {
@ -52,7 +52,7 @@ discourseModule("Unit | Utility | uploads", function () {
"the upload is not valid" "the upload is not valid"
); );
assert.ok( assert.ok(
bootbox.alert.calledWith( dialog.alert.calledWith(
I18n.t("post.errors.image_upload_not_allowed_for_new_user") I18n.t("post.errors.image_upload_not_allowed_for_new_user")
), ),
"the alert is called" "the alert is called"
@ -62,7 +62,7 @@ discourseModule("Unit | Utility | uploads", function () {
test("new user can upload images if allowed", function (assert) { test("new user can upload images if allowed", function (assert) {
this.siteSettings.newuser_max_embedded_media = 1; this.siteSettings.newuser_max_embedded_media = 1;
this.siteSettings.default_trust_level = 0; this.siteSettings.default_trust_level = 0;
sinon.stub(bootbox, "alert"); sinon.stub(dialog, "alert");
assert.ok( assert.ok(
validateUploadedFiles([{ name: "image.png" }], { validateUploadedFiles([{ name: "image.png" }], {
@ -74,7 +74,7 @@ discourseModule("Unit | Utility | uploads", function () {
test("TL1 can upload images", function (assert) { test("TL1 can upload images", function (assert) {
this.siteSettings.newuser_max_embedded_media = 0; this.siteSettings.newuser_max_embedded_media = 0;
sinon.stub(bootbox, "alert"); sinon.stub(dialog, "alert");
assert.ok( assert.ok(
validateUploadedFiles([{ name: "image.png" }], { validateUploadedFiles([{ name: "image.png" }], {
@ -86,7 +86,7 @@ discourseModule("Unit | Utility | uploads", function () {
test("new user cannot upload attachments", function (assert) { test("new user cannot upload attachments", function (assert) {
this.siteSettings.newuser_max_attachments = 0; this.siteSettings.newuser_max_attachments = 0;
sinon.stub(bootbox, "alert"); sinon.stub(dialog, "alert");
assert.notOk( assert.notOk(
validateUploadedFiles([{ name: "roman.txt" }], { validateUploadedFiles([{ name: "roman.txt" }], {
@ -95,21 +95,21 @@ discourseModule("Unit | Utility | uploads", function () {
}) })
); );
assert.ok( assert.ok(
bootbox.alert.calledWith( dialog.alert.calledWith(
I18n.t("post.errors.attachment_upload_not_allowed_for_new_user") I18n.t("post.errors.attachment_upload_not_allowed_for_new_user")
) )
); );
}); });
test("ensures an authorized upload", function (assert) { test("ensures an authorized upload", function (assert) {
sinon.stub(bootbox, "alert"); sinon.stub(dialog, "alert");
assert.notOk( assert.notOk(
validateUploadedFiles([{ name: "unauthorized.html" }], { validateUploadedFiles([{ name: "unauthorized.html" }], {
siteSettings: this.siteSettings, siteSettings: this.siteSettings,
}) })
); );
assert.ok( assert.ok(
bootbox.alert.calledWith( dialog.alert.calledWith(
I18n.t("post.errors.upload_not_authorized", { I18n.t("post.errors.upload_not_authorized", {
authorized_extensions: authorizedExtensions( authorized_extensions: authorizedExtensions(
false, false,
@ -122,7 +122,7 @@ discourseModule("Unit | Utility | uploads", function () {
test("skipping validation works", function (assert) { test("skipping validation works", function (assert) {
const files = [{ name: "backup.tar.gz" }]; const files = [{ name: "backup.tar.gz" }];
sinon.stub(bootbox, "alert"); sinon.stub(dialog, "alert");
assert.notOk( assert.notOk(
validateUploadedFiles(files, { validateUploadedFiles(files, {
@ -141,7 +141,7 @@ discourseModule("Unit | Utility | uploads", function () {
test("staff can upload anything in PM", function (assert) { test("staff can upload anything in PM", function (assert) {
const files = [{ name: "some.docx" }]; const files = [{ name: "some.docx" }];
this.siteSettings.authorized_extensions = "jpeg"; this.siteSettings.authorized_extensions = "jpeg";
sinon.stub(bootbox, "alert"); sinon.stub(dialog, "alert");
let user = User.create({ moderator: true }); let user = User.create({ moderator: true });
assert.notOk( assert.notOk(
@ -175,7 +175,7 @@ discourseModule("Unit | Utility | uploads", function () {
}; };
test("allows valid uploads to go through", function (assert) { test("allows valid uploads to go through", function (assert) {
sinon.stub(bootbox, "alert"); sinon.stub(dialog, "alert");
let user = User.create({ trust_level: 1 }); 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) { test("isImage", function (assert) {
@ -315,7 +315,7 @@ discourseModule("Unit | Utility | uploads", function () {
}); });
test("displayErrorForUpload - jquery file upload - jqXHR present", function (assert) { test("displayErrorForUpload - jquery file upload - jqXHR present", function (assert) {
sinon.stub(bootbox, "alert"); sinon.stub(dialog, "alert");
displayErrorForUpload( displayErrorForUpload(
{ {
jqXHR: { status: 422, responseJSON: { message: "upload failed" } }, 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 }, { max_attachment_size_kb: 1024, max_image_size_kb: 1024 },
"test.png" "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) { test("displayErrorForUpload - jquery file upload - jqXHR missing, errors present", function (assert) {
sinon.stub(bootbox, "alert"); sinon.stub(dialog, "alert");
displayErrorForUpload( displayErrorForUpload(
{ {
errors: ["upload failed"], errors: ["upload failed"],
@ -335,11 +335,11 @@ discourseModule("Unit | Utility | uploads", function () {
{ max_attachment_size_kb: 1024, max_image_size_kb: 1024 }, { max_attachment_size_kb: 1024, max_image_size_kb: 1024 },
"test.png" "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) { test("displayErrorForUpload - jquery file upload - no errors", function (assert) {
sinon.stub(bootbox, "alert"); sinon.stub(dialog, "alert");
displayErrorForUpload( displayErrorForUpload(
{}, {},
{ {
@ -349,13 +349,13 @@ discourseModule("Unit | Utility | uploads", function () {
"test.png" "test.png"
); );
assert.ok( assert.ok(
bootbox.alert.calledWith(I18n.t("post.errors.upload")), dialog.alert.calledWith(I18n.t("post.errors.upload")),
"the alert is called" "the alert is called"
); );
}); });
test("displayErrorForUpload - uppy - with response status and body", function (assert) { test("displayErrorForUpload - uppy - with response status and body", function (assert) {
sinon.stub(bootbox, "alert"); sinon.stub(dialog, "alert");
displayErrorForUpload( displayErrorForUpload(
{ {
status: 422, status: 422,
@ -364,6 +364,6 @@ discourseModule("Unit | Utility | uploads", function () {
"test.png", "test.png",
{ max_attachment_size_kb: 1024, max_image_size_kb: 1024 } { 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 Uppy from "@uppy/core";
import DropTarget from "@uppy/drop-target"; import DropTarget from "@uppy/drop-target";
import XHRUpload from "@uppy/xhr-upload"; import XHRUpload from "@uppy/xhr-upload";
import { inject as service } from "@ember/service";
export default Component.extend({ export default Component.extend({
classNames: ["wizard-container__image-upload"], classNames: ["wizard-container__image-upload"],
dialog: service(),
uploading: false, uploading: false,
@discourseComputed("field.id") @discourseComputed("field.id")
@ -57,7 +59,7 @@ export default Component.extend({
message = response.body.errors.join("\n"); message = response.body.errors.join("\n");
} }
window.bootbox.alert(message); this.dialog.alert(message);
this.set("uploading", false); this.set("uploading", false);
}); });

View File

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

View File

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

View File

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