DEV: Show theme/plugin error banner for route loading failures (#24218)
This aims to help admins and developers identify the cause of loading issues on routes. As with other theme/plugin errors, the UI banner is only shown to administrators. For non-admins, the information is only written to the browser console.
This commit is contained in:
parent
08e2ee3ec1
commit
67bcef3959
|
@ -8,6 +8,7 @@ import { setting } from "discourse/lib/computed";
|
|||
import cookie from "discourse/lib/cookie";
|
||||
import logout from "discourse/lib/logout";
|
||||
import mobile from "discourse/lib/mobile";
|
||||
import identifySource, { consolePrefix } from "discourse/lib/source-identifier";
|
||||
import DiscourseURL from "discourse/lib/url";
|
||||
import Category from "discourse/models/category";
|
||||
import Composer from "discourse/models/composer";
|
||||
|
@ -39,6 +40,7 @@ const ApplicationRoute = DiscourseRoute.extend({
|
|||
loadingSlider: service(),
|
||||
router: service(),
|
||||
siteSettings: service(),
|
||||
clientErrorHandler: service(),
|
||||
|
||||
get includeExternalLoginMethods() {
|
||||
return (
|
||||
|
@ -117,15 +119,24 @@ const ApplicationRoute = DiscourseRoute.extend({
|
|||
const xhrOrErr = err.jqXHR ? err.jqXHR : err;
|
||||
const exceptionController = this.controllerFor("exception");
|
||||
|
||||
const c = window.console;
|
||||
if (c && c.error) {
|
||||
c.error(xhrOrErr);
|
||||
}
|
||||
const themeOrPluginSource = identifySource(err);
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(
|
||||
...[consolePrefix(err, themeOrPluginSource), xhrOrErr].filter(Boolean)
|
||||
);
|
||||
|
||||
if (xhrOrErr && xhrOrErr.status === 404) {
|
||||
return this.router.transitionTo("exception-unknown");
|
||||
}
|
||||
|
||||
if (themeOrPluginSource) {
|
||||
this.clientErrorHandler.displayErrorNotice(
|
||||
"Error loading route",
|
||||
themeOrPluginSource
|
||||
);
|
||||
}
|
||||
|
||||
exceptionController.setProperties({
|
||||
lastTransition: transition,
|
||||
thrown: xhrOrErr,
|
||||
|
|
|
@ -83,11 +83,15 @@ export default class ClientErrorHandlerService extends Service {
|
|||
|
||||
let html = `⚠️ ${escape(message)}`;
|
||||
|
||||
if (source && source.type === "theme") {
|
||||
if (source?.type === "theme") {
|
||||
html += `<br/>${I18n.t("themes.error_caused_by", {
|
||||
name: escape(source.name),
|
||||
path: source.path,
|
||||
})}`;
|
||||
} else if (source?.type === "plugin") {
|
||||
html += `<br/>${I18n.t("broken_plugin_alert", {
|
||||
name: escape(source.name),
|
||||
})}`;
|
||||
}
|
||||
|
||||
html += `<br/><span class='theme-error-suffix'>${I18n.t(
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
import { getOwner } from "@ember/application";
|
||||
import { visit } from "@ember/test-helpers";
|
||||
import { test } from "qunit";
|
||||
import Sinon from "sinon";
|
||||
import { acceptance } from "../helpers/qunit-helpers";
|
||||
|
||||
acceptance("client-error-handler service", function (needs) {
|
||||
needs.user({
|
||||
admin: true,
|
||||
});
|
||||
|
||||
test("displays route-loading errors caused by themes", async function (assert) {
|
||||
const fakeError = new Error("Something bad happened");
|
||||
fakeError.stack = "assets/plugins/some-fake-plugin-name.js";
|
||||
|
||||
const topicRoute = getOwner(this).lookup("route:topic");
|
||||
Sinon.stub(topicRoute, "model").throws(fakeError);
|
||||
|
||||
const consoleStub = Sinon.stub(console, "error");
|
||||
try {
|
||||
await visit("/t/280");
|
||||
} catch {}
|
||||
consoleStub.restore();
|
||||
|
||||
assert.dom(".broken-theme-alert-banner").exists();
|
||||
assert
|
||||
.dom(".broken-theme-alert-banner")
|
||||
.containsText("some-fake-plugin-name");
|
||||
});
|
||||
});
|
|
@ -221,6 +221,8 @@ en:
|
|||
|
||||
broken_decorator_alert: "Posts may not display correctly because one of the post content decorators on your site raised an error."
|
||||
|
||||
broken_plugin_alert: "Caused by plugin '%{name}'"
|
||||
|
||||
s3:
|
||||
regions:
|
||||
ap_northeast_1: "Asia Pacific (Tokyo)"
|
||||
|
|
Loading…
Reference in New Issue