Move query logic to containers

This commit is contained in:
Chi Vinh Le
2017-05-24 19:04:05 +07:00
parent 3cde313ab4
commit c35ce979f5
22 changed files with 322 additions and 344 deletions
@@ -27,3 +27,9 @@ export const hideShortcutsNote = () => {
export const viewUserDetail = (userId) => ({type: actions.VIEW_USER_DETAIL, userId});
export const hideUserDetail = () => ({type: actions.HIDE_USER_DETAIL});
export const setSortOrder = (order) => ({
type: actions.SET_SORT_ORDER,
order
});
@@ -7,3 +7,4 @@ export const SHOW_SUSPEND_USER_DIALOG = 'SHOW_SUSPEND_USER_DIALOG';
export const HIDE_SUSPEND_USER_DIALOG = 'HIDE_SUSPEND_USER_DIALOG';
export const VIEW_USER_DETAIL = 'VIEW_USER_DETAIL';
export const HIDE_USER_DETAIL = 'HIDE_USER_DETAIL';
export const SET_SORT_ORDER = 'MODERATION_SET_SORT_ORDER';
@@ -1,12 +0,0 @@
fragment metrics on Asset {
id
title
url
author
created_at
commentCount
action_summaries {
actionCount
actionableItemCount
}
}
@@ -1,31 +0,0 @@
fragment commentView on Comment {
id
body
created_at
status
user {
id
name: username
status
}
asset {
id
title
url
}
action_summaries {
count
... on FlagActionSummary {
reason
}
}
actions {
... on FlagAction {
reason
message
user {
username
}
}
}
}
@@ -1,6 +0,0 @@
query Assets {
assets {
id
title
}
}
@@ -1,22 +0,0 @@
query Counts ($asset_id: ID) {
allCount: commentCount(query: {
asset_id: $asset_id
})
acceptedCount: commentCount(query: {
statuses: [ACCEPTED],
asset_id: $asset_id
})
premodCount: commentCount(query: {
statuses: [PREMOD],
asset_id: $asset_id
})
rejectedCount: commentCount(query: {
statuses: [REJECTED],
asset_id: $asset_id
})
flaggedCount: commentCount(query: {
action_type: FLAG,
asset_id: $asset_id,
statuses: [NONE, PREMOD]
})
}
@@ -1,116 +0,0 @@
import {graphql} from 'react-apollo';
import MOD_QUEUE_QUERY from './modQueueQuery.graphql';
import MOD_QUEUE_LOAD_MORE from './loadMore.graphql';
import MOD_USER_FLAGGED_QUERY from './modUserFlaggedQuery.graphql';
import METRICS from './metricsQuery.graphql';
import USER_DETAIL from './userDetail.graphql';
import GET_QUEUE_COUNTS from './getQueueCounts.graphql';
export const modQueueQuery = graphql(MOD_QUEUE_QUERY, {
options: ({params: {id = null}}) => {
return {
variables: {
asset_id: id,
sort: 'REVERSE_CHRONOLOGICAL'
}
};
},
props: ({ownProps: {params: {id = null}}, data}) => ({
data,
modQueueResort: modQueueResort(id, data.fetchMore),
loadMore: loadMore(data.fetchMore)
})
});
export const getMetrics = graphql(METRICS, {
options: ({settings: {dashboardWindowStart, dashboardWindowEnd}}) => {
return {
variables: {
from: dashboardWindowStart,
to: dashboardWindowEnd
}
};
}
});
export const loadMore = (fetchMore) => ({limit = 10, cursor, sort, tab, asset_id}) => {
let variables = {
limit,
cursor,
sort,
asset_id
};
switch(tab) {
case 'all':
variables.statuses = null;
break;
case 'accepted':
variables.statuses = ['ACCEPTED'];
break;
case 'premod':
variables.statuses = ['PREMOD'];
break;
case 'flagged':
variables.statuses = ['NONE', 'PREMOD'];
variables.action_type = 'FLAG';
break;
case 'rejected':
variables.statuses = ['REJECTED'];
break;
}
return fetchMore({
query: MOD_QUEUE_LOAD_MORE,
variables,
updateQuery: (oldData, {fetchMoreResult:{comments}}) => {
return {
...oldData,
[tab]: [
...oldData[tab],
...comments
]
};
}
});
};
export const modUserFlaggedQuery = graphql(MOD_USER_FLAGGED_QUERY, {
options: ({params: {action_type = 'FLAG'}}) => {
return {
variables: {
action_type: action_type
}
};
}
});
export const modQueueResort = (id, fetchMore) => (sort) => {
return fetchMore({
query: MOD_QUEUE_QUERY,
variables: {
asset_id: id,
sort
},
updateQuery: (oldData, {fetchMoreResult:{data}}) => data
});
};
export const getUserDetail = graphql(USER_DETAIL, {
options: ({id}) => {
return {
variables: {author_id: id}
};
}
});
export const getQueueCounts = graphql(GET_QUEUE_COUNTS, {
options: ({params: {id = null}}) => {
return {
pollInterval: 5000,
variables: {
asset_id: id
}
};
}
});
@@ -1,13 +0,0 @@
#import "../fragments/commentView.graphql"
query LoadMoreModQueue($limit: Int = 10, $cursor: Date, $sort: SORT_ORDER, $asset_id: ID, $statuses:[COMMENT_STATUS!], $action_type: ACTION_TYPE) {
comments(query: {limit: $limit, cursor: $cursor, asset_id: $asset_id, statuses: $statuses, sort: $sort, action_type: $action_type}) {
...commentView
action_summaries {
count
... on FlagActionSummary {
reason
}
}
}
}
@@ -1,10 +0,0 @@
#import "../fragments/assetMetricsView.graphql"
query Metrics ($from: Date!, $to: Date!) {
assetsByFlag: assetMetrics(from: $from, to: $to, sort: FLAG) {
...metrics
}
assetsByActivity: assetMetrics(from: $from, to: $to, sort: ACTIVITY) {
...metrics
}
}
@@ -1,68 +0,0 @@
#import "../fragments/commentView.graphql"
query ModQueue ($asset_id: ID, $sort: SORT_ORDER) {
all: comments(query: {
statuses: [NONE, PREMOD, ACCEPTED, REJECTED],
asset_id: $asset_id,
sort: $sort
}) {
...commentView
}
accepted: comments(query: {
statuses: [ACCEPTED],
asset_id: $asset_id,
sort: $sort
}) {
...commentView
}
premod: comments(query: {
statuses: [PREMOD],
asset_id: $asset_id,
sort: $sort
}) {
...commentView
}
flagged: comments(query: {
action_type: FLAG,
asset_id: $asset_id,
statuses: [NONE, PREMOD],
sort: $sort
}) {
...commentView
}
rejected: comments(query: {
statuses: [REJECTED],
asset_id: $asset_id,
sort: $sort
}) {
...commentView
}
assets: assets {
id
title
url
}
allCount: commentCount(query: {
asset_id: $asset_id
})
acceptedCount: commentCount(query: {
statuses: [ACCEPTED],
asset_id: $asset_id
})
premodCount: commentCount(query: {
statuses: [PREMOD],
asset_id: $asset_id
})
rejectedCount: commentCount(query: {
statuses: [REJECTED],
asset_id: $asset_id
})
flaggedCount: commentCount(query: {
action_type: FLAG,
asset_id: $asset_id,
statuses: [NONE, PREMOD]
})
settings {
organizationName
}
}
@@ -1,26 +0,0 @@
query Users ($action_type: ACTION_TYPE) {
users (query:{action_type: $action_type}){
id
username
status
roles
actions{
id
created_at
... on FlagAction {
reason
message
user {
id
username
}
}
}
action_summaries {
count
... on FlagActionSummary {
reason
}
}
}
}
@@ -1,13 +0,0 @@
query UserDetail ($author_id: ID!) {
user(id: $author_id) {
id
username
created_at
profiles {
id
provider
}
}
totalComments: commentCount(query: {author_id: $author_id})
rejectedComments: commentCount(query: {author_id: $author_id, statuses: [REJECTED]})
}
@@ -10,6 +10,7 @@ const initialState = fromJS({
userDetailId: null,
banDialog: false,
shortcutsNoteVisible: window.localStorage.getItem('coral:shortcutsNote') || 'show',
sortOrder: 'REVERSE_CHRONOLOGICAL',
suspendUserDialog: {
show: false,
userId: null,
@@ -64,6 +65,8 @@ export default function moderation (state = initialState, action) {
return state.set('userDetailId', action.userId);
case actions.HIDE_USER_DETAIL:
return state.set('userDetailId', null);
case actions.SET_SORT_ORDER:
return state.set('sortOrder', action.order);
default :
return state;
}
@@ -1,9 +1,8 @@
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {compose} from 'react-apollo';
import {compose, graphql, gql} from 'react-apollo';
import {modUserFlaggedQuery} from 'coral-admin/src/graphql/queries';
import {banUser, setUserStatus, rejectUsername} from 'coral-admin/src/graphql/mutations';
import {
@@ -31,6 +30,43 @@ class CommunityContainer extends Component {
}
}
export const withQuery = graphql(gql`
query Users($action_type: ACTION_TYPE) {
users(query:{action_type: $action_type}){
id
username
status
roles
actions{
id
created_at
... on FlagAction {
reason
message
user {
id
username
}
}
}
action_summaries {
count
... on FlagActionSummary {
reason
}
}
}
}
`, {
options: ({params: {action_type = 'FLAG'}}) => {
return {
variables: {
action_type: action_type
}
};
}
});
const mapStateToProps = (state) => ({
community: state.community.toJS()
});
@@ -48,7 +84,7 @@ const mapDispatchToProps = (dispatch) =>
export default compose(
connect(mapStateToProps, mapDispatchToProps),
modUserFlaggedQuery,
withQuery,
banUser,
setUserStatus,
rejectUsername
@@ -1,8 +1,7 @@
import React from 'react';
import {compose} from 'react-apollo';
import {connect} from 'react-redux';
import {getMetrics} from 'coral-admin/src/graphql/queries';
import Dashboard from '../components/Dashboard';
import {compose, graphql, gql} from 'react-apollo';
import {Spinner} from 'coral-ui';
@@ -20,6 +19,38 @@ class DashboardContainer extends React.Component {
}
}
export const withQuery = graphql(gql`
query Metrics($from: Date!, $to: Date!) {
assetsByFlag: assetMetrics(from: $from, to: $to, sort: FLAG) {
...metrics
}
assetsByActivity: assetMetrics(from: $from, to: $to, sort: ACTIVITY) {
...metrics
}
}
fragment metrics on Asset {
id
title
url
author
created_at
commentCount
action_summaries {
actionCount
actionableItemCount
}
}
`, {
options: ({settings: {dashboardWindowStart, dashboardWindowEnd}}) => {
return {
variables: {
from: dashboardWindowStart,
to: dashboardWindowEnd
}
};
}
});
const mapStateToProps = (state) => {
return {
settings: state.settings.toJS(),
@@ -29,5 +60,5 @@ const mapStateToProps = (state) => {
export default compose(
connect(mapStateToProps),
getMetrics
withQuery,
)(DashboardContainer);
@@ -1 +1 @@
export {default} from './containers/InstallContainer.js';
export {default} from './containers/Install.js';
@@ -12,14 +12,13 @@ import ModerationMenu from './ModerationMenu';
import ModerationHeader from './ModerationHeader';
import NotFoundAsset from './NotFoundAsset';
import ModerationKeysModal from '../../../components/ModerationKeysModal';
import UserDetail from './UserDetail';
import UserDetail from '../containers/UserDetail';
const lang = new I18n(translations);
export default class Moderation extends Component {
state = {
selectedIndex: 0,
sort: 'REVERSE_CHRONOLOGICAL'
}
componentWillMount() {
@@ -76,11 +75,6 @@ export default class Moderation extends Component {
}
}
selectSort = (sort) => {
this.setState({sort});
this.props.modQueueResort(sort);
}
suspendUser = async (args) => {
this.props.hideSuspendUserDialog();
try {
@@ -174,8 +168,8 @@ export default class Moderation extends Component {
premodCount={data.premodCount}
rejectedCount={data.rejectedCount}
flaggedCount={data.flaggedCount}
selectSort={this.selectSort}
sort={this.state.sort}
selectSort={this.props.setSortOrder}
sort={this.props.moderation.sortOrder}
/>
<ModerationQueue
currentAsset={asset}
@@ -191,7 +185,7 @@ export default class Moderation extends Component {
rejectComment={props.rejectComment}
loadMore={props.loadMore}
assetId={providedAssetId}
sort={this.state.sort}
sort={this.props.moderation.sortOrder}
commentCount={activeTabCount}
currentUserId={this.props.auth.user.id}
viewUserDetail={viewUserDetail}
@@ -7,7 +7,7 @@ export default class UserDetail extends React.Component {
static propTypes = {
id: PropTypes.string.isRequired,
hideUserDetail: PropTypes.func.isRequired,
data: PropTypes.string.isRequired,
data: PropTypes.object.isRequired,
}
copyPermalink = () => {
@@ -1,10 +1,9 @@
import React, {Component} from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import {compose} from 'react-apollo';
import {compose, graphql, gql} from 'react-apollo';
import isEqual from 'lodash/isEqual';
import {modQueueQuery, getQueueCounts} from '../../../graphql/queries';
import {banUser, setCommentStatus, suspendUser} from '../../../graphql/mutations';
import {fetchSettings} from 'actions/settings';
@@ -18,7 +17,8 @@ import {
hideSuspendUserDialog,
hideShortcutsNote,
viewUserDetail,
hideUserDetail
hideUserDetail,
setSortOrder,
} from 'actions/moderation';
import {Spinner} from 'coral-ui';
@@ -36,6 +36,46 @@ class ModerationContainer extends Component {
}
}
loadMore = ({limit = 10, cursor, sort, tab, asset_id}) => {
let variables = {
limit,
cursor,
sort,
asset_id
};
switch(tab) {
case 'all':
variables.statuses = null;
break;
case 'accepted':
variables.statuses = ['ACCEPTED'];
break;
case 'premod':
variables.statuses = ['PREMOD'];
break;
case 'flagged':
variables.statuses = ['NONE', 'PREMOD'];
variables.action_type = 'FLAG';
break;
case 'rejected':
variables.statuses = ['REJECTED'];
break;
}
return this.props.data.fetchMore({
query: LOAD_MORE_QUERY,
variables,
updateQuery: (oldData, {fetchMoreResult:{comments}}) => {
return {
...oldData,
[tab]: [
...oldData[tab],
...comments
]
};
}
});
};
render () {
const {data} = this.props;
@@ -46,10 +86,172 @@ class ModerationContainer extends Component {
if (data.error) {
return <div>Error</div>;
}
return <Moderation {...this.props} />;
return <Moderation {...this.props} loadMore={this.loadMore} />;
}
}
const commentView = gql`
fragment commentView on Comment {
id
body
created_at
status
user {
id
name: username
status
}
asset {
id
title
url
}
action_summaries {
count
... on FlagActionSummary {
reason
}
}
actions {
... on FlagAction {
reason
message
user {
username
}
}
}
}
`;
const LOAD_MORE_QUERY = gql`
query LoadMoreModQueue($limit: Int = 10, $cursor: Date, $sort: SORT_ORDER, $asset_id: ID, $statuses:[COMMENT_STATUS!], $action_type: ACTION_TYPE) {
comments(query: {limit: $limit, cursor: $cursor, asset_id: $asset_id, statuses: $statuses, sort: $sort, action_type: $action_type}) {
...commentView
action_summaries {
count
... on FlagActionSummary {
reason
}
}
}
}
${commentView}
`;
const withQuery = graphql(gql`
query ModQueue($asset_id: ID, $sort: SORT_ORDER) {
all: comments(query: {
statuses: [NONE, PREMOD, ACCEPTED, REJECTED],
asset_id: $asset_id,
sort: $sort
}) {
...commentView
}
accepted: comments(query: {
statuses: [ACCEPTED],
asset_id: $asset_id,
sort: $sort
}) {
...commentView
}
premod: comments(query: {
statuses: [PREMOD],
asset_id: $asset_id,
sort: $sort
}) {
...commentView
}
flagged: comments(query: {
action_type: FLAG,
asset_id: $asset_id,
statuses: [NONE, PREMOD],
sort: $sort
}) {
...commentView
}
rejected: comments(query: {
statuses: [REJECTED],
asset_id: $asset_id,
sort: $sort
}) {
...commentView
}
assets: assets {
id
title
url
}
allCount: commentCount(query: {
asset_id: $asset_id
})
acceptedCount: commentCount(query: {
statuses: [ACCEPTED],
asset_id: $asset_id
})
premodCount: commentCount(query: {
statuses: [PREMOD],
asset_id: $asset_id
})
rejectedCount: commentCount(query: {
statuses: [REJECTED],
asset_id: $asset_id
})
flaggedCount: commentCount(query: {
action_type: FLAG,
asset_id: $asset_id,
statuses: [NONE, PREMOD]
})
settings {
organizationName
}
}
${commentView}
`, {
options: ({params: {id = null}, moderation: {sortOrder}}) => {
return {
variables: {
asset_id: id,
sort: sortOrder,
}
};
},
});
const withQueueCountPolling = graphql(gql`
query Counts($asset_id: ID) {
allCount: commentCount(query: {
asset_id: $asset_id
})
acceptedCount: commentCount(query: {
statuses: [ACCEPTED],
asset_id: $asset_id
})
premodCount: commentCount(query: {
statuses: [PREMOD],
asset_id: $asset_id
})
rejectedCount: commentCount(query: {
statuses: [REJECTED],
asset_id: $asset_id
})
flaggedCount: commentCount(query: {
action_type: FLAG,
asset_id: $asset_id,
statuses: [NONE, PREMOD]
})
}
`, {
options: ({params: {id = null}}) => {
return {
pollInterval: 5000,
variables: {
asset_id: id
}
};
}
});
const mapStateToProps = (state) => ({
moderation: state.moderation.toJS(),
settings: state.settings.toJS(),
@@ -70,14 +272,15 @@ const mapDispatchToProps = (dispatch) => ({
hideSuspendUserDialog,
viewUserDetail,
hideUserDetail,
setSortOrder,
}, dispatch),
});
export default compose(
connect(mapStateToProps, mapDispatchToProps),
setCommentStatus,
getQueueCounts,
banUser,
suspendUser,
modQueueQuery,
withQueueCountPolling,
withQuery,
)(ModerationContainer);
@@ -1,6 +1,5 @@
import React, {PropTypes} from 'react';
import {compose} from 'react-apollo';
import {getUserDetail} from 'coral-admin/src/graphql/queries';
import {compose, graphql, gql} from 'react-apollo';
import UserDetail from '../components/UserDetail';
class UserDetailContainer extends React.Component {
@@ -14,6 +13,28 @@ class UserDetailContainer extends React.Component {
}
}
export const withQuery = graphql(gql`
query UserDetail($author_id: ID!) {
user(id: $author_id) {
id
username
created_at
profiles {
id
provider
}
}
totalComments: commentCount(query: {author_id: $author_id})
rejectedComments: commentCount(query: {author_id: $author_id, statuses: [REJECTED]})
}
`, {
options: ({id}) => {
return {
variables: {author_id: id}
};
}
});
export default compose(
getUserDetail
withQuery,
)(UserDetailContainer);