Add "Debug" button to inspect the response of a failed AJAX request

Related to #118
This commit is contained in:
Toby Zerner 2015-09-18 16:46:46 +09:30
parent 80665450fc
commit efca923d30
6 changed files with 79 additions and 17 deletions

View File

@ -10,6 +10,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- Tags: Ability to set the tags page as the home page. - Tags: Ability to set the tags page as the home page.
- `bidi` attribute for Mithril elements as a shortcut to set up bidirectional bindings. - `bidi` attribute for Mithril elements as a shortcut to set up bidirectional bindings.
- Abstract SettingsModal component for quickly building admin config modals. - Abstract SettingsModal component for quickly building admin config modals.
- "Debug" button to inspect the response of a failed AJAX request.
### Changed ### Changed
- Migrations must be namespaced under `Flarum\Migrations\{Core|ExtensionName}`. ([#422](https://github.com/flarum/core/issues/422)) - Migrations must be namespaced under `Flarum\Migrations\{Core|ExtensionName}`. ([#422](https://github.com/flarum/core/issues/422))

View File

@ -1,8 +1,11 @@
import ItemList from 'flarum/utils/ItemList'; import ItemList from 'flarum/utils/ItemList';
import Alert from 'flarum/components/Alert'; import Alert from 'flarum/components/Alert';
import Button from 'flarum/components/Button';
import RequestErrorModal from 'flarum/components/RequestErrorModal';
import Translator from 'flarum/Translator'; import Translator from 'flarum/Translator';
import extract from 'flarum/utils/extract'; import extract from 'flarum/utils/extract';
import patchMithril from 'flarum/utils/patchMithril'; import patchMithril from 'flarum/utils/patchMithril';
import RequestError from 'flarum/utils/RequestError';
/** /**
* The `App` class provides a container for an application, as well as various * The `App` class provides a container for an application, as well as various
@ -193,7 +196,7 @@ export default class App {
try { try {
return JSON.parse(responseText); return JSON.parse(responseText);
} catch (e) { } catch (e) {
throw new Error('Oops! Something went wrong on the server. Please reload the page and try again.'); throw new RequestError(e.message, responseText);
} }
}); });
@ -202,35 +205,52 @@ export default class App {
// awry. // awry.
const original = options.extract; const original = options.extract;
options.extract = xhr => { options.extract = xhr => {
let responseText;
if (original) {
responseText = original(xhr.responseText);
} else {
responseText = xhr.responseText.length > 0 ? xhr.responseText : null;
}
const status = xhr.status; const status = xhr.status;
if (status >= 500 && status <= 599) { if (status >= 500 && status <= 599) {
throw new Error('Oops! Something went wrong on the server. Please reload the page and try again.'); throw new RequestError('Internal Server Error', responseText);
} }
if (original) { return responseText;
return original(xhr.responseText);
}
return xhr.responseText.length > 0 ? xhr.responseText : null;
}; };
this.alerts.dismiss(this.requestError); this.alerts.dismiss(this.requestErrorAlert);
// Now make the request. If it's a failure, inspect the error that was // Now make the request. If it's a failure, inspect the error that was
// returned and show an alert containing its contents. // returned and show an alert containing its contents.
return m.request(options).then(null, response => { return m.request(options).then(null, error => {
if (response instanceof Error) { if (error instanceof RequestError) {
this.alerts.show(this.requestError = new Alert({ this.alerts.show(this.requestErrorAlert = new Alert({
type: 'error', type: 'error',
children: response.message children: 'Oops! Something went wrong. Please reload the page and try again.',
controls: app.forum.attribute('debug') ? [
<Button className="Button Button--link" onclick={this.showDebug.bind(this, error)}>Debug</Button>
] : undefined
})); }));
} }
throw response; throw error;
}); });
} }
/**
* @param {RequestError} error
* @private
*/
showDebug(error) {
this.alerts.dismiss(this.requestErrorAlert);
this.modal.show(new RequestErrorModal({error}));
}
/** /**
* Show alert error messages for each error returned in an API response. * Show alert error messages for each error returned in an API response.
* *

View File

@ -0,0 +1,25 @@
import Modal from 'flarum/components/Modal';
export default class RequestErrorModal extends Modal {
className() {
return 'RequestErrorModal Modal--large';
}
title() {
return this.props.error.message;
}
content() {
let responseText;
try {
responseText = JSON.stringify(JSON.parse(this.props.error.responseText), null, 2);
} catch (e) {
responseText = this.props.error.responseText;
}
return <div className="Modal-body">
<pre>{responseText}</pre>
</div>;
}
}

View File

@ -0,0 +1,6 @@
export default class RequestError {
constructor(message, responseText) {
this.message = message;
this.responseText = responseText;
}
}

View File

@ -4,21 +4,21 @@
background: @alert-bg; background: @alert-bg;
line-height: 1.5; line-height: 1.5;
&, button, button:hover { &, .Button, .Button:hover {
color: @alert-color; color: @alert-color;
} }
} }
.Alert--error { .Alert--error {
background: @alert-error-bg; background: @alert-error-bg;
&, a, a:hover, button, button:hover { &, a, a:hover, .Button, .Button:hover {
color: @alert-error-color; color: @alert-error-color;
} }
} }
.Alert--success { .Alert--success {
background: @alert-success-bg; background: @alert-success-bg;
&, a, a:hover, button, button:hover { &, a, a:hover, .Button, .Button:hover {
color: @alert-success-color; color: @alert-success-color;
} }
a, a:hover { a, a:hover {
@ -35,7 +35,7 @@
display: inline-block; display: inline-block;
margin: 0 5px; margin: 0 5px;
> a { > a, > .Button {
text-transform: uppercase; text-transform: uppercase;
font-size: 12px; font-size: 12px;
font-weight: bold; font-weight: bold;
@ -45,6 +45,9 @@
text-decoration: none; text-decoration: none;
opacity: 0.5; opacity: 0.5;
} }
&:hover {
text-decoration: underline;
}
} }
> .Button { > .Button {

View File

@ -130,3 +130,10 @@ blockquote ol:last-child {
position: fixed; position: fixed;
} }
} }
.RequestErrorModal {
pre {
white-space: pre-wrap;
margin: 0;
}
}