* WIP Global error handler Adding components Adding actions * Add general errors where errors are caught * Filter out non displayable errors * Initial setup to email errors * Add current user/team to error email * Fix a few lints * Ensure errors are cleared when reporting a problem * Add clear all and internationalization * Fix trailing comma issue * fix lints * Use Formatted Text component * Move error list out of channel * Add mobile prefix to i18n id for connection error * Set shouldRender to true in RightMenuDrawerItem.defaultProps * Update component name for RightMenuDrawerItem * Clean up propTypes in RightMenuDrawerItem * Clean up styles in RightMenuDrawerItem * Use selector to filter displayable errors * Clarify code for constructing wrapper style in ErrorList * Avoid indenting email body for error report * Remove extraneous params from errors actions * Rename action type for logging errors * Rename action for logging errors * Set shouldRender to true in RightMenuDrawerItem.defaultProps * Make logged errors displayable by default * Don't log error when websocket connection is closed * Hide button to dismiss all errors if ShowErrorsList isn't enabled * Display only last error in alert bar when ShowErrorsList is disabled * Add error logging where missing in actions * Always show button to report problem * Only include errors in report problem email if any have been logged * Clarify subject of report problem email * Set ShowErrorsList to false in default config.json * Remove unused component + translation for connection errors * Capture entire error object not just message * Display fallback if error.message is blank * Log errors in login actions * Fix construction of errors email body
106 lines
2.8 KiB
JavaScript
106 lines
2.8 KiB
JavaScript
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
|
|
// See License.txt for license information.
|
|
|
|
import {batchActions} from 'redux-batched-actions';
|
|
import Client from 'service/client';
|
|
import {UsersTypes} from 'service/constants';
|
|
import {getLogErrorAction} from './errors';
|
|
const HTTP_UNAUTHORIZED = 401;
|
|
|
|
export async function forceLogoutIfNecessary(err, dispatch) {
|
|
if (err.status_code === HTTP_UNAUTHORIZED && err.url.indexOf('/login') === -1) {
|
|
dispatch({type: UsersTypes.LOGOUT_REQUEST});
|
|
await Client.logout();
|
|
dispatch({type: UsersTypes.LOGOUT_SUCCESS});
|
|
}
|
|
}
|
|
|
|
function dispatcher(type, data, dispatch, getState) {
|
|
if (type.indexOf('SUCCESS') === -1) { // we don't want to pass the data for the request types
|
|
dispatch(requestSuccess(type, data), getState);
|
|
} else {
|
|
dispatch(requestData(type), getState);
|
|
}
|
|
}
|
|
|
|
export function requestData(type) {
|
|
return {
|
|
type
|
|
};
|
|
}
|
|
|
|
export function requestSuccess(type, data) {
|
|
return {
|
|
type,
|
|
data
|
|
};
|
|
}
|
|
|
|
export function requestFailure(type, error) {
|
|
return {
|
|
type,
|
|
error
|
|
};
|
|
}
|
|
|
|
export function bindClientFunc(clientFunc, request, success, failure, ...args) {
|
|
return async (dispatch, getState) => {
|
|
dispatch(requestData(request), getState);
|
|
|
|
let data = null;
|
|
try {
|
|
data = await clientFunc(...args);
|
|
} catch (err) {
|
|
forceLogoutIfNecessary(err, dispatch);
|
|
dispatch(batchActions([
|
|
requestFailure(failure, err),
|
|
getLogErrorAction(err)
|
|
]), getState);
|
|
return;
|
|
}
|
|
|
|
if (Array.isArray(success)) {
|
|
success.forEach((s) => {
|
|
dispatcher(s, data, dispatch, getState);
|
|
});
|
|
} else {
|
|
dispatcher(success, data, dispatch, getState);
|
|
}
|
|
};
|
|
}
|
|
|
|
// Debounce function based on underscores modified to use es6 and a cb
|
|
export function debounce(func, wait, immediate, cb) {
|
|
let timeout;
|
|
return function fx(...args) {
|
|
const runLater = () => {
|
|
timeout = null;
|
|
if (!immediate) {
|
|
Reflect.apply(func, this, args);
|
|
if (cb) {
|
|
cb();
|
|
}
|
|
}
|
|
};
|
|
const callNow = immediate && !timeout;
|
|
clearTimeout(timeout);
|
|
timeout = setTimeout(runLater, wait);
|
|
if (callNow) {
|
|
Reflect.apply(func, this, args);
|
|
if (cb) {
|
|
cb();
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
export class FormattedError extends Error {
|
|
constructor(id, defaultMessage, values = {}) {
|
|
super(defaultMessage);
|
|
this.intl = {
|
|
id,
|
|
defaultMessage,
|
|
values
|
|
};
|
|
}
|
|
}
|