mirror of
https://github.com/flarum/core.git
synced 2025-08-06 08:27:42 +02:00
common: use AlertState for Alert component data - pass this to AlertManager
app.alerts.show() now can take plain object OR AlertState instance - will return AlertState.prototype.key app.alerts.dismiss() takes AlertState or state key (returned by show())
This commit is contained in:
@@ -1,13 +1,13 @@
|
||||
import app from '../app';
|
||||
|
||||
import Page from './Page';
|
||||
import Button from '../../common/components/Button';
|
||||
import FieldSet from '../../common/components/FieldSet';
|
||||
import Select from '../../common/components/Select';
|
||||
import Button from '../../common/components/Button';
|
||||
import Alert from '../../common/components/Alert';
|
||||
import Switch from '../../common/components/Switch';
|
||||
import saveSettings from '../utils/saveSettings';
|
||||
import ItemList from '../../common/utils/ItemList';
|
||||
import Switch from '../../common/components/Switch';
|
||||
import AlertState from '../../common/states/AlertState';
|
||||
|
||||
import Stream from 'mithril/stream';
|
||||
|
||||
@@ -27,7 +27,7 @@ export default class BasicsPage extends Page {
|
||||
|
||||
localeOptions: object = {};
|
||||
|
||||
successAlert: Alert;
|
||||
successAlert?: number;
|
||||
|
||||
oninit(vnode) {
|
||||
super.oninit(vnode);
|
||||
@@ -180,9 +180,7 @@ export default class BasicsPage extends Page {
|
||||
|
||||
saveSettings(settings)
|
||||
.then(() => {
|
||||
app.alerts.show(
|
||||
(this.successAlert = Alert.component({ 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(() => {})
|
||||
.then(() => {
|
||||
|
@@ -1,12 +1,13 @@
|
||||
import app from '../app';
|
||||
|
||||
import Page from './Page';
|
||||
import FieldSet from '../../common/components/FieldSet';
|
||||
import Button from '../../common/components/Button';
|
||||
import Alert from '../../common/components/Alert';
|
||||
import Select from '../../common/components/Select';
|
||||
import Button from '../../common/components/Button';
|
||||
import FieldSet from '../../common/components/FieldSet';
|
||||
import LoadingIndicator from '../../common/components/LoadingIndicator';
|
||||
import Select from '../../common/components/Select';
|
||||
import saveSettings from '../utils/saveSettings';
|
||||
import AlertState from '../../common/states/AlertState';
|
||||
|
||||
import Stream from 'mithril/stream';
|
||||
|
||||
@@ -21,7 +22,7 @@ export default class MailPage extends Page {
|
||||
|
||||
status = { sending: false, errors: {} };
|
||||
|
||||
successAlert: Alert;
|
||||
successAlert?: number;
|
||||
|
||||
oninit(vnode) {
|
||||
super.oninit(vnode);
|
||||
@@ -179,9 +180,7 @@ export default class MailPage extends Page {
|
||||
|
||||
saveSettings(settings)
|
||||
.then(() => {
|
||||
app.alerts.show(
|
||||
(this.successAlert = Alert.component({ 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(() => {})
|
||||
.then(() => {
|
||||
|
@@ -19,13 +19,14 @@ import Post from './models/Post';
|
||||
import Group from './models/Group';
|
||||
import Notification from './models/Notification';
|
||||
|
||||
import Alert from './components/Alert';
|
||||
import AlertManager from './components/AlertManager';
|
||||
import Button from './components/Button';
|
||||
import ModalManager from './components/ModalManager';
|
||||
import Page from './components/Page';
|
||||
import RequestErrorModal from './components/RequestErrorModal';
|
||||
|
||||
import AlertState from './states/AlertState';
|
||||
|
||||
import flattenDeep from 'lodash/flattenDeep';
|
||||
|
||||
export type ApplicationData = {
|
||||
@@ -330,7 +331,7 @@ export default abstract class Application {
|
||||
|
||||
const isDebug = app.forum.attribute('debug');
|
||||
|
||||
error.alert = Alert.component({
|
||||
error.alert = new AlertState({
|
||||
type: 'error',
|
||||
children,
|
||||
controls: isDebug && [
|
||||
|
@@ -1,34 +1,48 @@
|
||||
import * as Mithril from 'mithril';
|
||||
|
||||
import Component, { ComponentProps } from '../Component';
|
||||
import Button from './Button';
|
||||
import listItems from '../helpers/listItems';
|
||||
import extract from '../utils/extract';
|
||||
import * as Mithril from 'mithril';
|
||||
import AlertState from '../states/AlertState';
|
||||
|
||||
export interface AlertProps extends ComponentProps {
|
||||
export interface AlertData extends ComponentProps {
|
||||
/**
|
||||
* An array of controls to show in the alert.
|
||||
*/
|
||||
controls?: Mithril.ChildArray;
|
||||
|
||||
/**
|
||||
* The type of alert this is. Will be used to give the alert a class
|
||||
* name of `Alert--{type}`.
|
||||
*/
|
||||
type?: string;
|
||||
|
||||
/**
|
||||
* Whether or not the alert can be dismissed.
|
||||
*/
|
||||
dismissible?: boolean;
|
||||
|
||||
/**
|
||||
* A callback to run when the alert is dismissed.
|
||||
*/
|
||||
ondismiss?: () => any;
|
||||
}
|
||||
|
||||
export interface AlertProps extends AlertData {
|
||||
state: AlertState;
|
||||
}
|
||||
|
||||
/**
|
||||
* The `Alert` component represents an alert box, which contains a message,
|
||||
* some controls, and may be dismissible.
|
||||
*
|
||||
* The alert may have the following special props:
|
||||
*
|
||||
* - `type` The type of alert this is. Will be used to give the alert a class
|
||||
* name of `Alert--{type}`.
|
||||
* - `controls` An array of controls to show in the alert.
|
||||
* - `dismissible` Whether or not the alert can be dismissed.
|
||||
* - `ondismiss` A callback to run when the alert is dismissed.
|
||||
*
|
||||
* All other props will be assigned as attributes on the alert element.
|
||||
*/
|
||||
export default class Alert extends Component<AlertProps> {
|
||||
view() {
|
||||
const attrs: AlertProps = Object.assign({}, this.props);
|
||||
const data = this.props.state?.data || this.props;
|
||||
const attrs: AlertData = Object.assign({}, data);
|
||||
|
||||
const type: string = extract(attrs, 'type');
|
||||
attrs.className = `Alert Alert--${type} ${attrs.className || ''}`;
|
||||
@@ -41,7 +55,7 @@ export default class Alert extends Component<AlertProps> {
|
||||
// the alert.
|
||||
const dismissible: boolean | undefined = extract(attrs, 'dismissible');
|
||||
const ondismiss: () => any = extract(attrs, 'ondismiss');
|
||||
const dismissControl = [];
|
||||
const dismissControl: JSX.Element[] = [];
|
||||
|
||||
if (dismissible || dismissible === undefined) {
|
||||
dismissControl.push(<Button icon="fas fa-times" className="Button Button--link Button--icon Alert-dismiss" onclick={ondismiss} />);
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import Component, { ComponentProps } from '../Component';
|
||||
import Alert from './Alert';
|
||||
import { Vnode } from 'mithril';
|
||||
import Component from '../Component';
|
||||
import AlertState from '../states/AlertState';
|
||||
import Alert, { AlertData } from './Alert';
|
||||
|
||||
/**
|
||||
* The `AlertManager` component provides an area in which `Alert` components can
|
||||
@@ -10,13 +10,15 @@ export default class AlertManager extends Component {
|
||||
/**
|
||||
* An array of Alert components which are currently showing.
|
||||
*/
|
||||
protected components: Vnode<ComponentProps, Alert>[] = [];
|
||||
protected states: AlertState[] = [];
|
||||
|
||||
view() {
|
||||
return (
|
||||
<div className="AlertManager">
|
||||
{this.components.map((vnode) => (
|
||||
<div className="AlertManager-alert">{vnode}</div>
|
||||
{this.states.map((state) => (
|
||||
<div className="AlertManager-alert">
|
||||
<Alert state={state} ondismiss={this.dismiss.bind(this)} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
@@ -25,21 +27,27 @@ export default class AlertManager extends Component {
|
||||
/**
|
||||
* Show an Alert in the alerts area.
|
||||
*/
|
||||
public show(vnode: Vnode<ComponentProps, Alert>) {
|
||||
vnode.attrs.ondismiss = this.dismiss.bind(this, vnode);
|
||||
public show(state: AlertState | AlertData): number {
|
||||
if (!(state instanceof AlertState)) state = new AlertState(state);
|
||||
|
||||
this.components.push(vnode);
|
||||
this.states.push(state as AlertState);
|
||||
m.redraw();
|
||||
|
||||
return state.key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismiss an alert.
|
||||
*/
|
||||
public dismiss(vnode) {
|
||||
const index = this.components.indexOf(vnode);
|
||||
public dismiss(keyOrState?: AlertState | number) {
|
||||
if (!keyOrState) return;
|
||||
|
||||
const key = keyOrState instanceof AlertState ? keyOrState.key : keyOrState;
|
||||
|
||||
let index = this.states.indexOf(this.states.filter((a) => a.key == key)[0]);
|
||||
|
||||
if (index !== -1) {
|
||||
this.components.splice(index, 1);
|
||||
this.states.splice(index, 1);
|
||||
m.redraw();
|
||||
}
|
||||
}
|
||||
@@ -48,7 +56,7 @@ export default class AlertManager extends Component {
|
||||
* Clear all alerts.
|
||||
*/
|
||||
public clear() {
|
||||
this.components = [];
|
||||
this.states = [];
|
||||
m.redraw();
|
||||
}
|
||||
}
|
||||
|
11
js/src/common/states/AlertState.ts
Normal file
11
js/src/common/states/AlertState.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { AlertData } from '../components/Alert';
|
||||
|
||||
export default class AlertState {
|
||||
data: AlertData;
|
||||
key: number;
|
||||
|
||||
constructor(data: AlertData, key = Date.now()) {
|
||||
this.data = data;
|
||||
this.key = key;
|
||||
}
|
||||
}
|
@@ -1,5 +1,7 @@
|
||||
import Mithril from 'mithril';
|
||||
|
||||
import AlertState from '../states/AlertState';
|
||||
|
||||
export interface RequestErrorResponse extends JSON {
|
||||
errors?: {
|
||||
code: string;
|
||||
@@ -15,7 +17,7 @@ export default class RequestError {
|
||||
options: Mithril.RequestOptions;
|
||||
xhr: XMLHttpRequest;
|
||||
response?: RequestErrorResponse;
|
||||
alert?: Mithril.Vnode;
|
||||
alert?: AlertState;
|
||||
|
||||
constructor(status, responseText, options, xhr) {
|
||||
this.status = status;
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import Alert from '../../common/components/Alert';
|
||||
import app from '../app';
|
||||
|
||||
import Button from '../../common/components/Button';
|
||||
import Separator from '../../common/components/Separator';
|
||||
import EditUserModal from '../components/EditUserModal';
|
||||
@@ -103,15 +104,13 @@ export default {
|
||||
* Show deletion alert of user.
|
||||
*/
|
||||
showDeletionAlert(user: User, type: string) {
|
||||
const { username, email } = user.data.attributes;
|
||||
const { username, email } = user.data.attributes!;
|
||||
const message = `core.forum.user_controls.delete_${type}_message`;
|
||||
|
||||
app.alerts.show(
|
||||
Alert.component({
|
||||
type,
|
||||
children: app.translator.trans(message, { username, email }),
|
||||
})
|
||||
);
|
||||
app.alerts.show({
|
||||
type,
|
||||
children: app.translator.trans(message, { username, email }),
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
Reference in New Issue
Block a user