- react
- jsx-a11y
- import
+- promise
parserOptions:
sourceType: module
- "app/javascript/**/__tests__/**"
import/no-unresolved: error
import/no-webpack-loader-syntax: error
+
+ promise/catch-or-return: error
dispatch(importFetchedAccount(response.data));
})).then(() => {
dispatch(fetchAccountSuccess());
- }, error => {
+ }).catch(error => {
dispatch(fetchAccountFail(id, error));
});
};
+import { defineMessages } from 'react-intl';
+
+const messages = defineMessages({
+ unexpectedTitle: { id: 'alert.unexpected.title', defaultMessage: 'Oops!' },
+ unexpectedMessage: { id: 'alert.unexpected.message', defaultMessage: 'An unexpected error occurred.' },
+});
+
export const ALERT_SHOW = 'ALERT_SHOW';
export const ALERT_DISMISS = 'ALERT_DISMISS';
export const ALERT_CLEAR = 'ALERT_CLEAR';
message,
};
};
+
+export function showAlertForError(error) {
+ if (error.response) {
+ const { data, status, statusText } = error.response;
+
+ let message = statusText;
+ let title = `${status}`;
+
+ if (data.error) {
+ message = data.error;
+ }
+
+ return showAlert(title, message);
+ } else {
+ console.error(error);
+ return showAlert(messages.unexpectedTitle, messages.unexpectedMessage);
+ }
+}
import api from '../api';
-import { CancelToken } from 'axios';
+import { CancelToken, isCancel } from 'axios';
import { throttle } from 'lodash';
import { search as emojiSearch } from '../features/emoji/emoji_mart_search_light';
import { tagHistory } from '../settings';
import { useEmoji } from './emojis';
import { importFetchedAccounts } from './importer';
import { updateTimeline } from './timelines';
+import { showAlertForError } from './alerts';
let cancelFetchComposeSuggestionsAccounts;
}).then(response => {
dispatch(importFetchedAccounts(response.data));
dispatch(readyComposeSuggestionsAccounts(token, response.data));
+ }).catch(error => {
+ if (!isCancel(error)) {
+ dispatch(showAlertForError(error));
+ }
});
}, 200, { leading: true, trailing: true });
import api from '../api';
import { importFetchedAccounts } from './importer';
+import { showAlertForError } from './alerts';
export const LIST_FETCH_REQUEST = 'LIST_FETCH_REQUEST';
export const LIST_FETCH_SUCCESS = 'LIST_FETCH_SUCCESS';
api(getState).get('/api/v1/accounts/search', { params }).then(({ data }) => {
dispatch(importFetchedAccounts(data));
dispatch(fetchListSuggestionsReady(q, data));
- });
+ }).catch(error => dispatch(showAlertForError(error)));
};
export const fetchListSuggestionsReady = (query, accounts) => ({
pushNotificationsSetting.remove(me);
}
- try {
- getRegistration()
- .then(getPushSubscription)
- .then(unsubscribe);
- } catch (e) {
-
- }
- });
+ return getRegistration()
+ .then(getPushSubscription)
+ .then(unsubscribe);
+ })
+ .catch(console.warn);
} else {
console.warn('Your browser does not support Web Push Notifications.');
}
if (me) {
pushNotificationsSetting.set(me, data);
}
- });
+ }).catch(console.warn);
};
}
import api from '../api';
import { debounce } from 'lodash';
+import { showAlertForError } from './alerts';
export const SETTING_CHANGE = 'SETTING_CHANGE';
export const SETTING_SAVE = 'SETTING_SAVE';
const data = getState().get('settings').filter((_, path) => path !== 'saved').toJS();
- api(getState).put('/api/web/settings', { data }).then(() => dispatch({ type: SETTING_SAVE }));
+ api(getState).put('/api/web/settings', { data })
+ .then(() => dispatch({ type: SETTING_SAVE }))
+ .catch(error => dispatch(showAlertForError(error)));
}, 5000, { trailing: true });
export function saveSettings() {
import { openModal } from '../actions/modal';
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
import { boostModal, deleteModal } from '../initial_state';
+import { showAlertForError } from '../actions/alerts';
const messages = defineMessages({
deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
},
onEmbed (status) {
- dispatch(openModal('EMBED', { url: status.get('url') }));
+ dispatch(openModal('EMBED', {
+ url: status.get('url'),
+ onError: error => dispatch(showAlertForError(error)),
+ }));
},
onDelete (status) {
static propTypes = {
url: PropTypes.string.isRequired,
onClose: PropTypes.func.isRequired,
+ onError: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired,
}
iframeDocument.body.style.margin = 0;
this.iframe.width = iframeDocument.body.scrollWidth;
this.iframe.height = iframeDocument.body.scrollHeight;
+ }).catch(error => {
+ this.props.onError(error);
});
}
-import { defineMessages } from 'react-intl';
-import { showAlert } from '../actions/alerts';
+import { showAlertForError } from '../actions/alerts';
const defaultFailSuffix = 'FAIL';
-const messages = defineMessages({
- unexpectedTitle: { id: 'alert.unexpected.title', defaultMessage: 'Oops!' },
- unexpectedMessage: { id: 'alert.unexpected.message', defaultMessage: 'An unexpected error occurred.' },
-});
-
export default function errorsMiddleware() {
return ({ dispatch }) => next => action => {
if (action.type && !action.skipAlert) {
const isFail = new RegExp(`${defaultFailSuffix}$`, 'g');
if (action.type.match(isFail)) {
- if (action.error.response) {
- const { data, status, statusText } = action.error.response;
-
- let message = statusText;
- let title = `${status}`;
-
- if (data.error) {
- message = data.error;
- }
-
- dispatch(showAlert(title, message));
- } else {
- console.error(action.error);
- dispatch(showAlert(messages.unexpectedTitle, messages.unexpectedMessage));
- }
+ dispatch(showAlertForError(action.error));
}
}
// https://webkit.org/status/#specification-service-workers
const asyncCache = window.caches ? caches.open('mastodon-system') : Promise.reject();
+function printErrorIfAvailable(error) {
+ if (error) {
+ console.warn(error);
+ }
+}
+
function put(name, objects, onupdate, oncreate) {
return asyncDB.then(db => new Promise((resolve, reject) => {
const putTransaction = db.transaction(name, 'readwrite');
function evict(toEvict) {
toEvict.forEach(record => {
- asyncCache.then(cache => accountAssetKeys.forEach(key => cache.delete(records[key])));
+ asyncCache
+ .then(cache => accountAssetKeys.forEach(key => cache.delete(records[key])))
+ .catch(printErrorIfAvailable);
accountsMovedIndex.getAll(record.id).onsuccess = ({ target }) => evict(target.result);
}
evict(records);
- });
+ }).catch(printErrorIfAvailable);
}
export function evictStatus(id) {
- return evictStatuses([id]);
+ evictStatuses([id]);
}
export function evictStatuses(ids) {
idIndex.getKey(id).onsuccess =
({ target }) => target.result && store.delete(target.result);
});
- });
+ }).catch(printErrorIfAvailable);
}
function evictStatusesByRecords(records) {
const oldURL = target.result[key];
if (newURL !== oldURL) {
- asyncCache.then(cache => cache.delete(oldURL));
+ asyncCache
+ .then(cache => cache.delete(oldURL))
+ .catch(printErrorIfAvailable);
}
});
oncomplete();
}).then(records => {
evictAccountsByRecords(records);
- asyncCache.then(cache => cache.addAll(newURLs));
- });
+ asyncCache
+ .then(cache => cache.addAll(newURLs))
+ .catch(printErrorIfAvailable);
+ }).catch(printErrorIfAvailable);
}
export function putStatuses(records) {
- put('statuses', records).then(evictStatusesByRecords);
+ put('statuses', records)
+ .then(evictStatusesByRecords)
+ .catch(printErrorIfAvailable);
}
"eslint": "^4.15.0",
"eslint-plugin-import": "^2.8.0",
"eslint-plugin-jsx-a11y": "^5.1.1",
+ "eslint-plugin-promise": "^3.7.0",
"eslint-plugin-react": "^7.5.1",
"jest": "^21.2.1",
"raf": "^3.4.0",
emoji-regex "^6.1.0"
jsx-ast-utils "^1.4.0"
+eslint-plugin-promise@^3.7.0:
+ version "3.7.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.7.0.tgz#f4bde5c2c77cdd69557a8f69a24d1ad3cfc9e67e"
+
eslint-plugin-react@^7.5.1:
version "7.5.1"
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.5.1.tgz#52e56e8d80c810de158859ef07b880d2f56ee30b"