FIX: Broken error reporting in modals (and other places) (#23680)

1. actually call `popupAjaxError`, thanks :P
2. don't close a modal on error
3. use `extractError()` instead of manually joining error messages
4. …or passing just the error object to `this.flash`
This commit is contained in:
Jarek Radosz
2023-09-27 17:11:44 +02:00
committed by GitHub
parent 1ad60b791c
commit 6adc67a7a8
11 changed files with 70 additions and 58 deletions

View File

@ -163,8 +163,8 @@ export default class InstallTheme extends Component {
await theme.save({ name: this.name, component: this.component }); await theme.save({ name: this.name, component: this.component });
this.args.model.addTheme(theme); this.args.model.addTheme(theme);
this.args.closeModal(); this.args.closeModal();
} catch { } catch (e) {
popupAjaxError; popupAjaxError(e);
} finally { } finally {
this.loading = false; this.loading = false;
} }

View File

@ -44,12 +44,13 @@ export default class Reseed extends Component {
}, },
type: "POST", type: "POST",
}); });
this.flash = null;
this.args.closeModal();
} catch { } catch {
this.flash = I18n.t("generic_error"); this.flash = I18n.t("generic_error");
} finally { } finally {
this.reseeding = false; this.reseeding = false;
this.flash = null;
this.args.closeModal();
} }
} }
} }

View File

@ -4,6 +4,7 @@ import { tracked } from "@glimmer/tracking";
import I18n from "I18n"; import I18n from "I18n";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import { isEmpty } from "@ember/utils"; import { isEmpty } from "@ember/utils";
import { extractError } from "discourse/lib/ajax-error";
const THEME_FIELD_VARIABLE_TYPE_IDS = [2, 3, 4]; const THEME_FIELD_VARIABLE_TYPE_IDS = [2, 3, 4];
const SCSS_VARIABLE_NAMES = [ const SCSS_VARIABLE_NAMES = [
@ -108,7 +109,7 @@ export default class ThemeUploadAdd extends Component {
this.args.model.addUpload(upload); this.args.model.addUpload(upload);
this.args.closeModal(); this.args.closeModal();
} catch (e) { } catch (e) {
this.flash = e.jqXHR.responseJSON.errors.join(". "); this.flash = extractError(e);
} }
} }
} }

View File

@ -4,6 +4,7 @@ import { inject as service } from "@ember/service";
import { tracked } from "@glimmer/tracking"; import { tracked } from "@glimmer/tracking";
import { changeEmail } from "discourse/lib/user-activation"; import { changeEmail } from "discourse/lib/user-activation";
import ActivationResent from "./activation-resent"; import ActivationResent from "./activation-resent";
import { extractError } from "discourse/lib/ajax-error";
export default class ActivationEdit extends Component { export default class ActivationEdit extends Component {
@service login; @service login;
@ -17,18 +18,20 @@ export default class ActivationEdit extends Component {
} }
@action @action
changeEmail() { async changeEmail() {
changeEmail({ try {
username: this.login?.loginName, await changeEmail({
password: this.login?.loginPassword, username: this.login?.loginName,
email: this.args.model.newEmail, password: this.login?.loginPassword,
}) email: this.args.model.newEmail,
.then(() => { });
this.modal.show(ActivationResent, {
model: { currentEmail: this.args.model.newEmail }, this.modal.show(ActivationResent, {
}); model: { currentEmail: this.args.model.newEmail },
}) });
.catch((e) => (this.flash = e)); } catch (e) {
this.flash = extractError(e);
}
} }
@action @action

View File

@ -2,6 +2,7 @@ import Component from "@glimmer/component";
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"; import { inject as service } from "@ember/service";
import { extractError } from "discourse/lib/ajax-error";
export default class DoNotDisturb extends Component { export default class DoNotDisturb extends Component {
@service currentUser; @service currentUser;
@ -15,7 +16,7 @@ export default class DoNotDisturb extends Component {
await this.currentUser.enterDoNotDisturbFor(duration); await this.currentUser.enterDoNotDisturbFor(duration);
this.args.closeModal(); this.args.closeModal();
} catch (e) { } catch (e) {
this.flash = e; this.flash = extractError(e);
} }
} }

View File

@ -6,6 +6,7 @@ import I18n from "I18n";
import { timeShortcuts } from "discourse/lib/time-shortcut"; import { timeShortcuts } from "discourse/lib/time-shortcut";
import Topic from "discourse/models/topic"; import Topic from "discourse/models/topic";
import { inject as service } from "@ember/service"; import { inject as service } from "@ember/service";
import { extractError } from "discourse/lib/ajax-error";
const SLOW_MODE_OPTIONS = [ const SLOW_MODE_OPTIONS = [
{ {
@ -154,7 +155,7 @@ export default class EditSlowMode extends Component {
this.args.model.topic.set("slow_mode_seconds", 0); this.args.model.topic.set("slow_mode_seconds", 0);
this.args.closeModal(); this.args.closeModal();
} catch (e) { } catch (e) {
this.flash = e; this.flash = extractError(e);
} finally { } finally {
this.saveDisabled = false; this.saveDisabled = false;
} }

View File

@ -27,8 +27,8 @@ export default class EditUserDirectoryColumns extends Component {
this.columns = response.directory_columns this.columns = response.directory_columns
.sort((a, b) => (a.position > b.position ? 1 : -1)) .sort((a, b) => (a.position > b.position ? 1 : -1))
.map((c) => ({ ...c, enabled: Boolean(c.enabled) })); .map((c) => ({ ...c, enabled: Boolean(c.enabled) }));
} catch { } catch (e) {
popupAjaxError; popupAjaxError(e);
} }
} }

View File

@ -5,6 +5,7 @@ import { tracked } from "@glimmer/tracking";
import { emailValid } from "discourse/lib/utilities"; import { emailValid } from "discourse/lib/utilities";
import I18n from "I18n"; import I18n from "I18n";
import { inject as service } from "@ember/service"; import { inject as service } from "@ember/service";
import { extractError } from "discourse/lib/ajax-error";
export default class GroupAddMembers extends Component { export default class GroupAddMembers extends Component {
@service currentUser; @service currentUser;
@ -42,28 +43,33 @@ export default class GroupAddMembers extends Component {
} }
@action @action
addMembers() { async addMembers() {
if (isEmpty(this.usernamesAndEmails)) { if (isEmpty(this.usernamesAndEmails)) {
return; return;
} }
this.loading = true; this.loading = true;
const promise = this.setOwner
? this.args.model.addOwners(this.usernames, true, this.notifyUsers) try {
: this.args.model.addMembers( if (this.setOwner) {
await this.args.model.addOwners(this.usernames, true, this.notifyUsers);
} else {
await this.args.model.addMembers(
this.usernames, this.usernames,
true, true,
this.notifyUsers, this.notifyUsers,
this.emails this.emails
); );
}
promise this.router.transitionTo("group.members", this.args.model.name, {
.then(() => { queryParams: { ...(this.usernames && { filter: this.usernames }) },
this.router.transitionTo("group.members", this.args.model.name, { });
queryParams: { ...(this.usernames && { filter: this.usernames }) }, this.args.closeModal();
}); } catch (e) {
this.args.closeModal(); this.flash = extractError(e);
}) } finally {
.catch((e) => (this.flash = e.jqXHR.responseJSON.errors.join(". "))) this.loading = false;
.finally(() => (this.loading = false)); }
} }
} }

View File

@ -35,8 +35,8 @@ export default DiscourseRoute.extend({
`/associate/${encodeURIComponent(params.token)}.json` `/associate/${encodeURIComponent(params.token)}.json`
); );
showModal("associate-account-confirm", { model }); showModal("associate-account-confirm", { model });
} catch { } catch (e) {
popupAjaxError; popupAjaxError(e);
} }
}, },
}); });

View File

@ -9,6 +9,7 @@ import { inject as service } from "@ember/service";
import { isBlank, isPresent } from "@ember/utils"; import { isBlank, isPresent } from "@ember/utils";
import { htmlSafe } from "@ember/template"; import { htmlSafe } from "@ember/template";
import { tracked } from "@glimmer/tracking"; import { tracked } from "@glimmer/tracking";
import { extractError } from "discourse/lib/ajax-error";
const DEFAULT_HINT = htmlSafe( const DEFAULT_HINT = htmlSafe(
I18n.t("chat.create_channel.choose_category.default_hint", { I18n.t("chat.create_channel.choose_category.default_hint", {
@ -108,17 +109,16 @@ export default class ChatModalCreateChannel extends Component {
} }
} }
#createChannel(data) { async #createChannel(data) {
return this.chatApi try {
.createChannel(data) const channel = await this.chatApi.createChannel(data);
.then((channel) => {
this.args.closeModal(); this.args.closeModal();
this.chatChannelsManager.follow(channel); this.chatChannelsManager.follow(channel);
this.router.transitionTo("chat.channel", ...channel.routeModels); this.router.transitionTo("chat.channel", ...channel.routeModels);
}) } catch (e) {
.catch((e) => { this.flash = extractError(e);
this.flash = e.jqXHR.responseJSON.errors[0]; }
});
} }
#buildCategorySlug(category) { #buildCategorySlug(category) {

View File

@ -2,6 +2,7 @@ import Component from "@glimmer/component";
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"; import { inject as service } from "@ember/service";
import { extractError } from "discourse/lib/ajax-error";
const DESCRIPTION_MAX_LENGTH = 280; const DESCRIPTION_MAX_LENGTH = 280;
@ -27,18 +28,16 @@ export default class ChatModalEditChannelDescription extends Component {
} }
@action @action
onSaveChatChannelDescription() { async onSaveChatChannelDescription() {
return this.chatApi try {
.updateChannel(this.channel.id, { description: this.editedDescription }) const result = await this.chatApi.updateChannel(this.channel.id, {
.then((result) => { description: this.editedDescription,
this.channel.description = result.channel.description;
this.args.closeModal();
})
.catch((event) => {
if (event.jqXHR?.responseJSON?.errors) {
this.flash = event.jqXHR.responseJSON.errors.join("\n");
}
}); });
this.channel.description = result.channel.description;
this.args.closeModal();
} catch (error) {
this.flash = extractError(error);
}
} }
@action @action