Skip to content

Commit

Permalink
Merge pull request #557 from coralproject/admin-queue-polish
Browse files Browse the repository at this point in the history
load more comments to moderate if available
  • Loading branch information
kgardnr authored May 3, 2017
2 parents 4f2126e + 7d0d4aa commit 5168f56
Show file tree
Hide file tree
Showing 12 changed files with 136 additions and 76 deletions.
5 changes: 2 additions & 3 deletions client/coral-admin/src/components/ActionButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@ import styles from './ModerationList.css';
import {Button} from 'coral-ui';
import {menuActionsMap} from '../containers/ModerationQueue/helpers/moderationQueueActionsMap';

const ActionButton = ({type = '', status, ...props}) => {
const ActionButton = ({type = '', active, ...props}) => {
const typeName = type.toLowerCase();
const active = ((type === 'REJECT' && status === 'REJECTED') || (type === 'APPROVE' && status === 'ACCEPTED'));
let text = menuActionsMap[type].text;

if (text === 'Approve' && active) {
Expand All @@ -25,7 +24,7 @@ const ActionButton = ({type = '', status, ...props}) => {
};

ActionButton.propTypes = {
status: PropTypes.string
active: PropTypes.bool
};

export default ActionButton;
2 changes: 1 addition & 1 deletion client/coral-admin/src/containers/Dashboard/FlagWidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const FlagWidget = ({assets}) => {
? assets.map(asset => {
let flagSummary = null;
if (asset.action_summaries) {
flagSummary = asset.action_summaries.find(s => s.type === 'FlagAssetActionSummary');
flagSummary = asset.action_summaries.find(s => s.__typename === 'FlagAssetActionSummary');
}

return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import key from 'keymaster';
import isEqual from 'lodash/isEqual';
import styles from './components/styles.css';

import {modQueueQuery} from '../../graphql/queries';
import {modQueueQuery, getQueueCounts} from '../../graphql/queries';
import {banUser, setCommentStatus} from '../../graphql/mutations';

import {fetchSettings} from 'actions/settings';
Expand Down Expand Up @@ -220,6 +220,7 @@ const mapDispatchToProps = dispatch => ({
export default compose(
connect(mapStateToProps, mapDispatchToProps),
setCommentStatus,
getQueueCounts,
modQueueQuery,
banUser
)(ModerationContainer);
108 changes: 62 additions & 46 deletions client/coral-admin/src/containers/ModerationQueue/ModerationQueue.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,51 +9,67 @@ import translations from 'coral-admin/src/translations';
import LoadMore from './components/LoadMore';

const lang = new I18n(translations);
const ModerationQueue = ({comments, selectedIndex, commentCount, singleView, loadMore, activeTab, sort, ...props}) => {
return (
<div id="moderationList" className={`${styles.list} ${singleView ? styles.singleView : ''}`}>
<ul style={{paddingLeft: 0}}>
{
comments.length
? comments.map((comment, i) => {
const status = comment.action_summaries ? 'FLAGGED' : comment.status;
return <Comment
key={i}
index={i}
comment={comment}
selected={i === selectedIndex}
suspectWords={props.suspectWords}
bannedWords={props.bannedWords}
actions={actionsMap[status]}
showBanUserDialog={props.showBanUserDialog}
acceptComment={props.acceptComment}
rejectComment={props.rejectComment}
currentAsset={props.currentAsset}
/>;
})
: <EmptyCard>{lang.t('modqueue.emptyqueue')}</EmptyCard>
}
</ul>
<LoadMore
comments={comments}
loadMore={loadMore}
sort={sort}
tab={activeTab}
showLoadMore={comments.length < commentCount}
assetId={props.assetId}
/>
</div>
);
};

ModerationQueue.propTypes = {
bannedWords: PropTypes.arrayOf(PropTypes.string).isRequired,
suspectWords: PropTypes.arrayOf(PropTypes.string).isRequired,
currentAsset: PropTypes.object,
showBanUserDialog: PropTypes.func.isRequired,
rejectComment: PropTypes.func.isRequired,
acceptComment: PropTypes.func.isRequired,
comments: PropTypes.array.isRequired
};
class ModerationQueue extends React.Component {

static propTypes = {
bannedWords: PropTypes.arrayOf(PropTypes.string).isRequired,
suspectWords: PropTypes.arrayOf(PropTypes.string).isRequired,
currentAsset: PropTypes.object,
showBanUserDialog: PropTypes.func.isRequired,
rejectComment: PropTypes.func.isRequired,
acceptComment: PropTypes.func.isRequired,
comments: PropTypes.array.isRequired
}

componentDidUpdate (prev) {
const {loadMore, comments, commentCount, sort, activeTab: tab, assetId: asset_id} = this.props;

// if the user just moderated the last (visible) comment
// AND there are more comments available on the server,
// go ahead and load more comments
if (prev.comments.length > 0 && comments.length === 0 && commentCount > 0) {
loadMore({sort, tab, asset_id});
}
}

render () {
const {comments, selectedIndex, commentCount, singleView, loadMore, activeTab, sort, ...props} = this.props;

return (
<div id="moderationList" className={`${styles.list} ${singleView ? styles.singleView : ''}`}>
<ul style={{paddingLeft: 0}}>
{
comments.length
? comments.map((comment, i) => {
const status = comment.action_summaries ? 'FLAGGED' : comment.status;
return <Comment
key={i}
index={i}
comment={comment}
selected={i === selectedIndex}
suspectWords={props.suspectWords}
bannedWords={props.bannedWords}
actions={actionsMap[status]}
showBanUserDialog={props.showBanUserDialog}
acceptComment={props.acceptComment}
rejectComment={props.rejectComment}
currentAsset={props.currentAsset}
/>;
})
: <EmptyCard>{lang.t('modqueue.emptyqueue')}</EmptyCard>
}
</ul>
<LoadMore
comments={comments}
loadMore={loadMore}
sort={sort}
tab={activeTab}
showLoadMore={comments.length < commentCount}
assetId={props.assetId}
/>
</div>
);
}
}

export default ModerationQueue;
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,17 @@ const Comment = ({actions = [], comment, ...props}) => {
<div className={styles.sideActions}>
{links ? <span className={styles.hasLinks}><Icon name='error_outline'/> Contains Link</span> : null}
<div className={`actions ${styles.actions}`}>
{actions.map((action, i) =>
<ActionButton key={i}
type={action}
user={comment.user}
status={comment.status}
acceptComment={() => props.acceptComment({commentId: comment.id})}
rejectComment={() => props.rejectComment({commentId: comment.id})}
/>
)}
{actions.map((action, i) => {
const active = (action === 'REJECT' && comment.status === 'REJECTED') ||
(action === 'APPROVE' && comment.status === 'ACCEPTED');
return <ActionButton key={i}
type={action}
user={comment.user}
status={comment.status}
active={active}
acceptComment={() => props.acceptComment({commentId: comment.id})}
rejectComment={() => props.rejectComment({commentId: comment.id})} />;
})}
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@ const LoadMore = ({comments, loadMore, sort, tab, assetId, showLoadMore}) =>
{
showLoadMore && <Button
className={styles.loadMore}
onClick={() =>
loadMore({
cursor: comments[comments.length - 1].created_at,
onClick={() => {
const lastComment = comments[comments.length - 1];
const cursor = lastComment ? lastComment.created_at : null;
return loadMore({
cursor,
sort,
tab,
asset_id: assetId
})}>
});
}}>
Load More
</Button>
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ fragment metrics on Asset {
created_at
commentCount
action_summaries {
type: __typename
actionCount
actionableItemCount
}
Expand Down
25 changes: 15 additions & 10 deletions client/coral-admin/src/graphql/mutations/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ export const suspendUser = graphql(SUSPEND_USER, {
})
});

const views = ['all', 'premod', 'flagged', 'accepted', 'rejected'];
export const setCommentStatus = graphql(SET_COMMENT_STATUS, {
props: ({mutate}) => ({
acceptComment: ({commentId}) => {
Expand All @@ -54,7 +55,9 @@ export const setCommentStatus = graphql(SET_COMMENT_STATUS, {
},
updateQueries: {
ModQueue: (oldData) => {
const comment = oldData.all.find(c => c.id === commentId);
const comment = views.reduce((comment, view) => {
return comment ? comment : oldData[view].find(c => c.id === commentId);
}, null);
let accepted;
let acceptedCount = oldData.acceptedCount;

Expand All @@ -76,10 +79,10 @@ export const setCommentStatus = graphql(SET_COMMENT_STATUS, {

return {
...oldData,
premodCount,
flaggedCount,
acceptedCount,
rejectedCount,
premodCount: Math.max(0, premodCount),
flaggedCount: Math.max(0, flaggedCount),
acceptedCount: Math.max(0, acceptedCount),
rejectedCount: Math.max(0, rejectedCount),
premod,
flagged,
accepted,
Expand All @@ -97,7 +100,9 @@ export const setCommentStatus = graphql(SET_COMMENT_STATUS, {
},
updateQueries: {
ModQueue: (oldData) => {
const comment = oldData.all.find(c => c.id === commentId);
const comment = views.reduce((comment, view) => {
return comment ? comment : oldData[view].find(c => c.id === commentId);
}, null);
let rejected;
let rejectedCount = oldData.rejectedCount;

Expand All @@ -119,10 +124,10 @@ export const setCommentStatus = graphql(SET_COMMENT_STATUS, {

return {
...oldData,
premodCount,
flaggedCount,
acceptedCount,
rejectedCount,
premodCount: Math.max(0, premodCount),
flaggedCount: Math.max(0, flaggedCount),
acceptedCount: Math.max(0, acceptedCount),
rejectedCount: Math.max(0, rejectedCount),
premod,
flagged,
accepted,
Expand Down
22 changes: 22 additions & 0 deletions client/coral-admin/src/graphql/queries/getQueueCounts.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
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]
})
}
12 changes: 12 additions & 0 deletions client/coral-admin/src/graphql/queries/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ 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 GET_QUEUE_COUNTS from './getQueueCounts.graphql';

export const modQueueQuery = graphql(MOD_QUEUE_QUERY, {
options: ({params: {id = null}}) => {
Expand Down Expand Up @@ -93,3 +94,14 @@ export const modQueueResort = (id, fetchMore) => (sort) => {
updateQuery: (oldData, {fetchMoreResult:{data}}) => data
});
};

export const getQueueCounts = graphql(GET_QUEUE_COUNTS, {
options: ({params: {id = null}}) => {
return {
pollInterval: 5000,
variables: {
asset_id: id
}
};
}
});
2 changes: 2 additions & 0 deletions client/coral-admin/src/services/fragmentMatcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const fm = new IntrospectionFragmentMatcher({
kind: 'INTERFACE',
name: 'Action',
possibleTypes: [
{name: 'DefaultAction'},
{name: 'FlagAction'},
{name: 'DontAgreeAction'}
],
Expand All @@ -44,6 +45,7 @@ const fm = new IntrospectionFragmentMatcher({
kind: 'INTERFACE',
name: 'ActionSummary',
possibleTypes: [
{name: 'DefaultActionSummary'},
{name: 'FlagActionSummary'},
{name: 'DontAgreeActionSummary'}
],
Expand Down
1 change: 0 additions & 1 deletion test/server/graph/loaders/metrics.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ describe('graph.loaders.Metrics', () => {
fragment metrics on Asset {
id
action_summaries {
type: __typename
actionCount
actionableItemCount
}
Expand Down

0 comments on commit 5168f56

Please sign in to comment.