withQuery and withMutation support for notifyOnError (default: true)

This commit is contained in:
Chi Vinh Le
2018-01-23 19:05:08 +01:00
parent 303e2e84c5
commit 0523faee2b
16 changed files with 133 additions and 139 deletions
-2
View File
@@ -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;
+37 -6
View File
@@ -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);
};
+40 -6
View File
@@ -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);
};