mirror of
https://github.com/flarum/framework.git
synced 2025-02-06 04:24:00 +08:00
Extract AlertManagerState from AlertManager (#2163)
This commit is contained in:
parent
417e878c0c
commit
95f367c837
|
@ -2,7 +2,6 @@ import Page from '../../common/components/Page';
|
||||||
import FieldSet from '../../common/components/FieldSet';
|
import FieldSet from '../../common/components/FieldSet';
|
||||||
import Select from '../../common/components/Select';
|
import Select from '../../common/components/Select';
|
||||||
import Button from '../../common/components/Button';
|
import Button from '../../common/components/Button';
|
||||||
import Alert from '../../common/components/Alert';
|
|
||||||
import saveSettings from '../utils/saveSettings';
|
import saveSettings from '../utils/saveSettings';
|
||||||
import ItemList from '../../common/utils/ItemList';
|
import ItemList from '../../common/utils/ItemList';
|
||||||
import Switch from '../../common/components/Switch';
|
import Switch from '../../common/components/Switch';
|
||||||
|
@ -186,7 +185,10 @@ export default class BasicsPage extends Page {
|
||||||
|
|
||||||
saveSettings(settings)
|
saveSettings(settings)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
app.alerts.show((this.successAlert = new Alert({ type: 'success', children: app.translator.trans('core.admin.basics.saved_message') })));
|
this.successAlert = app.alerts.show({
|
||||||
|
type: 'success',
|
||||||
|
children: app.translator.trans('core.admin.basics.saved_message'),
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch(() => {})
|
.catch(() => {})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|
|
@ -179,9 +179,10 @@ export default class MailPage extends Page {
|
||||||
})
|
})
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
this.sendingTest = false;
|
this.sendingTest = false;
|
||||||
app.alerts.show(
|
this.testEmailSuccessAlert = app.alerts.show({
|
||||||
(this.testEmailSuccessAlert = new Alert({ type: 'success', children: app.translator.trans('core.admin.email.send_test_mail_success') }))
|
type: 'success',
|
||||||
);
|
children: app.translator.trans('core.admin.email.send_test_mail_success'),
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
this.sendingTest = false;
|
this.sendingTest = false;
|
||||||
|
@ -204,7 +205,10 @@ export default class MailPage extends Page {
|
||||||
|
|
||||||
saveSettings(settings)
|
saveSettings(settings)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
app.alerts.show((this.successAlert = new Alert({ type: 'success', children: app.translator.trans('core.admin.basics.saved_message') })));
|
this.successAlert = app.alerts.show({
|
||||||
|
type: 'success',
|
||||||
|
children: app.translator.trans('core.admin.basics.saved_message'),
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch(() => {})
|
.catch(() => {})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import ItemList from './utils/ItemList';
|
import ItemList from './utils/ItemList';
|
||||||
import Alert from './components/Alert';
|
|
||||||
import Button from './components/Button';
|
import Button from './components/Button';
|
||||||
import ModalManager from './components/ModalManager';
|
import ModalManager from './components/ModalManager';
|
||||||
import AlertManager from './components/AlertManager';
|
import AlertManager from './components/AlertManager';
|
||||||
|
@ -23,6 +22,7 @@ import Group from './models/Group';
|
||||||
import Notification from './models/Notification';
|
import Notification from './models/Notification';
|
||||||
import { flattenDeep } from 'lodash-es';
|
import { flattenDeep } from 'lodash-es';
|
||||||
import PageState from './states/PageState';
|
import PageState from './states/PageState';
|
||||||
|
import AlertManagerState from './states/AlertManagerState';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
|
@ -109,13 +109,13 @@ export default class Application {
|
||||||
booted = false;
|
booted = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An Alert that was shown as a result of an AJAX request error. If present,
|
* The key for an Alert that was shown as a result of an AJAX request error.
|
||||||
* it will be dismissed on the next successful request.
|
* If present, it will be dismissed on the next successful request.
|
||||||
*
|
*
|
||||||
* @type {null|Alert}
|
* @type {int}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
requestError = null;
|
requestErrorAlert = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The page the app is currently on.
|
* The page the app is currently on.
|
||||||
|
@ -139,6 +139,11 @@ export default class Application {
|
||||||
*/
|
*/
|
||||||
previous = new PageState(null);
|
previous = new PageState(null);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* An object that manages the state of active alerts.
|
||||||
|
*/
|
||||||
|
alerts = new AlertManagerState();
|
||||||
|
|
||||||
data;
|
data;
|
||||||
|
|
||||||
title = '';
|
title = '';
|
||||||
|
@ -175,7 +180,7 @@ export default class Application {
|
||||||
|
|
||||||
mount(basePath = '') {
|
mount(basePath = '') {
|
||||||
this.modal = m.mount(document.getElementById('modal'), <ModalManager />);
|
this.modal = m.mount(document.getElementById('modal'), <ModalManager />);
|
||||||
this.alerts = m.mount(document.getElementById('alerts'), <AlertManager />);
|
m.mount(document.getElementById('alerts'), <AlertManager state={this.alerts} />);
|
||||||
|
|
||||||
this.drawer = new Drawer();
|
this.drawer = new Drawer();
|
||||||
|
|
||||||
|
@ -313,7 +318,7 @@ export default class Application {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.requestError) this.alerts.dismiss(this.requestError.alert);
|
if (this.requestErrorAlert) 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.
|
||||||
|
@ -322,8 +327,6 @@ export default class Application {
|
||||||
m.request(options).then(
|
m.request(options).then(
|
||||||
(response) => deferred.resolve(response),
|
(response) => deferred.resolve(response),
|
||||||
(error) => {
|
(error) => {
|
||||||
this.requestError = error;
|
|
||||||
|
|
||||||
let children;
|
let children;
|
||||||
|
|
||||||
switch (error.status) {
|
switch (error.status) {
|
||||||
|
@ -357,7 +360,7 @@ export default class Application {
|
||||||
// the details property is decoded to transform escaped characters such as '\n'
|
// the details property is decoded to transform escaped characters such as '\n'
|
||||||
const formattedError = error.response && Array.isArray(error.response.errors) && error.response.errors.map((e) => decodeURI(e.detail));
|
const formattedError = error.response && Array.isArray(error.response.errors) && error.response.errors.map((e) => decodeURI(e.detail));
|
||||||
|
|
||||||
error.alert = new Alert({
|
error.alert = {
|
||||||
type: 'error',
|
type: 'error',
|
||||||
children,
|
children,
|
||||||
controls: isDebug && [
|
controls: isDebug && [
|
||||||
|
@ -365,7 +368,7 @@ export default class Application {
|
||||||
Debug
|
Debug
|
||||||
</Button>,
|
</Button>,
|
||||||
],
|
],
|
||||||
});
|
};
|
||||||
|
|
||||||
try {
|
try {
|
||||||
options.errorHandler(error);
|
options.errorHandler(error);
|
||||||
|
@ -381,7 +384,7 @@ export default class Application {
|
||||||
console.groupEnd();
|
console.groupEnd();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.alerts.show(error.alert);
|
this.requestErrorAlert = this.alerts.show(error.alert);
|
||||||
}
|
}
|
||||||
|
|
||||||
deferred.reject(error);
|
deferred.reject(error);
|
||||||
|
@ -397,7 +400,7 @@ export default class Application {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
showDebug(error, formattedError) {
|
showDebug(error, formattedError) {
|
||||||
this.alerts.dismiss(this.requestError.alert);
|
this.alerts.dismiss(this.requestErrorAlert);
|
||||||
|
|
||||||
this.modal.show(new RequestErrorModal({ error, formattedError }));
|
this.modal.show(new RequestErrorModal({ error, formattedError }));
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,20 +7,16 @@ import Alert from './Alert';
|
||||||
*/
|
*/
|
||||||
export default class AlertManager extends Component {
|
export default class AlertManager extends Component {
|
||||||
init() {
|
init() {
|
||||||
/**
|
this.state = this.props.state;
|
||||||
* An array of Alert components which are currently showing.
|
|
||||||
*
|
|
||||||
* @type {Alert[]}
|
|
||||||
* @protected
|
|
||||||
*/
|
|
||||||
this.components = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
view() {
|
view() {
|
||||||
return (
|
return (
|
||||||
<div className="AlertManager">
|
<div className="AlertManager">
|
||||||
{this.components.map((component) => (
|
{Object.entries(this.state.getActiveAlerts()).map(([key, alert]) => (
|
||||||
<div className="AlertManager-alert">{component}</div>
|
<div className="AlertManager-alert">
|
||||||
|
{(alert.componentClass || Alert).component({ ...alert.attrs, ondismiss: this.state.dismiss.bind(this.state, key) })}
|
||||||
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -32,46 +28,4 @@ export default class AlertManager extends Component {
|
||||||
// to be retained across route changes.
|
// to be retained across route changes.
|
||||||
context.retain = true;
|
context.retain = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Show an Alert in the alerts area.
|
|
||||||
*
|
|
||||||
* @param {Alert} component
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
show(component) {
|
|
||||||
if (!(component instanceof Alert)) {
|
|
||||||
throw new Error('The AlertManager component can only show Alert components');
|
|
||||||
}
|
|
||||||
|
|
||||||
component.props.ondismiss = this.dismiss.bind(this, component);
|
|
||||||
|
|
||||||
this.components.push(component);
|
|
||||||
m.redraw();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Dismiss an alert.
|
|
||||||
*
|
|
||||||
* @param {Alert} component
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
dismiss(component) {
|
|
||||||
const index = this.components.indexOf(component);
|
|
||||||
|
|
||||||
if (index !== -1) {
|
|
||||||
this.components.splice(index, 1);
|
|
||||||
m.redraw();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear all alerts.
|
|
||||||
*
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
clear() {
|
|
||||||
this.components = [];
|
|
||||||
m.redraw();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,16 +11,16 @@ import Button from './Button';
|
||||||
export default class Modal extends Component {
|
export default class Modal extends Component {
|
||||||
init() {
|
init() {
|
||||||
/**
|
/**
|
||||||
* An alert component to show below the header.
|
* Attributes for an alert component to show below the header.
|
||||||
*
|
*
|
||||||
* @type {Alert}
|
* @type {object}
|
||||||
*/
|
*/
|
||||||
this.alert = null;
|
this.alertAttrs = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
view() {
|
view() {
|
||||||
if (this.alert) {
|
if (this.alertAttrs) {
|
||||||
this.alert.props.dismissible = false;
|
this.alertAttrs.dismissible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -43,7 +43,7 @@ export default class Modal extends Component {
|
||||||
<h3 className="App-titleControl App-titleControl--text">{this.title()}</h3>
|
<h3 className="App-titleControl App-titleControl--text">{this.title()}</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{alert ? <div className="Modal-alert">{this.alert}</div> : ''}
|
{this.alertAttrs ? <div className="Modal-alert">{Alert.component(this.alertAttrs)}</div> : ''}
|
||||||
|
|
||||||
{this.content()}
|
{this.content()}
|
||||||
</form>
|
</form>
|
||||||
|
@ -123,7 +123,7 @@ export default class Modal extends Component {
|
||||||
* @param {RequestError} error
|
* @param {RequestError} error
|
||||||
*/
|
*/
|
||||||
onerror(error) {
|
onerror(error) {
|
||||||
this.alert = error.alert;
|
this.alertAttrs = error.alert;
|
||||||
|
|
||||||
m.redraw();
|
m.redraw();
|
||||||
|
|
||||||
|
|
50
framework/core/js/src/common/states/AlertManagerState.js
Normal file
50
framework/core/js/src/common/states/AlertManagerState.js
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
import Alert from '../components/Alert';
|
||||||
|
|
||||||
|
export default class AlertManagerState {
|
||||||
|
constructor() {
|
||||||
|
this.activeAlerts = {};
|
||||||
|
this.alertId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
getActiveAlerts() {
|
||||||
|
return this.activeAlerts;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show an Alert in the alerts area.
|
||||||
|
*/
|
||||||
|
show(attrs, componentClass = Alert) {
|
||||||
|
// Breaking Change Compliance Warning, Remove in Beta 15.
|
||||||
|
// This is applied to the first argument (attrs) because previously, the alert was passed as the first argument.
|
||||||
|
if (attrs === Alert || attrs instanceof Alert) {
|
||||||
|
// This is duplicated so that if the error is caught, an error message still shows up in the debug console.
|
||||||
|
console.error('The AlertManager can only show Alerts. Whichever extension triggered this alert should be updated to comply with beta 14.');
|
||||||
|
throw new Error('The AlertManager can only show Alerts. Whichever extension triggered this alert should be updated to comply with beta 14.');
|
||||||
|
}
|
||||||
|
// End Change Compliance Warning, Remove in Beta 15
|
||||||
|
this.activeAlerts[++this.alertId] = { attrs, componentClass };
|
||||||
|
m.redraw();
|
||||||
|
|
||||||
|
return this.alertId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dismiss an alert.
|
||||||
|
*/
|
||||||
|
dismiss(key) {
|
||||||
|
if (!key || !(key in this.activeAlerts)) return;
|
||||||
|
|
||||||
|
delete this.activeAlerts[key];
|
||||||
|
m.redraw();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear all alerts.
|
||||||
|
*
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
clear() {
|
||||||
|
this.activeAlerts = {};
|
||||||
|
m.redraw();
|
||||||
|
}
|
||||||
|
}
|
|
@ -122,7 +122,7 @@ export default class ChangeEmailModal extends Modal {
|
||||||
|
|
||||||
onerror(error) {
|
onerror(error) {
|
||||||
if (error.status === 401) {
|
if (error.status === 401) {
|
||||||
error.alert.props.children = app.translator.trans('core.forum.change_email.incorrect_password_message');
|
error.alert.children = app.translator.trans('core.forum.change_email.incorrect_password_message');
|
||||||
}
|
}
|
||||||
|
|
||||||
super.onerror(error);
|
super.onerror(error);
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import ComposerBody from './ComposerBody';
|
import ComposerBody from './ComposerBody';
|
||||||
import Alert from '../../common/components/Alert';
|
|
||||||
import Button from '../../common/components/Button';
|
import Button from '../../common/components/Button';
|
||||||
import icon from '../../common/helpers/icon';
|
import icon from '../../common/helpers/icon';
|
||||||
|
|
||||||
|
@ -101,13 +100,11 @@ export default class EditPostComposer extends ComposerBody {
|
||||||
app.alerts.dismiss(alert);
|
app.alerts.dismiss(alert);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
app.alerts.show(
|
alert = app.alerts.show({
|
||||||
(alert = new Alert({
|
|
||||||
type: 'success',
|
type: 'success',
|
||||||
children: app.translator.trans('core.forum.composer_edit.edited_message'),
|
children: app.translator.trans('core.forum.composer_edit.edited_message'),
|
||||||
controls: [viewButton],
|
controls: [viewButton],
|
||||||
}))
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app.composer.hide();
|
app.composer.hide();
|
||||||
|
|
|
@ -104,7 +104,7 @@ export default class ForgotPasswordModal extends Modal {
|
||||||
|
|
||||||
onerror(error) {
|
onerror(error) {
|
||||||
if (error.status === 404) {
|
if (error.status === 404) {
|
||||||
error.alert.props.children = app.translator.trans('core.forum.forgot_password.not_found_message');
|
error.alert.children = app.translator.trans('core.forum.forgot_password.not_found_message');
|
||||||
}
|
}
|
||||||
|
|
||||||
super.onerror(error);
|
super.onerror(error);
|
||||||
|
|
|
@ -179,7 +179,7 @@ export default class LogInModal extends Modal {
|
||||||
|
|
||||||
onerror(error) {
|
onerror(error) {
|
||||||
if (error.status === 401) {
|
if (error.status === 401) {
|
||||||
error.alert.props.children = app.translator.trans('core.forum.log_in.invalid_login_message');
|
error.alert.children = app.translator.trans('core.forum.log_in.invalid_login_message');
|
||||||
}
|
}
|
||||||
|
|
||||||
super.onerror(error);
|
super.onerror(error);
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import ComposerBody from './ComposerBody';
|
import ComposerBody from './ComposerBody';
|
||||||
import Alert from '../../common/components/Alert';
|
|
||||||
import Button from '../../common/components/Button';
|
import Button from '../../common/components/Button';
|
||||||
import icon from '../../common/helpers/icon';
|
import icon from '../../common/helpers/icon';
|
||||||
import extractText from '../../common/utils/extractText';
|
import extractText from '../../common/utils/extractText';
|
||||||
|
@ -104,13 +103,11 @@ export default class ReplyComposer extends ComposerBody {
|
||||||
app.alerts.dismiss(alert);
|
app.alerts.dismiss(alert);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
app.alerts.show(
|
alert = app.alerts.show({
|
||||||
(alert = new Alert({
|
|
||||||
type: 'success',
|
type: 'success',
|
||||||
children: app.translator.trans('core.forum.composer_reply.posted_message'),
|
children: app.translator.trans('core.forum.composer_reply.posted_message'),
|
||||||
controls: [viewButton],
|
controls: [viewButton],
|
||||||
}))
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
app.composer.hide();
|
app.composer.hide();
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import Alert from '../../common/components/Alert';
|
|
||||||
import Button from '../../common/components/Button';
|
import Button from '../../common/components/Button';
|
||||||
import Separator from '../../common/components/Separator';
|
import Separator from '../../common/components/Separator';
|
||||||
import EditUserModal from '../components/EditUserModal';
|
import EditUserModal from '../components/EditUserModal';
|
||||||
|
@ -134,12 +133,10 @@ export default {
|
||||||
error: 'core.forum.user_controls.delete_error_message',
|
error: 'core.forum.user_controls.delete_error_message',
|
||||||
}[type];
|
}[type];
|
||||||
|
|
||||||
app.alerts.show(
|
app.alerts.show({
|
||||||
new Alert({
|
|
||||||
type,
|
type,
|
||||||
children: app.translator.trans(message, { username, email }),
|
children: app.translator.trans(message, { username, email }),
|
||||||
})
|
});
|
||||||
);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue
Block a user