Implement indicator subscriptions for moderation

This commit is contained in:
Chi Vinh Le
2018-01-25 16:45:19 +01:00
parent 2246b16cf4
commit 66934cbb82
8 changed files with 258 additions and 35 deletions
+8 -2
View File
@@ -31,10 +31,16 @@ export const storySearchChange = value => ({
});
export const clearState = () => ({
type: actions.MODERATION_CLEAR_STATE,
type: actions.CLEAR_STATE,
});
export const selectCommentId = id => ({
type: actions.MODERATION_SELECT_COMMENT,
type: actions.SELECT_COMMENT,
id,
});
// Enable or disable the activity indicator subscriptions.
export const setIndicatorTrack = track => ({
type: actions.SET_INDICATOR_TRACK,
track,
});
+12 -9
View File
@@ -1,9 +1,12 @@
export const TOGGLE_MODAL = 'TOGGLE_MODAL';
export const SINGLE_VIEW = 'SINGLE_VIEW';
export const HIDE_SHORTCUTS_NOTE = 'HIDE_SHORTCUTS_NOTE';
export const SET_SORT_ORDER = 'MODERATION_SET_SORT_ORDER';
export const SHOW_STORY_SEARCH = 'SHOW_STORY_SEARCH';
export const HIDE_STORY_SEARCH = 'HIDE_STORY_SEARCH';
export const STORY_SEARCH_CHANGE_VALUE = 'STORY_SEARCH_CHANGE_VALUE';
export const MODERATION_CLEAR_STATE = 'MODERATION_CLEAR_STATE';
export const MODERATION_SELECT_COMMENT = 'MODERATION_SELECT_COMMENT';
const prefix = `MODERATION`;
export const TOGGLE_MODAL = `${prefix}_TOGGLE_MODAL`;
export const SINGLE_VIEW = `${prefix}_SINGLE_VIEW`;
export const HIDE_SHORTCUTS_NOTE = `${prefix}_HIDE_SHORTCUTS_NOTE`;
export const SET_SORT_ORDER = `${prefix}_SET_SORT_ORDER`;
export const SHOW_STORY_SEARCH = `${prefix}_SHOW_STORY_SEARCH`;
export const HIDE_STORY_SEARCH = `${prefix}_HIDE_STORY_SEARCH`;
export const STORY_SEARCH_CHANGE_VALUE = `${prefix}_STORY_SEARCH_CHANGE_VALUE`;
export const CLEAR_STATE = `${prefix}_CLEAR_STATE`;
export const SELECT_COMMENT = `${prefix}_SELECT_COMMENT`;
export const SET_INDICATOR_TRACK = `${prefix}_SET_INDICATOR_TRACK`;
+12 -2
View File
@@ -8,14 +8,19 @@ const initialState = {
shortcutsNoteVisible: 'show',
sortOrder: 'DESC',
selectedCommentId: '',
// If true the activity indicator will turn on subscriptions
// in order to determine queue counts. Set this to false
// if the queue count is determined by other means.
indicatorTrack: true,
};
export default function moderation(state = initialState, action) {
switch (action.type) {
case actions.MODERATION_CLEAR_STATE:
case actions.CLEAR_STATE:
return {
...initialState,
shortcutsNoteVisible: state.shortcutsNoteVisible,
indicatorTrack: state.indicatorTrack,
};
case actions.TOGGLE_MODAL:
return {
@@ -52,11 +57,16 @@ export default function moderation(state = initialState, action) {
...state,
sortOrder: action.order,
};
case actions.MODERATION_SELECT_COMMENT:
case actions.SELECT_COMMENT:
return {
...state,
selectedCommentId: action.id,
};
case actions.SET_INDICATOR_TRACK:
return {
...state,
indicatorTrack: action.track,
};
default:
return state;
}
@@ -35,10 +35,6 @@ function whoFlagged(user) {
class FlaggedAccountsContainer extends Component {
subscriptions = [];
constructor(props) {
super(props);
}
getCountWithoutDangling() {
return this.props.root.flaggedUsers.nodes.filter(
node => !isFlaggedUserDangling(node)
@@ -153,9 +153,6 @@ const enhance = compose(
state: { status: { username: [SET, CHANGED] } }
}
)
me {
id
}
}
`,
})
@@ -1,11 +1,179 @@
import React, { Component } from 'react';
import { compose, gql } from 'react-apollo';
import Indicator from '../../../components/Indicator';
import { withFragments } from 'plugin-api/beta/client/hocs';
import { branch, renderNothing } from 'recompose';
import { handleIndicatorChange } from '../graphql';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import withQueueConfig from '../hoc/withQueueConfig';
import baseQueueConfig from '../queueConfig';
const hideIfNoData = hasNoData => branch(hasNoData, renderNothing);
class IndicatorContainer extends Component {
subscriptions = [];
subscribeToUpdates() {
const parameters = [
{
document: COMMENT_ADDED_SUBSCRIPTION,
updateQuery: (
prev,
{ subscriptionData: { data: { commentAdded: comment } } }
) => {
return handleIndicatorChange(prev, comment, this.props.queueConfig);
},
},
{
document: COMMENT_FLAGGED_SUBSCRIPTION,
updateQuery: (
prev,
{ subscriptionData: { data: { commentFlagged: comment } } }
) => {
return handleIndicatorChange(prev, comment, this.props.queueConfig);
},
},
{
document: COMMENT_ACCEPTED_SUBSCRIPTION,
updateQuery: (
prev,
{ subscriptionData: { data: { commentAccepted: comment } } }
) => {
return handleIndicatorChange(prev, comment, this.props.queueConfig);
},
},
{
document: COMMENT_REJECTED_SUBSCRIPTION,
updateQuery: (
prev,
{ subscriptionData: { data: { commentRejected: { comment } } } }
) => {
return handleIndicatorChange(prev, comment, this.props.queueConfig);
},
},
{
document: COMMENT_RESET_SUBSCRIPTION,
updateQuery: (
prev,
{ subscriptionData: { data: { commentReset: { comment } } } }
) => {
return handleIndicatorChange(prev, comment, this.props.queueConfig);
},
},
];
this.subscriptions = parameters.map(param =>
this.props.data.subscribeToMore(param)
);
}
unsubscribe() {
this.subscriptions.forEach(unsubscribe => unsubscribe());
this.subscriptions = [];
}
componentWillMount() {
if (this.props.track) {
this.subscribeToUpdates();
}
}
componentWillUnmount() {
this.unsubscribe();
}
componentWillReceiveProps(nextProps) {
if (!this.props.track && nextProps.track) {
this.subscribeToUpdates();
}
if (this.props.track && !nextProps.track) {
this.unsubscribe();
}
}
render() {
if (
!this.props.root ||
(!this.props.root.premodCount && !this.props.root.reportedCount)
) {
return null;
}
return <Indicator />;
}
}
IndicatorContainer.propTypes = {
data: PropTypes.object,
root: PropTypes.object,
track: PropTypes.bool,
queueConfig: PropTypes.object,
};
const fields = `
status
actions {
__typename
... on FlagAction {
reason
}
user {
id
role
}
}
status_history {
type
assigned_by {
id
}
}
`;
const COMMENT_ADDED_SUBSCRIPTION = gql`
subscription TalkAdmin_ModerationIndicator_CommentAdded {
commentAdded {
${fields}
}
}
`;
const COMMENT_FLAGGED_SUBSCRIPTION = gql`
subscription TalkAdmin_ModerationIndicator_CommentFlagged {
commentFlagged {
${fields}
}
}
`;
const COMMENT_ACCEPTED_SUBSCRIPTION = gql`
subscription TalkAdmin_ModerationIndicator_CommentAccepted {
commentAccepted{
${fields}
}
}
`;
const COMMENT_REJECTED_SUBSCRIPTION = gql`
subscription TalkAdmin_ModerationIndicator_CommentRejected {
commentRejected{
${fields}
}
}
`;
const COMMENT_RESET_SUBSCRIPTION = gql`
subscription TalkAdmin_ModerationIndicator_CommentReset {
commentReset {
${fields}
}
}
`;
const mapStateToProps = state => ({
track: state.moderation.indicatorTrack,
});
const enhance = compose(
connect(mapStateToProps),
withFragments({
root: gql`
fragment TalkAdmin_Moderation_Indicator_root on RootQuery {
@@ -19,7 +187,7 @@ const enhance = compose(
}
`,
}),
hideIfNoData(props => !props.root.premodCount && !props.root.reportedCount)
withQueueConfig(baseQueueConfig)
);
export default enhance(Indicator);
export default enhance(IndicatorContainer);
@@ -27,6 +27,7 @@ import {
storySearchChange,
clearState,
selectCommentId,
setIndicatorTrack,
} from 'actions/moderation';
import withQueueConfig from '../hoc/withQueueConfig';
import { notify } from 'coral-framework/actions/notification';
@@ -198,11 +199,15 @@ class ModerationContainer extends Component {
}
componentWillMount() {
// Stop activity indicator tracking, as we'll handle it here.
this.props.setIndicatorTrack(false);
this.props.clearState();
this.subscribeToUpdates();
}
componentWillUnmount() {
// Restart activity indicator tracking.
this.props.setIndicatorTrack(true);
this.unsubscribe();
}
@@ -525,6 +530,7 @@ const mapDispatchToProps = dispatch => ({
clearState,
notify,
selectCommentId,
setIndicatorTrack,
},
dispatch
),
@@ -91,6 +91,22 @@ function getCommentQueues(comment, queueConfig) {
return queues;
}
/**
* getPreviousCommentQueues determines queues that this comment previously belonged to.
*/
function getPreviousCommentQueues(comment, queueConfig) {
return comment.status_history.length <= 1
? []
: getCommentQueues(
{
...comment,
status:
comment.status_history[comment.status_history.length - 2].type,
},
queueConfig
);
}
/**
* Return whether or not the comment belongs to the queue.
*/
@@ -203,17 +219,7 @@ export function handleCommentChange(
let next = root;
// Queues that this comment previously belonged to.
const prevQueues =
comment.status_history.length <= 1
? []
: getCommentQueues(
{
...comment,
status:
comment.status_history[comment.status_history.length - 2].type,
},
queueConfig
);
const prevQueues = getPreviousCommentQueues(comment, queueConfig);
// Queues that this comment needs to be placed.
const nextQueues = getCommentQueues(comment, queueConfig);
@@ -291,3 +297,34 @@ export function handleCommentChange(
});
return next;
}
const indicatorQueues = ['premod', 'reported'];
/**
* Track indicator status
* @param {Object} root current state of the store
* @param {Object} comment comment that was changed
* @return {Object} next state of the store
*/
export function handleIndicatorChange(root, comment, queueConfig) {
let next = root;
// Queues that this comment previously belonged to.
const prevQueues = getPreviousCommentQueues(comment, queueConfig);
// Queues that this comment needs to be placed.
const nextQueues = getCommentQueues(comment, queueConfig);
for (const queue of indicatorQueues) {
if (prevQueues.indexOf(queue) === -1 && nextQueues.indexOf(queue) >= 0) {
next = increaseCommentCount(next, queue);
} else if (
prevQueues.indexOf(queue) >= 0 &&
nextQueues.indexOf(queue) === -1
) {
next = decreaseCommentCount(next, queue);
}
}
return next;
}