mirror of
https://github.com/wassname/talk.git
synced 2026-06-29 07:24:53 +08:00
withQuery and withMutation support for notifyOnError (default: true)
This commit is contained in:
@@ -10,7 +10,6 @@ import {
|
||||
} from 'coral-framework/graphql/mutations';
|
||||
import { compose } from 'react-apollo';
|
||||
import t from 'coral-framework/services/i18n';
|
||||
import { getErrorMessages } from 'coral-framework/utils';
|
||||
import { notify } from 'coral-framework/actions/notification';
|
||||
|
||||
class BanUserDialogContainer extends Component {
|
||||
@@ -22,16 +21,11 @@ class BanUserDialogContainer extends Component {
|
||||
banUser,
|
||||
setCommentStatus,
|
||||
hideBanUserDialog,
|
||||
notify,
|
||||
} = this.props;
|
||||
try {
|
||||
await banUser({ id: userId, message: '' });
|
||||
hideBanUserDialog();
|
||||
if (commentId && commentStatus && commentStatus !== 'REJECTED') {
|
||||
await setCommentStatus({ commentId, status: 'REJECTED' });
|
||||
}
|
||||
} catch (err) {
|
||||
notify('error', getErrorMessages(err));
|
||||
await banUser({ id: userId, message: '' });
|
||||
hideBanUserDialog();
|
||||
if (commentId && commentStatus && commentStatus !== 'REJECTED') {
|
||||
await setCommentStatus({ commentId, status: 'REJECTED' });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -85,7 +79,7 @@ const mapDispatchToProps = dispatch => ({
|
||||
});
|
||||
|
||||
export default compose(
|
||||
connect(mapStateToProps, mapDispatchToProps),
|
||||
withBanUser,
|
||||
withSetCommentStatus,
|
||||
connect(mapStateToProps, mapDispatchToProps)
|
||||
withSetCommentStatus
|
||||
)(BanUserDialogContainer);
|
||||
|
||||
@@ -11,7 +11,6 @@ import {
|
||||
import { compose, gql } from 'react-apollo';
|
||||
import t, { timeago } from 'coral-framework/services/i18n';
|
||||
import withQuery from 'coral-framework/hocs/withQuery';
|
||||
import { getErrorMessages } from 'coral-framework/utils';
|
||||
import get from 'lodash/get';
|
||||
import { notify } from 'coral-framework/actions/notification';
|
||||
|
||||
@@ -28,17 +27,13 @@ class SuspendUserDialogContainer extends Component {
|
||||
notify,
|
||||
} = this.props;
|
||||
hideSuspendUserDialog();
|
||||
try {
|
||||
await suspendUser({ id: userId, message, until });
|
||||
notify(
|
||||
'success',
|
||||
t('suspenduser.notify_suspend_until', username, timeago(until))
|
||||
);
|
||||
if (commentId && commentStatus && commentStatus !== 'REJECTED') {
|
||||
await setCommentStatus({ commentId, status: 'REJECTED' });
|
||||
}
|
||||
} catch (err) {
|
||||
notify('error', getErrorMessages(err));
|
||||
await suspendUser({ id: userId, message, until });
|
||||
notify(
|
||||
'success',
|
||||
t('suspenduser.notify_suspend_until', username, timeago(until))
|
||||
);
|
||||
if (commentId && commentStatus && commentStatus !== 'REJECTED') {
|
||||
await setCommentStatus({ commentId, status: 'REJECTED' });
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ import UserDetailComment from './UserDetailComment';
|
||||
import update from 'immutability-helper';
|
||||
import { showBanUserDialog } from 'actions/banUserDialog';
|
||||
import { showSuspendUserDialog } from 'actions/suspendUserDialog';
|
||||
import { notifyOnMutationError, notifyOnDataError } from 'coral-framework/hocs';
|
||||
import { notify } from 'coral-framework/actions/notification';
|
||||
|
||||
const commentConnectionFragment = gql`
|
||||
fragment CoralAdmin_UserDetail_CommentConnection on CommentConnection {
|
||||
@@ -272,6 +272,7 @@ const mapDispatchToProps = dispatch => ({
|
||||
viewUserDetail,
|
||||
hideUserDetail,
|
||||
toggleSelectAllCommentInUserDetail,
|
||||
notify,
|
||||
},
|
||||
dispatch
|
||||
),
|
||||
@@ -282,7 +283,5 @@ export default compose(
|
||||
withUserDetailQuery,
|
||||
withSetCommentStatus,
|
||||
withUnbanUser,
|
||||
withUnsuspendUser,
|
||||
notifyOnMutationError(['unbanUser', 'unsuspendUser', 'setCommentStatus']),
|
||||
notifyOnDataError
|
||||
withUnsuspendUser
|
||||
)(UserDetailContainer);
|
||||
|
||||
@@ -15,7 +15,6 @@ import { handleFlaggedUsernameChange } from '../graphql';
|
||||
import { notify } from 'coral-framework/actions/notification';
|
||||
import { isFlaggedUserDangling } from '../utils';
|
||||
import t from 'coral-framework/services/i18n';
|
||||
import { notifyOnMutationError, notifyOnDataError } from 'coral-framework/hocs';
|
||||
|
||||
import FlaggedAccounts from '../components/FlaggedAccounts';
|
||||
import FlaggedUser from '../containers/FlaggedUser';
|
||||
@@ -295,7 +294,6 @@ const mapDispatchToProps = dispatch =>
|
||||
export default compose(
|
||||
connect(null, mapDispatchToProps),
|
||||
withApproveUsername,
|
||||
notifyOnMutationError(['approveUsername']),
|
||||
withQuery(
|
||||
gql`
|
||||
query TalkAdmin_Community_FlaggedAccounts {
|
||||
@@ -334,6 +332,5 @@ export default compose(
|
||||
fetchPolicy: 'network-only',
|
||||
},
|
||||
}
|
||||
),
|
||||
notifyOnDataError
|
||||
)
|
||||
)(FlaggedAccountsContainer);
|
||||
|
||||
@@ -16,7 +16,7 @@ import { appendNewNodes } from 'plugin-api/beta/client/utils';
|
||||
import update from 'immutability-helper';
|
||||
import { Spinner } from 'coral-ui';
|
||||
import withQuery from 'coral-framework/hocs/withQuery';
|
||||
import { notifyOnMutationError, notifyOnDataError } from 'coral-framework/hocs';
|
||||
import { notify } from 'coral-framework/actions/notification';
|
||||
|
||||
class PeopleContainer extends React.Component {
|
||||
timer = null;
|
||||
@@ -132,6 +132,7 @@ const mapDispatchToProps = dispatch =>
|
||||
viewUserDetail,
|
||||
showSuspendUserDialog,
|
||||
showBanUserDialog,
|
||||
notify,
|
||||
},
|
||||
dispatch
|
||||
);
|
||||
@@ -205,7 +206,6 @@ export default compose(
|
||||
withSetUserRole,
|
||||
withUnsuspendUser,
|
||||
withUnbanUser,
|
||||
notifyOnMutationError(['setUserRole', 'unsuspendUser', 'unbanUser']),
|
||||
withQuery(
|
||||
gql`
|
||||
query TalkAdmin_Community_People {
|
||||
@@ -241,6 +241,5 @@ export default compose(
|
||||
fetchPolicy: 'network-only',
|
||||
},
|
||||
}
|
||||
),
|
||||
notifyOnDataError
|
||||
)
|
||||
)(PeopleContainer);
|
||||
|
||||
@@ -5,7 +5,6 @@ import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { compose } from 'react-apollo';
|
||||
import { notify } from 'coral-framework/actions/notification';
|
||||
import { notifyOnMutationError } from 'coral-framework/hocs';
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
user: state.community.user,
|
||||
@@ -23,6 +22,5 @@ const mapDispatchToProps = dispatch =>
|
||||
|
||||
export default compose(
|
||||
connect(mapStateToProps, mapDispatchToProps),
|
||||
withRejectUsername,
|
||||
notifyOnMutationError(['rejectUsername'])
|
||||
withRejectUsername
|
||||
)(RejectUsernameDialog);
|
||||
|
||||
@@ -12,7 +12,7 @@ import TechSettings from './TechSettings';
|
||||
import ModerationSettings from './ModerationSettings';
|
||||
import { clearPending, setActiveSection } from '../../../actions/configure';
|
||||
import Configure from '../components/Configure';
|
||||
import { notifyOnMutationError, notifyOnDataError } from 'coral-framework/hocs';
|
||||
import { notify } from 'coral-framework/actions/notification';
|
||||
|
||||
class ConfigureContainer extends Component {
|
||||
savePending = async () => {
|
||||
@@ -83,16 +83,15 @@ const mapDispatchToProps = dispatch =>
|
||||
{
|
||||
clearPending,
|
||||
setActiveSection,
|
||||
notify,
|
||||
},
|
||||
dispatch
|
||||
);
|
||||
|
||||
export default compose(
|
||||
withUpdateSettings,
|
||||
notifyOnMutationError(['updateSettings']),
|
||||
withConfigureQuery,
|
||||
notifyOnDataError,
|
||||
connect(mapStateToProps, mapDispatchToProps),
|
||||
withUpdateSettings,
|
||||
withConfigureQuery,
|
||||
withMergedSettings('root.settings', 'pending', 'mergedSettings')
|
||||
)(ConfigureContainer);
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ import { Spinner } from 'coral-ui';
|
||||
import Moderation from '../components/Moderation';
|
||||
import Comment from './Comment';
|
||||
import baseQueueConfig from '../queueConfig';
|
||||
import { notifyOnMutationError, notifyOnDataError } from 'coral-framework/hocs';
|
||||
|
||||
function prepareNotificationText(text) {
|
||||
return truncate(text, { length: 50 }).replace('\n', ' ');
|
||||
@@ -535,7 +534,5 @@ export default compose(
|
||||
withQueueConfig(baseQueueConfig),
|
||||
connect(mapStateToProps, mapDispatchToProps),
|
||||
withSetCommentStatus,
|
||||
notifyOnMutationError(['setCommentStatus']),
|
||||
withModQueueQuery,
|
||||
notifyOnDataError
|
||||
withModQueueQuery
|
||||
)(ModerationContainer);
|
||||
|
||||
@@ -7,7 +7,9 @@ import {
|
||||
withUpdateAssetStatus,
|
||||
withCloseAsset,
|
||||
} from 'coral-framework/graphql/mutations';
|
||||
import { notifyOnMutationError } from 'coral-framework/hocs';
|
||||
import { notify } from 'coral-framework/actions/notification';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
|
||||
class AssetStatusInfoContainer extends React.Component {
|
||||
openAsset = () =>
|
||||
@@ -43,11 +45,19 @@ const withAssetStatusInfoFragments = withFragments({
|
||||
`,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = dispatch =>
|
||||
bindActionCreators(
|
||||
{
|
||||
notify,
|
||||
},
|
||||
dispatch
|
||||
);
|
||||
|
||||
const enhance = compose(
|
||||
connect(null, mapDispatchToProps),
|
||||
withAssetStatusInfoFragments,
|
||||
withUpdateAssetStatus,
|
||||
withCloseAsset,
|
||||
notifyOnMutationError(['updateAssetStatus', 'closeAsset'])
|
||||
withCloseAsset
|
||||
);
|
||||
|
||||
export default enhance(AssetStatusInfoContainer);
|
||||
|
||||
@@ -8,7 +8,7 @@ import { withUpdateAssetSettings } from 'coral-framework/graphql/mutations';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { clearPending, updatePending } from '../../../actions/configure';
|
||||
import { notifyOnMutationError } from 'coral-framework/hocs';
|
||||
import { notify } from 'coral-framework/actions/notification';
|
||||
|
||||
const slots = ['streamSettings'];
|
||||
|
||||
@@ -129,15 +129,15 @@ const mapDispatchToProps = dispatch =>
|
||||
{
|
||||
clearPending,
|
||||
updatePending,
|
||||
notify,
|
||||
},
|
||||
dispatch
|
||||
);
|
||||
|
||||
const enhance = compose(
|
||||
connect(mapStateToProps, mapDispatchToProps),
|
||||
withSettingsFragments,
|
||||
withUpdateAssetSettings,
|
||||
notifyOnMutationError(['updateAssetSettings']),
|
||||
connect(mapStateToProps, mapDispatchToProps),
|
||||
withMergedSettings('asset.settings', 'pending', 'mergedSettings')
|
||||
);
|
||||
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
import { compose } from 'react-apollo';
|
||||
import { withChangeUsername } from 'coral-framework/graphql/mutations';
|
||||
import ChangeUsername from '../components/ChangeUsername';
|
||||
import { notify } from 'coral-framework/actions/notification';
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
|
||||
export default compose(withChangeUsername)(ChangeUsername);
|
||||
const mapDispatchToProps = dispatch =>
|
||||
bindActionCreators(
|
||||
{
|
||||
notify,
|
||||
},
|
||||
dispatch
|
||||
);
|
||||
|
||||
export default compose(connect(null, mapDispatchToProps), withChangeUsername)(
|
||||
ChangeUsername
|
||||
);
|
||||
|
||||
@@ -6,5 +6,3 @@ export { default as withEmit } from './withEmit';
|
||||
export { default as excludeIf } from './excludeIf';
|
||||
export { default as connect } from './connect';
|
||||
export { default as withMergedSettings } from './withMergedSettings';
|
||||
export { default as notifyOnMutationError } from './notifyOnMutationError';
|
||||
export { default as notifyOnDataError } from './notifyOnDataError';
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { notify } from 'coral-framework/actions/notification';
|
||||
import { branch, lifecycle, compose } from 'recompose';
|
||||
import { get } from 'lodash';
|
||||
|
||||
const notifyOnMutationError = compose(
|
||||
branch(
|
||||
({ notify }) => !notify,
|
||||
connect(null, dispatch =>
|
||||
bindActionCreators(
|
||||
{
|
||||
notify,
|
||||
},
|
||||
dispatch
|
||||
)
|
||||
)
|
||||
),
|
||||
lifecycle({
|
||||
componentWillReceiveProps(next) {
|
||||
if (
|
||||
get(next, 'data.error.message') &&
|
||||
get(this.props, 'data.error.message') !==
|
||||
get(next, 'data.error.message')
|
||||
) {
|
||||
return this.props.notify('error', next.data.error.message);
|
||||
}
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
export default notifyOnMutationError;
|
||||
@@ -1,38 +0,0 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { bindActionCreators } from 'redux';
|
||||
import { compose } from 'react-apollo';
|
||||
import { notify } from 'coral-framework/actions/notification';
|
||||
import { forEachError } from 'coral-framework/utils';
|
||||
import { withProps, branch } from 'recompose';
|
||||
|
||||
const notifyOnMutationError = keys =>
|
||||
compose(
|
||||
branch(
|
||||
({ notify }) => !notify,
|
||||
connect(null, dispatch =>
|
||||
bindActionCreators(
|
||||
{
|
||||
notify,
|
||||
},
|
||||
dispatch
|
||||
)
|
||||
)
|
||||
),
|
||||
withProps(ownProps =>
|
||||
keys.reduce((props, key) => {
|
||||
props[key] = async (...args) => {
|
||||
try {
|
||||
return await ownProps[key](...args);
|
||||
} catch (e) {
|
||||
forEachError(e, ({ msg }) => {
|
||||
ownProps.notify('error', msg);
|
||||
});
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
return props;
|
||||
}, {})
|
||||
)
|
||||
);
|
||||
|
||||
export default notifyOnMutationError;
|
||||
@@ -4,7 +4,11 @@ import merge from 'lodash/merge';
|
||||
import uniq from 'lodash/uniq';
|
||||
import flatten from 'lodash/flatten';
|
||||
import isEmpty from 'lodash/isEmpty';
|
||||
import { getDefinitionName, getResponseErrors } from '../utils';
|
||||
import {
|
||||
getDefinitionName,
|
||||
getResponseErrors,
|
||||
getErrorMessages,
|
||||
} from '../utils';
|
||||
import PropTypes from 'prop-types';
|
||||
import t from 'coral-framework/services/i18n';
|
||||
import hoistStatics from 'recompose/hoistStatics';
|
||||
@@ -27,11 +31,7 @@ class ResponseError {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports a HOC with the same signature as `graphql`, that will
|
||||
* apply mutation options registered in the graphRegistry.
|
||||
*/
|
||||
export default (document, config = {}) =>
|
||||
const createHOC = (document, config, { notifyOnError = true }) =>
|
||||
hoistStatics(WrappedComponent => {
|
||||
config = {
|
||||
...config,
|
||||
@@ -46,10 +46,25 @@ export default (document, config = {}) =>
|
||||
graphql: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
notify: PropTypes.func,
|
||||
};
|
||||
|
||||
get graphqlRegistry() {
|
||||
return this.context.graphql.registry;
|
||||
}
|
||||
|
||||
notifyErrors(messages) {
|
||||
if (this.props.notify) {
|
||||
this.props.notify('error', messages);
|
||||
} else {
|
||||
console.error(
|
||||
'`notifyOnError` is set to `true` but missing `notify` property'
|
||||
);
|
||||
console.error(messages);
|
||||
}
|
||||
}
|
||||
|
||||
resolveDocument(documentOrCallback) {
|
||||
return this.context.graphql.resolveDocument(
|
||||
documentOrCallback,
|
||||
@@ -165,6 +180,11 @@ export default (document, config = {}) =>
|
||||
variables,
|
||||
error,
|
||||
});
|
||||
|
||||
// Show errors as notifications.
|
||||
if (notifyOnError) {
|
||||
this.notifyErrors(getErrorMessages(error));
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
};
|
||||
@@ -213,3 +233,14 @@ export default (document, config = {}) =>
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Exports a HOC with the same signature as `graphql`, that will
|
||||
* apply mutation options registered in the graphRegistry.
|
||||
*/
|
||||
export default (document, config = {}) => settingsOrComponent => {
|
||||
if (typeof settingsOrComponent === 'function') {
|
||||
return createHOC(document, config, {})(settingsOrComponent);
|
||||
}
|
||||
return createHOC(document, config, settingsOrComponent);
|
||||
};
|
||||
|
||||
@@ -9,6 +9,7 @@ import PropTypes from 'prop-types';
|
||||
import hoistStatics from 'recompose/hoistStatics';
|
||||
import { getOperationName } from 'apollo-client/queries/getFromAST';
|
||||
import throttle from 'lodash/throttle';
|
||||
import get from 'lodash/get';
|
||||
|
||||
const withSkipOnErrors = reducer => (prev, action, ...rest) => {
|
||||
if (
|
||||
@@ -36,15 +37,12 @@ function networkStatusToString(networkStatus) {
|
||||
return 'ready';
|
||||
case 8:
|
||||
return 'error';
|
||||
default:
|
||||
throw new Error(`Unknown network status ${networkStatus}`);
|
||||
}
|
||||
throw new Error(`Unknown network status ${networkStatus}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports a HOC with the same signature as `graphql`, that will
|
||||
* apply query options registered in the graphRegistry.
|
||||
*/
|
||||
export default (document, config = {}) =>
|
||||
const createHOC = (document, config, { notifyOnError = true }) =>
|
||||
hoistStatics(WrappedComponent => {
|
||||
return class WithQuery extends React.Component {
|
||||
static contextTypes = {
|
||||
@@ -53,6 +51,10 @@ export default (document, config = {}) =>
|
||||
client: PropTypes.object,
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
notify: PropTypes.func,
|
||||
};
|
||||
|
||||
// Lazily resolve fragments from graphRegistry to support circular dependencies.
|
||||
memoized = null;
|
||||
resolvedDocument = null;
|
||||
@@ -166,10 +168,31 @@ export default (document, config = {}) =>
|
||||
return () => this.client.networkInterface.unsubscribe(id);
|
||||
};
|
||||
|
||||
notifyErrors(messages) {
|
||||
if (this.props.notify) {
|
||||
this.props.notify('error', messages);
|
||||
} else {
|
||||
console.error(
|
||||
'`notifyOnError` is set to `true` but missing `notify` property'
|
||||
);
|
||||
console.error(messages);
|
||||
}
|
||||
}
|
||||
|
||||
nextData(data) {
|
||||
this.apolloData = data;
|
||||
this.emitWhenNeeded(data);
|
||||
|
||||
if (
|
||||
get(data, 'error.message') &&
|
||||
get(this, 'data.error.message') !== get(data, 'error.message')
|
||||
) {
|
||||
// Show errors as notifications.
|
||||
if (notifyOnError) {
|
||||
this.notifyErrors(data.error.message);
|
||||
}
|
||||
}
|
||||
|
||||
// If data was previously set, we update it in a immutable way.
|
||||
if (this.data) {
|
||||
if (this.data.loading && !data.loading) {
|
||||
@@ -319,3 +342,14 @@ export default (document, config = {}) =>
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
/**
|
||||
* Exports a HOC with the same signature as `graphql`, that will
|
||||
* apply query options registered in the graphRegistry.
|
||||
*/
|
||||
export default (document, config = {}) => settingsOrComponent => {
|
||||
if (typeof settingsOrComponent === 'function') {
|
||||
return createHOC(document, config, {})(settingsOrComponent);
|
||||
}
|
||||
return createHOC(document, config, settingsOrComponent);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user