Get rid of data direct dependency in the plugins

This commit is contained in:
Chi Vinh Le
2018-03-13 19:58:32 +01:00
parent 9ad92e38c0
commit 84f1003b2b
20 changed files with 172 additions and 39 deletions
+4
View File
@@ -14,6 +14,10 @@ export { default as withPopupAuthHandler } from './withPopupAuthHandler';
export { default as withEnumValues } from './withEnumValues';
export { default as withCombatPassthrough } from './withCombatPassthrough';
export { default as withSlotElements } from './withSlotElements';
export { default as withVariables } from './withVariables';
export { default as WithRefetch } from './withRefetch';
export { default as withFetchMore } from './withFetchMore';
export { default as withSubscribeToMore } from './withSubscribeToMore';
export {
default as withResendEmailConfirmation,
} from './withResendEmailConfirmation';
@@ -0,0 +1,27 @@
import React from 'react';
import hoistStatics from 'recompose/hoistStatics';
import { Subscriber } from 'react-broadcast';
import get from 'lodash/get';
/**
* WithFetchMore provides a property `fetchMore` to the wrapped component.
* Calling `fetchMore` is the same as calling `data.fetchMore` from the
* Apollo React API.
*/
export default hoistStatics(WrappedComponent => {
class WithFetchMore extends React.Component {
render() {
return (
<Subscriber channel="queryData">
{data => (
<WrappedComponent
{...this.props}
fetchMore={get(data, 'fetchMore')}
/>
)}
</Subscriber>
);
}
}
return WithFetchMore;
});
+18 -4
View File
@@ -11,6 +11,8 @@ import { getOperationName } from 'apollo-client/queries/getFromAST';
import throttle from 'lodash/throttle';
import get from 'lodash/get';
import { notify } from 'coral-framework/actions/notification';
import { Broadcast } from 'react-broadcast';
import { compose } from 'recompose';
const withSkipOnErrors = reducer => (prev, action, ...rest) => {
if (
@@ -71,6 +73,15 @@ function networkStatusToString(networkStatus) {
}
}
// When wrapped broadcast all data changes to channel "queryData".
const withBroadcaster = WrappedComponent => props => (
/* eslint-disable react/prop-types */
<Broadcast channel="queryData" value={props.data}>
<WrappedComponent {...props} />
</Broadcast>
/* eslint-enable react/prop-types */
);
const createHOC = (document, config, { notifyOnError = true }) =>
hoistStatics(WrappedComponent => {
return class WithQuery extends React.Component {
@@ -357,10 +368,13 @@ const createHOC = (document, config, { notifyOnError = true }) =>
if (!this.memoized) {
this.resolvedDocument = this.resolveDocument(document);
this.name = getDefinitionName(this.resolvedDocument);
this.memoized = graphql(this.resolvedDocument, {
...this.wrappedConfig,
options: this.wrappedOptions,
})(WrappedComponent);
this.memoized = compose(
graphql(this.resolvedDocument, {
...this.wrappedConfig,
options: this.wrappedOptions,
}),
withBroadcaster
)(WrappedComponent);
}
return this.memoized;
};
@@ -0,0 +1,23 @@
import React from 'react';
import hoistStatics from 'recompose/hoistStatics';
import { Subscriber } from 'react-broadcast';
import get from 'lodash/get';
/**
* WithRefetch provides a property `refetch` to the wrapped component.
* Calling refetch will perform a refetch of the parent Query.
*/
export default hoistStatics(WrappedComponent => {
class WithRefetch extends React.Component {
render() {
return (
<Subscriber channel="queryData">
{data => (
<WrappedComponent {...this.props} refetch={get(data, 'refetch')} />
)}
</Subscriber>
);
}
}
return WithRefetch;
});
@@ -0,0 +1,27 @@
import React from 'react';
import hoistStatics from 'recompose/hoistStatics';
import { Subscriber } from 'react-broadcast';
import get from 'lodash/get';
/**
* WithSubscribeToMore provides a property `subscribeToMore` to the wrapped component.
* Calling `subscribeToMore` is the same as calling `data.subscribeToMore` from the
* Apollo React API.
*/
export default hoistStatics(WrappedComponent => {
class WithSubscribeToMore extends React.Component {
render() {
return (
<Subscriber channel="queryData">
{data => (
<WrappedComponent
{...this.props}
subscribeToMore={get(data, 'subscribeToMoreThrottled')}
/>
)}
</Subscriber>
);
}
}
return WithSubscribeToMore;
});
@@ -0,0 +1,26 @@
import React from 'react';
import hoistStatics from 'recompose/hoistStatics';
import { Subscriber } from 'react-broadcast';
import get from 'lodash/get';
/**
* WithVariables provides a property `variables` to the wrapped component.
* These are the variables of the parent Query.
*/
export default hoistStatics(WrappedComponent => {
class WithVariables extends React.Component {
render() {
return (
<Subscriber channel="queryData">
{data => (
<WrappedComponent
{...this.props}
variables={get(data, 'variables')}
/>
)}
</Subscriber>
);
}
}
return WithVariables;
});
+1
View File
@@ -159,6 +159,7 @@
"query-string": "^5.0.0",
"react": "^15.4.2",
"react-apollo": "^1.4.12",
"react-broadcast": "^0.6.2",
"react-dom": "^15.4.2",
"react-input-autosize": "^1.1.4",
"react-mdl": "^1.11.0",
+5
View File
@@ -13,6 +13,10 @@ export {
withResendEmailConfirmation,
withSetUsername,
withEnumValues,
withVariables,
withFetchMore,
withSubscribeToMore,
withRefetch,
} from 'coral-framework/hocs';
export {
withIgnoreUser,
@@ -21,3 +25,4 @@ export {
withStopIgnoringUser,
withSetCommentStatus,
} from 'coral-framework/graphql/mutations';
export { compose } from 'recompose';
@@ -49,7 +49,6 @@ class AuthorNameContainer extends React.Component {
render() {
const {
data,
root,
asset,
comment,
@@ -57,7 +56,7 @@ class AuthorNameContainer extends React.Component {
showMenuForComment,
} = this.props;
const slotPassthrough = { data, root, asset, comment };
const slotPassthrough = { root, asset, comment };
return (
<AuthorName
@@ -73,7 +72,6 @@ class AuthorNameContainer extends React.Component {
}
AuthorNameContainer.propTypes = {
data: PropTypes.object.isRequired,
root: PropTypes.object.isRequired,
asset: PropTypes.object.isRequired,
comment: PropTypes.object.isRequired,
@@ -18,8 +18,8 @@ class Comment extends React.Component {
};
render() {
const { comment, asset, root, data } = this.props;
const slotPassthrough = { data, comment, asset, root };
const { comment, asset, root } = this.props;
const slotPassthrough = { comment, asset, root };
return (
<div className={cn(styles.root, `${pluginName}-comment`)}>
<Slot
@@ -62,12 +62,7 @@ class Comment extends React.Component {
inline
/>
<FeaturedButton
root={root}
data={data}
comment={comment}
asset={asset}
/>
<FeaturedButton root={root} comment={comment} asset={asset} />
</div>
<div
className={cn(
@@ -22,7 +22,6 @@ class TabPane extends React.Component {
render() {
const {
root,
data,
asset: { featuredComments, ...asset },
viewComment,
} = this.props;
@@ -32,7 +31,6 @@ class TabPane extends React.Component {
<Comment
key={comment.id}
root={root}
data={data}
comment={comment}
asset={asset}
viewComment={viewComment}
@@ -1,6 +1,7 @@
import React from 'react';
import { gql } from 'react-apollo';
import { subscriptionFields } from 'coral-admin/src/routes/Moderation/graphql';
import { compose, withSubscribeToMore } from 'plugin-api/beta/client/hocs';
class ModIndicatorSubscription extends React.Component {
subscriptions = null;
@@ -27,7 +28,7 @@ class ModIndicatorSubscription extends React.Component {
},
];
this.subscriptions = configs.map(config =>
this.props.data.subscribeToMore(config)
this.props.subscribeToMore(config)
);
}
@@ -60,4 +61,4 @@ const COMMENT_UNFEATURED_SUBSCRIPTION = gql`
}
`;
export default ModIndicatorSubscription;
export default compose(withSubscribeToMore)(ModIndicatorSubscription);
@@ -6,6 +6,11 @@ import { getDefinitionName } from 'coral-framework/utils';
import truncate from 'lodash/truncate';
import t from 'coral-framework/services/i18n';
import { subscriptionFields } from 'coral-admin/src/routes/Moderation/graphql';
import {
compose,
withSubscribeToMore,
withVariables,
} from 'plugin-api/beta/client/hocs';
function prepareNotificationText(text) {
return truncate(text, { length: 50 }).replace('\n', ' ');
@@ -19,7 +24,7 @@ class ModSubscription extends React.Component {
{
document: COMMENT_FEATURED_SUBSCRIPTION,
variables: {
assetId: this.props.data.variables.asset_id,
assetId: this.props.variables.asset_id,
},
updateQuery: (
prev,
@@ -39,7 +44,7 @@ class ModSubscription extends React.Component {
{
document: COMMENT_UNFEATURED_SUBSCRIPTION,
variables: {
assetId: this.props.data.variables.asset_id,
assetId: this.props.variables.asset_id,
},
updateQuery: (
prev,
@@ -62,7 +67,7 @@ class ModSubscription extends React.Component {
},
];
this.subscriptions = configs.map(config =>
this.props.data.subscribeToMore(config)
this.props.subscribeToMore(config)
);
}
@@ -111,4 +116,8 @@ const mapStateToProps = state => ({
user: state.auth.user,
});
export default connect(mapStateToProps, null)(ModSubscription);
export default compose(
connect(mapStateToProps, null),
withVariables,
withSubscribeToMore
)(ModSubscription);
@@ -2,7 +2,12 @@ import React from 'react';
import { bindActionCreators } from 'redux';
import { compose, gql } from 'react-apollo';
import TabPane from '../components/TabPane';
import { withFragments, connect } from 'plugin-api/beta/client/hocs';
import {
withFragments,
connect,
withFetchMore,
withVariables,
} from 'plugin-api/beta/client/hocs';
import Comment from '../containers/Comment';
import { viewComment } from 'coral-embed-stream/src/actions/stream';
import {
@@ -13,15 +18,15 @@ import update from 'immutability-helper';
class TabPaneContainer extends React.Component {
loadMore = () => {
return this.props.data.fetchMore({
return this.props.fetchMore({
query: LOAD_MORE_QUERY,
variables: {
limit: 5,
cursor: this.props.asset.featuredComments.endCursor,
asset_id: this.props.asset.id,
sortOrder: this.props.data.variables.sortOrder,
sortBy: this.props.data.variables.sortBy,
excludeIgnored: this.props.data.variables.excludeIgnored,
sortOrder: this.props.variables.sortOrder,
sortBy: this.props.variables.sortBy,
excludeIgnored: this.props.variables.excludeIgnored,
},
updateQuery: (previous, { fetchMoreResult: { comments } }) => {
const updated = update(previous, {
@@ -86,6 +91,8 @@ const mapDispatchToProps = dispatch =>
const enhance = compose(
connect(null, mapDispatchToProps),
withFetchMore,
withVariables,
withFragments({
root: gql`
fragment TalkFeaturedComments_TabPane_root on RootQuery {
@@ -10,7 +10,7 @@ import {
class FlagDetails extends Component {
render() {
const { comment: { actions }, more, data, root, comment } = this.props;
const { comment: { actions }, more, root, comment } = this.props;
const flagActions =
actions && actions.filter(a => a.__typename === 'FlagAction');
@@ -27,7 +27,6 @@ class FlagDetails extends Component {
const reasons = Object.keys(summaries);
const slotPassthrough = {
data,
root,
comment,
};
@@ -68,7 +67,6 @@ class FlagDetails extends Component {
FlagDetails.propTypes = {
more: PropTypes.bool,
data: PropTypes.object,
root: PropTypes.object,
comment: PropTypes.shape({
actions: PropTypes.arrayOf(
@@ -16,7 +16,6 @@ export default class ModerationActions extends React.Component {
comment,
root,
asset,
data,
menuVisible,
toogleMenu,
hideMenu,
@@ -25,7 +24,6 @@ export default class ModerationActions extends React.Component {
const slotPassthrough = {
comment,
asset,
data,
};
return (
@@ -72,7 +70,6 @@ ModerationActions.propTypes = {
comment: PropTypes.object,
root: PropTypes.object,
asset: PropTypes.object,
data: PropTypes.object,
menuVisible: PropTypes.bool,
toogleMenu: PropTypes.func,
hideMenu: PropTypes.func,
@@ -42,7 +42,6 @@ class ModerationActionsContainer extends React.Component {
render() {
return (
<ModerationActions
data={this.props.data}
root={this.props.root}
asset={this.props.asset}
comment={this.props.comment}
@@ -50,7 +50,6 @@ class SettingsContainer extends React.Component {
render() {
return (
<Settings
data={this.props.data}
root={this.props.root}
indicateOn={this.indicateOn}
indicateOff={this.indicateOff}
@@ -72,7 +71,6 @@ class SettingsContainer extends React.Component {
}
SettingsContainer.propTypes = {
data: PropTypes.object,
root: PropTypes.object,
updateNotificationSettings: PropTypes.func.isRequired,
digestFrequencyValues: PropTypes.array.isRequired,
@@ -31,9 +31,8 @@ const withViewingOptionsFragments = withFragments({
const enhance = compose(
connect(mapStateToProps, mapDispatchToProps),
withViewingOptionsFragments,
mapProps(({ root, asset, data, ...rest }) => ({
mapProps(({ root, asset, ...rest }) => ({
slotPassthrough: {
data,
root,
asset,
},
+7
View File
@@ -8677,6 +8677,13 @@ react-apollo@^1.4.12:
object-assign "^4.0.1"
prop-types "^15.5.8"
react-broadcast@^0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/react-broadcast/-/react-broadcast-0.6.2.tgz#9555c73b80ca5b2673830872e54f6bb3092cf8a9"
dependencies:
invariant "^2.2.1"
prop-types "^15.6.0"
react-dom@>=0.14.0:
version "16.2.0"
resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.2.0.tgz#69003178601c0ca19b709b33a83369fe6124c044"