From 219399a23153cc7f5e85b6c2b933478f530b8ec0 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Wed, 27 Sep 2017 22:50:45 +0700 Subject: [PATCH 01/17] Refactor ComemntDetail and implement ToxicDetail --- .../src/components/CommentDetail.css | 34 +++++++ .../src/components/CommentDetail.js | 32 +++++++ client/coral-admin/src/components/FlagBox.css | 93 +++++++------------ client/coral-admin/src/components/FlagBox.js | 65 +++++++------ .../routes/Moderation/components/Comment.js | 10 +- .../client/components/ToxicDetail.css | 11 +++ .../client/components/ToxicDetail.js | 46 +++++++++ .../client/containers/ToxicDetail.js | 21 +++++ .../client/containers/ToxicLabel.js | 7 +- .../client/index.js | 2 + .../client/utils.js | 4 + plugins/talk-plugin-toxic-comments/index.js | 2 + .../server/resolvers.js | 7 ++ .../server/typeDefs.graphql | 3 + 14 files changed, 235 insertions(+), 102 deletions(-) create mode 100644 client/coral-admin/src/components/CommentDetail.css create mode 100644 client/coral-admin/src/components/CommentDetail.js create mode 100644 plugins/talk-plugin-toxic-comments/client/components/ToxicDetail.css create mode 100644 plugins/talk-plugin-toxic-comments/client/components/ToxicDetail.js create mode 100644 plugins/talk-plugin-toxic-comments/client/containers/ToxicDetail.js create mode 100644 plugins/talk-plugin-toxic-comments/client/utils.js create mode 100644 plugins/talk-plugin-toxic-comments/server/resolvers.js diff --git a/client/coral-admin/src/components/CommentDetail.css b/client/coral-admin/src/components/CommentDetail.css new file mode 100644 index 000000000..259d4e1c5 --- /dev/null +++ b/client/coral-admin/src/components/CommentDetail.css @@ -0,0 +1,34 @@ +.root { + margin-left: 16px; +} + +.headerContainer { + display: flex; + justify-content: flex-start; + align-items: center; +} + +.header { + vertical-align: middle; + margin: 0; + font-weight: 500; + display: inline-block; + font-size: 12px; + line-height: 12px; + margin-right: 7px; +} + +.info { + font-size: 12px; +} + +.details { + padding: 0 20px 16px; + font-size: 12px; +} + +.icon { + vertical-align: middle; + font-size: 12px; + margin-right: 7px; +} diff --git a/client/coral-admin/src/components/CommentDetail.js b/client/coral-admin/src/components/CommentDetail.js new file mode 100644 index 000000000..2e1a89089 --- /dev/null +++ b/client/coral-admin/src/components/CommentDetail.js @@ -0,0 +1,32 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import cn from 'classnames'; +import styles from './CommentDetail.css'; +import {Icon} from 'coral-ui'; + +const CommentDetail = ({icon, header, info, children, className}) => { + return ( +
+
+ {icon && } +

{header}:

+
{info}
+
+ {children && +
+ {children} +
+ } +
+ ); +}; + +CommentDetail.propTypes = { + className: PropTypes.string, + header: PropTypes.node, + icon: PropTypes.string, + info: PropTypes.node, + children: PropTypes.node, +}; + +export default CommentDetail; diff --git a/client/coral-admin/src/components/FlagBox.css b/client/coral-admin/src/components/FlagBox.css index 232803203..b88f904b9 100644 --- a/client/coral-admin/src/components/FlagBox.css +++ b/client/coral-admin/src/components/FlagBox.css @@ -1,56 +1,42 @@ .flagBox { border-top: 1px solid rgba(66, 66, 66, 0.12); margin-top: 10px; - .container { - padding: 0 14px; - } + padding-top: 10px; +} - .detail { - padding: 0 20px 16px; - ul { - padding: 0; - list-style: none; - font-size: 12px; - font-weight: 500; - } - } +.info { + vertical-align: middle; + list-style: none; + display: inline-block; + padding: 0; + font-size: 12px; +} - .header { - position: relative; - .moreDetail { - float: right; - font-size: 12px; - font-weight: 500; - margin-right: 10px; - margin-top: 8px; - color: black; +.detail { + padding: 0; + list-style: none; + font-size: 12px; + font-weight: 500; +} - &:hover { - opacity: 0.9; - cursor: pointer; - } - } - i { - vertical-align: middle; - font-size: 12px; - } - ul { - vertical-align: middle; - list-style: none; - display: inline-block; - padding: 0; - margin-left: 10px; - font-size: 12px; - } - } +.subDetail { + padding: 0; + list-style: none; + font-size: 12px; + font-weight: normal; + color: #888; +} - h3 { - vertical-align: middle; - margin: 0; - font-weight: 500; - display: inline-block; - margin-left: 7px; - font-size: 12px; +.moreDetail { + position: absolute; + font-size: 12px; + font-weight: 500; + color: black; + right: 16px; + + &:hover { + opacity: 0.9; + cursor: pointer; } } @@ -59,15 +45,6 @@ margin-right: 10px; } -.subDetail { - font-weight: normal; - color: #888; - - span { - color: black; - } -} - .username { color: #393B44; text-decoration: none; @@ -77,7 +54,7 @@ border-radius: 2px; margin-left: -5px; transition: background-color 200ms ease; -&:hover { - background-color: #E0E0E0; - } + &:hover { + background-color: #E0E0E0; + } } diff --git a/client/coral-admin/src/components/FlagBox.js b/client/coral-admin/src/components/FlagBox.js index 05fd14128..44a302e52 100644 --- a/client/coral-admin/src/components/FlagBox.js +++ b/client/coral-admin/src/components/FlagBox.js @@ -1,8 +1,8 @@ import React, {Component} from 'react'; import PropTypes from 'prop-types'; -import {Icon} from 'coral-ui'; import styles from './FlagBox.css'; import t from 'coral-framework/services/i18n'; +import CommentDetail from './CommentDetail'; const shortReasons = { 'This comment is offensive': t('modqueue.offensive'), @@ -39,45 +39,42 @@ class FlagBox extends Component { return (
-
-
-

{t('community.flags')} ({actionSummaries.length}):

- - {showDetail ? t('modqueue.less_detail') : t('modqueue.more_detail')} -
+ }> {showDetail && ( -
-
    - {actionSummaries.map((summary, i) => { - - const actionList = actions.filter((a) => a.reason === summary.reason); - - return ( -
  • - {this.reasonMap(summary.reason)} ({summary.count}) - -
  • - ); - })} -
-
+
    + {actionSummaries.map((summary, i) => { + const actionList = actions.filter((a) => a.reason === summary.reason); + return ( +
  • + {this.reasonMap(summary.reason)} ({summary.count}) + +
  • + ); + })} +
)} -
+
); } diff --git a/client/coral-admin/src/routes/Moderation/components/Comment.js b/client/coral-admin/src/routes/Moderation/components/Comment.js index f72b0ef12..e19f34229 100644 --- a/client/coral-admin/src/routes/Moderation/components/Comment.js +++ b/client/coral-admin/src/routes/Moderation/components/Comment.js @@ -185,11 +185,6 @@ class Comment extends React.Component { - {flagActions && flagActions.length ? : null} + ); } diff --git a/plugins/talk-plugin-toxic-comments/client/components/ToxicDetail.css b/plugins/talk-plugin-toxic-comments/client/components/ToxicDetail.css new file mode 100644 index 000000000..cbf7ce8de --- /dev/null +++ b/plugins/talk-plugin-toxic-comments/client/components/ToxicDetail.css @@ -0,0 +1,11 @@ +.info { + background-color: rgba(44, 44, 44, 0.89); + color: white; + padding: 2px 4px; + font-size: 0.8em; + margin-left: 6px; +} + +.toxic { + background-color: #d03235; +} diff --git a/plugins/talk-plugin-toxic-comments/client/components/ToxicDetail.js b/plugins/talk-plugin-toxic-comments/client/components/ToxicDetail.js new file mode 100644 index 000000000..de8a0337c --- /dev/null +++ b/plugins/talk-plugin-toxic-comments/client/components/ToxicDetail.js @@ -0,0 +1,46 @@ +import React from 'react'; +import CommentDetail from 'coral-admin/src/components/CommentDetail'; +import {isToxic} from '../utils'; +import styles from './ToxicDetail.css'; +import cn from 'classnames'; +import PropTypes from 'prop-types'; + +const getInfo = (toxicity, actions) => { + const toxic = isToxic(actions); + let text = 'Unlikely'; + if (toxicity > 0.8) { + text = 'Highly Likely'; + } + else if (toxicity >= 0.5) { + text = 'Possibly'; + } + else if (toxicity >= 0.7) { + text = 'Likely'; + } + + return ( +
+ {text} + + {Math.round(toxicity * 100)}% + +
+ ); +}; + +const ToxicLabel = ({comment: {actions, toxicity}}) => ( + +); + +ToxicLabel.propTypes = { + comment: PropTypes.shape({ + actions: PropTypes.array, + toxicity: PropTypes.toxicity, + }), +}; + +export default ToxicLabel; diff --git a/plugins/talk-plugin-toxic-comments/client/containers/ToxicDetail.js b/plugins/talk-plugin-toxic-comments/client/containers/ToxicDetail.js new file mode 100644 index 000000000..32b83fbb3 --- /dev/null +++ b/plugins/talk-plugin-toxic-comments/client/containers/ToxicDetail.js @@ -0,0 +1,21 @@ +import {compose, gql} from 'react-apollo'; +import {withFragments, excludeIf} from 'plugin-api/beta/client/hocs'; +import ToxicDetail from '../components/ToxicDetail'; + +const enhance = compose( + withFragments({ + comment: gql` + fragment TalkToxicComments_ToxicDetail_Comment on Comment { + toxicity + actions { + __typename + ... on FlagAction { + reason + } + } + }`, + }), + excludeIf(({comment: {toxicity}}) => toxicity === null), +); + +export default enhance(ToxicDetail); diff --git a/plugins/talk-plugin-toxic-comments/client/containers/ToxicLabel.js b/plugins/talk-plugin-toxic-comments/client/containers/ToxicLabel.js index 0d2e9e14b..ee43f4a7e 100644 --- a/plugins/talk-plugin-toxic-comments/client/containers/ToxicLabel.js +++ b/plugins/talk-plugin-toxic-comments/client/containers/ToxicLabel.js @@ -1,15 +1,12 @@ import {compose, gql} from 'react-apollo'; import {withFragments, excludeIf} from 'plugin-api/beta/client/hocs'; import ToxicLabel from '../components/ToxicLabel'; - -function isToxic(actions) { - return actions.some((action) => action.__typename === 'FlagAction' && action.reason === 'TOXIC_COMMENT'); -} +import {isToxic} from '../utils'; const enhance = compose( withFragments({ comment: gql` - fragment TalkToxicComments_Comment on Comment { + fragment TalkToxicComments_ToxicLabel_Comment on Comment { actions { __typename ... on FlagAction { diff --git a/plugins/talk-plugin-toxic-comments/client/index.js b/plugins/talk-plugin-toxic-comments/client/index.js index 8a16b8dea..1db520891 100644 --- a/plugins/talk-plugin-toxic-comments/client/index.js +++ b/plugins/talk-plugin-toxic-comments/client/index.js @@ -1,11 +1,13 @@ import translations from './translations.yml'; import CheckToxicityHook from './containers/CheckToxicityHook'; import ToxicLabel from './containers/ToxicLabel'; +import ToxicDetail from './containers/ToxicDetail'; export default { translations, slots: { commentInputDetailArea: [CheckToxicityHook], adminCommentLabels: [ToxicLabel], + adminCommentDetailArea: [ToxicDetail], }, }; diff --git a/plugins/talk-plugin-toxic-comments/client/utils.js b/plugins/talk-plugin-toxic-comments/client/utils.js new file mode 100644 index 000000000..57bfd9633 --- /dev/null +++ b/plugins/talk-plugin-toxic-comments/client/utils.js @@ -0,0 +1,4 @@ +export function isToxic(actions) { + return actions.some((action) => action.__typename === 'FlagAction' && action.reason === 'TOXIC_COMMENT'); +} + diff --git a/plugins/talk-plugin-toxic-comments/index.js b/plugins/talk-plugin-toxic-comments/index.js index 0802a6c11..444cb94f5 100644 --- a/plugins/talk-plugin-toxic-comments/index.js +++ b/plugins/talk-plugin-toxic-comments/index.js @@ -1,8 +1,10 @@ const {readFileSync} = require('fs'); const path = require('path'); const hooks = require('./server/hooks'); +const resolvers = require('./server/resolvers'); module.exports = { typeDefs: readFileSync(path.join(__dirname, 'server/typeDefs.graphql'), 'utf8'), hooks, + resolvers, }; diff --git a/plugins/talk-plugin-toxic-comments/server/resolvers.js b/plugins/talk-plugin-toxic-comments/server/resolvers.js new file mode 100644 index 000000000..5af584b44 --- /dev/null +++ b/plugins/talk-plugin-toxic-comments/server/resolvers.js @@ -0,0 +1,7 @@ +const get = require('lodash/get'); + +module.exports = { + Comment: { + toxicity: (comment) => get(comment, 'metadata.perspective.SEVERE_TOXICITY.summaryScore'), + } +}; diff --git a/plugins/talk-plugin-toxic-comments/server/typeDefs.graphql b/plugins/talk-plugin-toxic-comments/server/typeDefs.graphql index b4dfc8345..c9e28fb9c 100644 --- a/plugins/talk-plugin-toxic-comments/server/typeDefs.graphql +++ b/plugins/talk-plugin-toxic-comments/server/typeDefs.graphql @@ -5,3 +5,6 @@ input CreateCommentInput { checkToxicity: Boolean } +type Comment { + toxicity: Float +} From 5d718f6dd4ce4a3b704512f9b1cbda002a51004e Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Thu, 28 Sep 2017 22:02:06 +0700 Subject: [PATCH 02/17] Only shw user flags in detail --- .../src/components/CommentDetails.css | 18 ++++ .../src/components/CommentDetails.js | 50 ++++++++++ client/coral-admin/src/components/FlagBox.js | 94 ------------------- .../{FlagBox.css => FlagDetails.css} | 19 +--- .../coral-admin/src/components/FlagDetails.js | 75 +++++++++++++++ .../src/components/UserDetailComment.js | 8 +- .../src/containers/UserDetailComment.js | 6 -- .../routes/Moderation/components/Comment.js | 4 +- 8 files changed, 148 insertions(+), 126 deletions(-) create mode 100644 client/coral-admin/src/components/CommentDetails.css create mode 100644 client/coral-admin/src/components/CommentDetails.js delete mode 100644 client/coral-admin/src/components/FlagBox.js rename client/coral-admin/src/components/{FlagBox.css => FlagDetails.css} (70%) create mode 100644 client/coral-admin/src/components/FlagDetails.js diff --git a/client/coral-admin/src/components/CommentDetails.css b/client/coral-admin/src/components/CommentDetails.css new file mode 100644 index 000000000..ff3679cc7 --- /dev/null +++ b/client/coral-admin/src/components/CommentDetails.css @@ -0,0 +1,18 @@ +.root { + margin-top: 10px; + padding-top: 10px; +} + +.moreDetail { + position: absolute; + font-size: 12px; + font-weight: 500; + color: black; + right: 16px; + + &:hover { + opacity: 0.9; + cursor: pointer; + } +} + diff --git a/client/coral-admin/src/components/CommentDetails.js b/client/coral-admin/src/components/CommentDetails.js new file mode 100644 index 000000000..9d9c26813 --- /dev/null +++ b/client/coral-admin/src/components/CommentDetails.js @@ -0,0 +1,50 @@ +import React, {Component} from 'react'; +import PropTypes from 'prop-types'; +import styles from './CommentDetails.css'; +import t from 'coral-framework/services/i18n'; +import FlagDetails from './FlagDetails'; + +class CommentDetails extends Component { + state = { + showDetail: false + }; + + constructor () { + super(); + this.state = { + showDetail: false + }; + } + + toggleDetail = () => { + this.setState((state) => ({ + showDetail: !state.showDetail + })); + } + + render() { + const {actions, viewUserDetail} = this.props; + const {showDetail} = this.state; + + return ( + + ); + } +} + +CommentDetails.propTypes = { + actions: PropTypes.arrayOf(PropTypes.shape({ + message: PropTypes.string, + user: PropTypes.shape({username: PropTypes.string}) + })).isRequired, + viewUserDetail: PropTypes.func.isRequired, +}; + +export default CommentDetails; diff --git a/client/coral-admin/src/components/FlagBox.js b/client/coral-admin/src/components/FlagBox.js deleted file mode 100644 index 44a302e52..000000000 --- a/client/coral-admin/src/components/FlagBox.js +++ /dev/null @@ -1,94 +0,0 @@ -import React, {Component} from 'react'; -import PropTypes from 'prop-types'; -import styles from './FlagBox.css'; -import t from 'coral-framework/services/i18n'; -import CommentDetail from './CommentDetail'; - -const shortReasons = { - 'This comment is offensive': t('modqueue.offensive'), - 'This looks like an ad/marketing': t('modqueue.spam_ads'), - 'This user is impersonating': t('modqueue.impersonating'), - 'I don\'t like this username': t('modqueue.dont_like_username'), - 'Other': t('modqueue.other') -}; - -class FlagBox extends Component { - constructor () { - super(); - this.state = { - showDetail: false - }; - } - - toggleDetail = () => { - this.setState((state) => ({ - showDetail: !state.showDetail - })); - } - - reasonMap = (reason) => { - const shortReason = shortReasons[reason]; - - // if the short reason isn't found, just return the long one. - return shortReason ? shortReason : reason; - } - - render() { - const {actionSummaries, actions, viewUserDetail} = this.props; - const {showDetail} = this.state; - - return ( -
- {showDetail ? t('modqueue.less_detail') : t('modqueue.more_detail')} - - {actionSummaries.map((action, i) => -
  • {this.reasonMap(action.reason)} ({action.count})
  • - )} - - }> - {showDetail && ( -
      - {actionSummaries.map((summary, i) => { - const actionList = actions.filter((a) => a.reason === summary.reason); - return ( -
    • - {this.reasonMap(summary.reason)} ({summary.count}) - -
    • - ); - })} -
    - )} -
    -
    - ); - } -} - -FlagBox.propTypes = { - actionSummaries: PropTypes.arrayOf(PropTypes.shape({ - reason: PropTypes.string, - count: PropTypes.number - })).isRequired, - actions: PropTypes.arrayOf(PropTypes.shape({ - message: PropTypes.string, - user: PropTypes.shape({username: PropTypes.string}) - })).isRequired -}; - -export default FlagBox; diff --git a/client/coral-admin/src/components/FlagBox.css b/client/coral-admin/src/components/FlagDetails.css similarity index 70% rename from client/coral-admin/src/components/FlagBox.css rename to client/coral-admin/src/components/FlagDetails.css index b88f904b9..302e24858 100644 --- a/client/coral-admin/src/components/FlagBox.css +++ b/client/coral-admin/src/components/FlagDetails.css @@ -1,8 +1,3 @@ -.flagBox { - border-top: 1px solid rgba(66, 66, 66, 0.12); - margin-top: 10px; - padding-top: 10px; -} .info { vertical-align: middle; @@ -20,6 +15,7 @@ } .subDetail { + margin-left:10px; padding: 0; list-style: none; font-size: 12px; @@ -27,19 +23,6 @@ color: #888; } -.moreDetail { - position: absolute; - font-size: 12px; - font-weight: 500; - color: black; - right: 16px; - - &:hover { - opacity: 0.9; - cursor: pointer; - } -} - .lessDetail { display: inline-block; margin-right: 10px; diff --git a/client/coral-admin/src/components/FlagDetails.js b/client/coral-admin/src/components/FlagDetails.js new file mode 100644 index 000000000..74bff8f24 --- /dev/null +++ b/client/coral-admin/src/components/FlagDetails.js @@ -0,0 +1,75 @@ +import React, {Component} from 'react'; +import PropTypes from 'prop-types'; +import styles from './FlagDetails.css'; +import t from 'coral-framework/services/i18n'; +import CommentDetail from './CommentDetail'; + +class FlagDetails extends Component { + + render() { + const {actions, viewUserDetail, more} = this.props; + const summaries = actions.reduce((sum, action) => { + if (!(action.reason in sum)) { + sum[action.reason] = {count: 0, userFlagged: false, actions: []}; + } + sum[action.reason].count++; + if (action.user) { + sum[action.reason].userFlagged = true; + } + sum[action.reason].actions.push(action); + return sum; + }, {}); + + const userFlagReasons = Object.keys(summaries).filter((reason) => summaries[reason].userFlagged); + + return ( + + {Object.keys(summaries).map((reason) => +
  • + {reason} {summaries[reason].userFlagged && `(${summaries[reason].count})`} +
  • + )} + + }> + {more && userFlagReasons.length > 0 && ( + + )} +
    + ); + } +} + +FlagDetails.propTypes = { + more: PropTypes.bool, + actions: PropTypes.arrayOf(PropTypes.shape({ + message: PropTypes.string, + user: PropTypes.shape({username: PropTypes.string}) + })).isRequired, + viewUserDetail: PropTypes.func.isRequired, +}; + +export default FlagDetails; diff --git a/client/coral-admin/src/components/UserDetailComment.js b/client/coral-admin/src/components/UserDetailComment.js index 2aec28ab9..4ef557173 100644 --- a/client/coral-admin/src/components/UserDetailComment.js +++ b/client/coral-admin/src/components/UserDetailComment.js @@ -3,9 +3,8 @@ import PropTypes from 'prop-types'; import {Link} from 'react-router'; import {Icon} from 'coral-ui'; -import FlagBox from './FlagBox'; +import CommentDetails from './CommentDetails'; import styles from './UserDetailComment.css'; -import {getActionSummary} from 'coral-framework/utils'; import ActionButton from 'coral-admin/src/components/ActionButton'; import CommentBodyHighlighter from 'coral-admin/src/components/CommentBodyHighlighter'; import IfHasLink from 'coral-admin/src/components/IfHasLink'; @@ -31,7 +30,6 @@ class UserDetailComment extends React.Component { ...props } = this.props; - const flagActionSummaries = getActionSummary('FlagActionSummary', comment); const flagActions = comment.actions && comment.actions.filter((a) => a.__typename === 'FlagAction'); return ( @@ -117,9 +115,8 @@ class UserDetailComment extends React.Component { {flagActions && flagActions.length - ? : null} @@ -139,7 +136,6 @@ UserDetailComment.propTypes = { toggleSelect: PropTypes.func, comment: PropTypes.shape({ body: PropTypes.string.isRequired, - action_summaries: PropTypes.array, actions: PropTypes.array, created_at: PropTypes.string.isRequired, asset: PropTypes.shape({ diff --git a/client/coral-admin/src/containers/UserDetailComment.js b/client/coral-admin/src/containers/UserDetailComment.js index 9f0199bce..6b3572434 100644 --- a/client/coral-admin/src/containers/UserDetailComment.js +++ b/client/coral-admin/src/containers/UserDetailComment.js @@ -17,12 +17,6 @@ export default withFragments({ title url } - action_summaries { - count - ... on FlagActionSummary { - reason - } - } actions { ... on FlagAction { id diff --git a/client/coral-admin/src/routes/Moderation/components/Comment.js b/client/coral-admin/src/routes/Moderation/components/Comment.js index e19f34229..c761ff591 100644 --- a/client/coral-admin/src/routes/Moderation/components/Comment.js +++ b/client/coral-admin/src/routes/Moderation/components/Comment.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import {Link} from 'react-router'; import {Icon} from 'coral-ui'; -import FlagBox from 'coral-admin/src/components/FlagBox'; +import CommentDetails from 'coral-admin/src/components/CommentDetails'; import styles from './Comment.css'; import CommentLabels from 'coral-admin/src/components/CommentLabels'; import CommentAnimatedEdit from 'coral-admin/src/components/CommentAnimatedEdit'; @@ -186,7 +186,7 @@ class Comment extends React.Component { {flagActions && flagActions.length - ? Date: Fri, 29 Sep 2017 19:42:44 +0700 Subject: [PATCH 03/17] Refactor and pluginize comment details --- .eslintignore | 1 + .gitignore | 1 + .../src/components/ActionButton.css | 24 ------ .../src/components/ActionButton.js | 38 --------- .../src/components/ApproveButton.css | 44 +++++++++++ .../src/components/ApproveButton.js | 30 +++++++ .../src/components/CommentDetails.js | 23 +++--- .../src/components/RejectButton.css | 44 +++++++++++ .../src/components/RejectButton.js | 30 +++++++ .../coral-admin/src/components/UserDetail.js | 6 +- .../src/components/UserDetailComment.js | 66 +++++++--------- .../src/containers/CommentDetails.js | 23 ++++++ .../src/containers/CommentLabels.js | 6 ++ .../coral-admin/src/containers/UserDetail.js | 2 + .../src/containers/UserDetailComment.js | 25 +++--- .../Community/components/ActionButton.css | 4 - .../Community/components/ActionButton.js | 22 ------ .../Community/components/FlaggedAccounts.js | 1 - .../Community/components/FlaggedUser.js | 25 +++--- .../components/RejectUsernameDialog.js | 2 +- .../routes/Community/containers/Community.js | 6 +- .../routes/Moderation/components/Comment.js | 68 ++++++---------- .../Moderation/components/ModerationQueue.js | 5 -- .../routes/Moderation/containers/Comment.js | 29 ++----- .../Moderation/containers/Moderation.js | 2 + .../src/utils/moderationQueueActionsMap.js | 14 ---- client/coral-ui/components/Button.css | 53 ------------- .../talk-plugin-flag-details/.eslintrc.json | 3 + .../talk-plugin-flag-details/client/.babelrc | 14 ++++ .../client/.eslintrc.json | 3 + .../client/components/FlagDetails.css | 43 ++++++++++ .../client/components/FlagDetails.js | 79 +++++++++++++++++++ .../client/containers/FlagDetails.js | 37 +++++++++ .../talk-plugin-flag-details/client/index.js | 9 +++ .../client/translations.yml | 3 + plugins/talk-plugin-flag-details/index.js | 1 + .../client/containers/ToxicDetail.js | 2 +- 37 files changed, 486 insertions(+), 302 deletions(-) delete mode 100644 client/coral-admin/src/components/ActionButton.css delete mode 100644 client/coral-admin/src/components/ActionButton.js create mode 100644 client/coral-admin/src/components/ApproveButton.css create mode 100644 client/coral-admin/src/components/ApproveButton.js create mode 100644 client/coral-admin/src/components/RejectButton.css create mode 100644 client/coral-admin/src/components/RejectButton.js create mode 100644 client/coral-admin/src/containers/CommentDetails.js delete mode 100644 client/coral-admin/src/routes/Community/components/ActionButton.css delete mode 100644 client/coral-admin/src/routes/Community/components/ActionButton.js delete mode 100644 client/coral-admin/src/utils/moderationQueueActionsMap.js create mode 100644 plugins/talk-plugin-flag-details/.eslintrc.json create mode 100644 plugins/talk-plugin-flag-details/client/.babelrc create mode 100644 plugins/talk-plugin-flag-details/client/.eslintrc.json create mode 100644 plugins/talk-plugin-flag-details/client/components/FlagDetails.css create mode 100644 plugins/talk-plugin-flag-details/client/components/FlagDetails.js create mode 100644 plugins/talk-plugin-flag-details/client/containers/FlagDetails.js create mode 100644 plugins/talk-plugin-flag-details/client/index.js create mode 100644 plugins/talk-plugin-flag-details/client/translations.yml create mode 100644 plugins/talk-plugin-flag-details/index.js diff --git a/.eslintignore b/.eslintignore index fc0214dd2..22cf3d4b8 100644 --- a/.eslintignore +++ b/.eslintignore @@ -26,5 +26,6 @@ plugins/* !plugins/talk-plugin-toxic-comments !plugins/talk-plugin-remember-sort !plugins/talk-plugin-deep-reply-count +!plugins/talk-plugin-flag-details node_modules diff --git a/.gitignore b/.gitignore index bcc7c89b1..e253c5904 100644 --- a/.gitignore +++ b/.gitignore @@ -43,5 +43,6 @@ plugins/* !plugins/talk-plugin-toxic-comments !plugins/talk-plugin-remember-sort !plugins/talk-plugin-deep-reply-count +!plugins/talk-plugin-flag-details **/node_modules/* diff --git a/client/coral-admin/src/components/ActionButton.css b/client/coral-admin/src/components/ActionButton.css deleted file mode 100644 index 226006c6b..000000000 --- a/client/coral-admin/src/components/ActionButton.css +++ /dev/null @@ -1,24 +0,0 @@ -.actionButton { - transform: scale(.8); - margin: 0; -} - -.minimal { - width: 45px; - min-width: 0; -} - -.approve__active { - box-shadow: none; - color: white; - background-color: #519954; - cursor: not-allowed; -} - -.reject__active, .rejected__active { - color: white; - background-color: #D03235; - box-shadow: none; - cursor: not-allowed; -} - diff --git a/client/coral-admin/src/components/ActionButton.js b/client/coral-admin/src/components/ActionButton.js deleted file mode 100644 index 77456b939..000000000 --- a/client/coral-admin/src/components/ActionButton.js +++ /dev/null @@ -1,38 +0,0 @@ -import React from 'react'; -import PropTypes from 'prop-types'; - -import styles from './ActionButton.css'; -import {Button} from 'coral-ui'; -import {menuActionsMap} from '../utils/moderationQueueActionsMap'; - -import t from 'coral-framework/services/i18n'; - -const ActionButton = ({type = '', active, ...props}) => { - const typeName = type.toLowerCase(); - let text = menuActionsMap[type].text; - - if (text === 'approve' && active) { - text = 'approved'; - } else if (text === 'reject' && active) { - text = 'rejected'; - } - - return ( - - ); -}; - -ActionButton.propTypes = { - active: PropTypes.bool, - type: PropTypes.oneOf(['APPROVE', 'REJECT']), - minimal: PropTypes.bool, - acceptComment: PropTypes.func, - rejectComment: PropTypes.func, -}; - -export default ActionButton; diff --git a/client/coral-admin/src/components/ApproveButton.css b/client/coral-admin/src/components/ApproveButton.css new file mode 100644 index 000000000..4c42cc233 --- /dev/null +++ b/client/coral-admin/src/components/ApproveButton.css @@ -0,0 +1,44 @@ +.root { + display: block; + color: #519954; + border: solid 2px rgba(81, 153, 84, 0.75); + background: white; + padding: 10px 12px; + box-sizing: border-box; + vertical-align: middle; + line-height: 24px; + font-size: 17px; + height: 47px; + border-radius: 3px; + text-transform: capitalize; + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.03), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.09); + width: 129px; + transform: scale(.8); + margin: 0; + + &:hover { + box-shadow: none; + color: white; + background-color: #519954; + cursor: pointer; + } +} + +.active { + box-shadow: none; + color: white; + background-color: #519954; + + &:hover { + cursor: not-allowed; + } +} + +.minimal { + width: 45px; + min-width: 0; +} + +.icon { + margin-right: 5px; +} diff --git a/client/coral-admin/src/components/ApproveButton.js b/client/coral-admin/src/components/ApproveButton.js new file mode 100644 index 000000000..151a5ca29 --- /dev/null +++ b/client/coral-admin/src/components/ApproveButton.js @@ -0,0 +1,30 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import cn from 'classnames'; +import styles from './ApproveButton.css'; +import {Icon} from 'coral-ui'; + +import t from 'coral-framework/services/i18n'; + +const ApproveButton = ({active, minimal, onClick}) => { + const text = active ? t('modqueue.approved') : t('modqueue.approve'); + return ( + + ); +}; + +ApproveButton.propTypes = { + active: PropTypes.bool, + minimal: PropTypes.bool, + onClick: PropTypes.func, +}; + +export default ApproveButton; + diff --git a/client/coral-admin/src/components/CommentDetails.js b/client/coral-admin/src/components/CommentDetails.js index 9d9c26813..d984ce0c1 100644 --- a/client/coral-admin/src/components/CommentDetails.js +++ b/client/coral-admin/src/components/CommentDetails.js @@ -2,7 +2,7 @@ import React, {Component} from 'react'; import PropTypes from 'prop-types'; import styles from './CommentDetails.css'; import t from 'coral-framework/services/i18n'; -import FlagDetails from './FlagDetails'; +import Slot from 'coral-framework/components/Slot'; class CommentDetails extends Component { state = { @@ -23,15 +23,20 @@ class CommentDetails extends Component { } render() { - const {actions, viewUserDetail} = this.props; + const {data, root, comment} = this.props; const {showDetail} = this.state; + const queryData = { + root, + comment, + }; return ( @@ -40,11 +45,9 @@ class CommentDetails extends Component { } CommentDetails.propTypes = { - actions: PropTypes.arrayOf(PropTypes.shape({ - message: PropTypes.string, - user: PropTypes.shape({username: PropTypes.string}) - })).isRequired, - viewUserDetail: PropTypes.func.isRequired, + data: PropTypes.object.isRequired, + root: PropTypes.object.isRequired, + comment: PropTypes.object.isRequired, }; export default CommentDetails; diff --git a/client/coral-admin/src/components/RejectButton.css b/client/coral-admin/src/components/RejectButton.css new file mode 100644 index 000000000..a06cf5f43 --- /dev/null +++ b/client/coral-admin/src/components/RejectButton.css @@ -0,0 +1,44 @@ +.root { + display: block; + color: #D03235; + border: solid 1px #D03235; + background: white; + padding: 10px 11px; + box-sizing: border-box; + vertical-align: middle; + line-height: 24px; + font-size: 17px; + height: 47px; + border-radius: 3px; + text-transform: capitalize; + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.03), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.09); + width: 129px; + transform: scale(.8); + margin: 0; + + &:hover { + color: white; + background-color: #D03235; + box-shadow: none; + cursor: pointer; + } +} + +.active { + color: white; + background-color: #D03235; + box-shadow: none; + + &:hover { + cursor: not-allowed; + } +} + +.minimal { + width: 45px; + min-width: 0; +} + +.icon { + margin-right: 5px; +} diff --git a/client/coral-admin/src/components/RejectButton.js b/client/coral-admin/src/components/RejectButton.js new file mode 100644 index 000000000..e01102dc3 --- /dev/null +++ b/client/coral-admin/src/components/RejectButton.js @@ -0,0 +1,30 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import cn from 'classnames'; +import styles from './RejectButton.css'; +import {Icon} from 'coral-ui'; + +import t from 'coral-framework/services/i18n'; + +const RejectButton = ({active, minimal, onClick}) => { + const text = active ? t('modqueue.rejected') : t('modqueue.reject'); + return ( + + ); +}; + +RejectButton.propTypes = { + active: PropTypes.bool, + minimal: PropTypes.bool, + onClick: PropTypes.func, +}; + +export default RejectButton; + diff --git a/client/coral-admin/src/components/UserDetail.js b/client/coral-admin/src/components/UserDetail.js index b6b239057..a5955af45 100644 --- a/client/coral-admin/src/components/UserDetail.js +++ b/client/coral-admin/src/components/UserDetail.js @@ -5,7 +5,6 @@ import styles from './UserDetail.css'; import {Icon, Button, Drawer, Spinner} from 'coral-ui'; import {Slot} from 'coral-framework/components'; import ButtonCopyToClipboard from './ButtonCopyToClipboard'; -import {actionsMap} from '../utils/moderationQueueActionsMap'; import ClickOutside from 'coral-framework/components/ClickOutside'; import LoadMore from '../components/LoadMore'; import cn from 'classnames'; @@ -70,6 +69,7 @@ export default class UserDetail extends React.Component { renderLoaded() { const { + data, root, root: { user, @@ -177,15 +177,15 @@ export default class UserDetail extends React.Component {
    { nodes.map((comment) => { - const status = comment.action_summaries ? 'FLAGGED' : comment.status; const selected = selectedCommentIds.indexOf(comment.id) !== -1; return (this.props.comment.status === 'ACCEPTED' + ? null + : this.props.acceptComment({commentId: this.props.comment.id}) + ); + + reject = () => (this.props.comment.status === 'REJECTED' + ? null + : this.props.rejectComment({commentId: this.props.comment.id}) + ); + render() { const { - actions = [], comment, - viewUserDetail, suspectWords, bannedWords, selected, toggleSelect, className, - user, - ...props + data, } = this.props; - const flagActions = comment.actions && comment.actions.filter((a) => a.__typename === 'FlagAction'); - return (
  • - {actions.map((action, i) => { - const active = - (action === 'REJECT' && comment.status === 'REJECTED') || - (action === 'APPROVE' && comment.status === 'ACCEPTED'); - return ( - - (comment.status === 'ACCEPTED' - ? null - : props.acceptComment({commentId: comment.id}))} - rejectComment={() => - (comment.status === 'REJECTED' - ? null - : props.rejectComment({commentId: comment.id}))} - /> - ); - })} + +
  • - {flagActions && flagActions.length - ? - : null} + ); } @@ -135,6 +127,8 @@ UserDetailComment.propTypes = { bannedWords: PropTypes.arrayOf(PropTypes.string).isRequired, toggleSelect: PropTypes.func, comment: PropTypes.shape({ + id: PropTypes.string.isRequired, + status: PropTypes.string.isRequired, body: PropTypes.string.isRequired, actions: PropTypes.array, created_at: PropTypes.string.isRequired, diff --git a/client/coral-admin/src/containers/CommentDetails.js b/client/coral-admin/src/containers/CommentDetails.js new file mode 100644 index 000000000..a72a8eee4 --- /dev/null +++ b/client/coral-admin/src/containers/CommentDetails.js @@ -0,0 +1,23 @@ +import {gql} from 'react-apollo'; +import CommentDetails from '../components/CommentDetails'; +import {getSlotFragmentSpreads} from 'coral-framework/utils'; +import withFragments from 'coral-framework/hocs/withFragments'; + +const slots = [ + 'adminCommentDetailArea', +]; + +export default withFragments({ + root: gql` + fragment CoralAdmin_CommentDetails_root on RootQuery { + __typename + ${getSlotFragmentSpreads(slots, 'root')} + } + `, + comment: gql` + fragment CoralAdmin_CommentDetails_comment on Comment { + __typename + ${getSlotFragmentSpreads(slots, 'comment')} + } + ` +})(CommentDetails); diff --git a/client/coral-admin/src/containers/CommentLabels.js b/client/coral-admin/src/containers/CommentLabels.js index af6a0d963..1942d1ad0 100644 --- a/client/coral-admin/src/containers/CommentLabels.js +++ b/client/coral-admin/src/containers/CommentLabels.js @@ -8,6 +8,12 @@ const slots = [ ]; export default withFragments({ + root: gql` + fragment CoralAdmin_CommentLabels_root on RootQuery { + __typename + ${getSlotFragmentSpreads(slots, 'root')} + } + `, comment: gql` fragment CoralAdmin_CommentLabels_comment on Comment { hasParent diff --git a/client/coral-admin/src/containers/UserDetail.js b/client/coral-admin/src/containers/UserDetail.js index 5effb2b84..2ae842b1d 100644 --- a/client/coral-admin/src/containers/UserDetail.js +++ b/client/coral-admin/src/containers/UserDetail.js @@ -160,8 +160,10 @@ export const withUserDetailQuery = withQuery(gql` }) { ...CoralAdmin_Moderation_CommentConnection } + ...${getDefinitionName(UserDetailComment.fragments.root)} ${getSlotFragmentSpreads(slots, 'root')} } + ${UserDetailComment.fragments.root} ${commentConnectionFragment} `, { options: ({userId, statuses}) => { diff --git a/client/coral-admin/src/containers/UserDetailComment.js b/client/coral-admin/src/containers/UserDetailComment.js index 6b3572434..9eef5934f 100644 --- a/client/coral-admin/src/containers/UserDetailComment.js +++ b/client/coral-admin/src/containers/UserDetailComment.js @@ -3,10 +3,20 @@ import UserDetailComment from '../components/UserDetailComment'; import withFragments from 'coral-framework/hocs/withFragments'; import {getDefinitionName} from 'coral-framework/utils'; import CommentLabels from './CommentLabels'; +import CommentDetails from './CommentDetails'; export default withFragments({ + root: gql` + fragment CoralAdmin_UserDetailComment_root on RootQuery { + __typename + ...${getDefinitionName(CommentLabels.fragments.root)} + ...${getDefinitionName(CommentDetails.fragments.root)} + } + ${CommentLabels.fragments.root} + ${CommentDetails.fragments.root} + `, comment: gql` - fragment CoralAdmin_UserDetail_comment on Comment { + fragment CoralAdmin_UserDetailComment_comment on Comment { id body created_at @@ -17,22 +27,13 @@ export default withFragments({ title url } - actions { - ... on FlagAction { - id - reason - message - user { - id - username - } - } - } editing { edited } ...${getDefinitionName(CommentLabels.fragments.comment)} + ...${getDefinitionName(CommentDetails.fragments.comment)} } ${CommentLabels.fragments.comment} + ${CommentDetails.fragments.comment} ` })(UserDetailComment); diff --git a/client/coral-admin/src/routes/Community/components/ActionButton.css b/client/coral-admin/src/routes/Community/components/ActionButton.css deleted file mode 100644 index 8f328e8b8..000000000 --- a/client/coral-admin/src/routes/Community/components/ActionButton.css +++ /dev/null @@ -1,4 +0,0 @@ -.actionButton { - transform: scale(.8); - margin: 0; -} diff --git a/client/coral-admin/src/routes/Community/components/ActionButton.js b/client/coral-admin/src/routes/Community/components/ActionButton.js deleted file mode 100644 index 0ef9b8a39..000000000 --- a/client/coral-admin/src/routes/Community/components/ActionButton.js +++ /dev/null @@ -1,22 +0,0 @@ -import React from 'react'; -import styles from './ActionButton.css'; -import {Button} from 'coral-ui'; -import {menuActionsMap} from '../../../utils/moderationQueueActionsMap'; - -import t from 'coral-framework/services/i18n'; - -// TODO: Needs refactoring. -const ActionButton = ({type = '', user, ...props}) => { - return ( - - ); -}; - -export default ActionButton; diff --git a/client/coral-admin/src/routes/Community/components/FlaggedAccounts.js b/client/coral-admin/src/routes/Community/components/FlaggedAccounts.js index 1d78c015a..e617def53 100644 --- a/client/coral-admin/src/routes/Community/components/FlaggedAccounts.js +++ b/client/coral-admin/src/routes/Community/components/FlaggedAccounts.js @@ -47,7 +47,6 @@ class FlaggedAccounts extends React.Component { this.props.viewUserDetail(this.props.user.id); + showRejectUsernameDialog = () => this.props.showRejectUsernameDialog({id: this.props.user.id}); + approveUser = () => this.props.approveUser({ + userId: this.props.user.id, + }); render() { const { user, - modActionButtons, viewUserDetail, selected, - approveUser, - showRejectUsernameDialog, me, className, } = this.props; @@ -125,14 +126,12 @@ class User extends React.Component {
    - {modActionButtons.map((action, i) => - - )} + +
    diff --git a/client/coral-admin/src/routes/Community/components/RejectUsernameDialog.js b/client/coral-admin/src/routes/Community/components/RejectUsernameDialog.js index a9877368a..20c411e52 100644 --- a/client/coral-admin/src/routes/Community/components/RejectUsernameDialog.js +++ b/client/coral-admin/src/routes/Community/components/RejectUsernameDialog.js @@ -51,7 +51,7 @@ class RejectUsernameDialog extends Component { const next = () => this.setState({stage: stage + 1}); const suspend = async () => { try { - await rejectUsername({id: user.user.id, message: this.state.email}); + await rejectUsername({id: user.id, message: this.state.email}); this.props.handleClose(); } catch (err) { diff --git a/client/coral-admin/src/routes/Community/containers/Community.js b/client/coral-admin/src/routes/Community/containers/Community.js index 4e60c64d7..6e20a3167 100644 --- a/client/coral-admin/src/routes/Community/containers/Community.js +++ b/client/coral-admin/src/routes/Community/containers/Community.js @@ -78,7 +78,11 @@ const withData = withQuery(gql` ${FlaggedAccounts.fragments.root} ${FlaggedUser.fragments.root} ${FlaggedUser.fragments.me} -`); +`, { + options: { + fetchPolicy: 'network-only', + }, +}); export default compose( connect(mapStateToProps, mapDispatchToProps), diff --git a/client/coral-admin/src/routes/Moderation/components/Comment.js b/client/coral-admin/src/routes/Moderation/components/Comment.js index c761ff591..42c9c2d13 100644 --- a/client/coral-admin/src/routes/Moderation/components/Comment.js +++ b/client/coral-admin/src/routes/Moderation/components/Comment.js @@ -8,13 +8,13 @@ import styles from './Comment.css'; import CommentLabels from 'coral-admin/src/components/CommentLabels'; import CommentAnimatedEdit from 'coral-admin/src/components/CommentAnimatedEdit'; import Slot from 'coral-framework/components/Slot'; -import {getActionSummary} from 'coral-framework/utils'; -import ActionButton from 'coral-admin/src/components/ActionButton'; import ActionsMenu from 'coral-admin/src/components/ActionsMenu'; import ActionsMenuItem from 'coral-admin/src/components/ActionsMenuItem'; import CommentBodyHighlighter from 'coral-admin/src/components/CommentBodyHighlighter'; import IfHasLink from 'coral-admin/src/components/IfHasLink'; import cn from 'classnames'; +import ApproveButton from 'coral-admin/src/components/ApproveButton'; +import RejectButton from 'coral-admin/src/components/RejectButton'; import t, {timeago} from 'coral-framework/services/i18n'; @@ -45,11 +45,19 @@ class Comment extends React.Component { return viewUserDetail(comment.user.id); }; + approve = () => (this.props.comment.status === 'ACCEPTED' + ? null + : this.props.acceptComment({commentId: this.props.comment.id}) + ); + + reject = () => (this.props.comment.status === 'REJECTED' + ? null + : this.props.rejectComment({commentId: this.props.comment.id}) + ); + render() { const { - actions = [], comment, - viewUserDetail, suspectWords, bannedWords, selected, @@ -58,15 +66,9 @@ class Comment extends React.Component { root, currentUserId, currentAsset, - acceptComment, - rejectComment, } = this.props; - const flagActionSummaries = getActionSummary('FlagActionSummary', comment); - const flagActions = comment.actions && comment.actions.filter((a) => a.__typename === 'FlagAction'); - const selectionStateCSS = selected ? 'mdl-shadow--16dp' : 'mdl-shadow--2dp'; - const queryData = {root, comment, asset: comment.asset}; return ( @@ -153,28 +155,14 @@ class Comment extends React.Component {
    - {actions.map((action, i) => { - const active = - (action === 'REJECT' && comment.status === 'REJECTED') || - (action === 'APPROVE' && comment.status === 'ACCEPTED'); - return ( - - (comment.status === 'ACCEPTED' - ? null - : acceptComment({commentId: comment.id}))} - rejectComment={() => - (comment.status === 'REJECTED' - ? null - : rejectComment({commentId: comment.id}))} - /> - ); - })} + +
    - {flagActions && flagActions.length - ? - : null} - ); @@ -214,6 +195,8 @@ Comment.propTypes = { showSuspendUserDialog: PropTypes.func.isRequired, currentUserId: PropTypes.string.isRequired, comment: PropTypes.shape({ + id: PropTypes.string.isRequired, + status: PropTypes.string.isRequired, body: PropTypes.string.isRequired, action_summaries: PropTypes.array, actions: PropTypes.array, @@ -230,7 +213,6 @@ Comment.propTypes = { }), data: PropTypes.object.isRequired, root: PropTypes.object.isRequired, - actions: PropTypes.array.isRequired, selected: PropTypes.bool, }; diff --git a/client/coral-admin/src/routes/Moderation/components/ModerationQueue.js b/client/coral-admin/src/routes/Moderation/components/ModerationQueue.js index 517892a77..47ed56925 100644 --- a/client/coral-admin/src/routes/Moderation/components/ModerationQueue.js +++ b/client/coral-admin/src/routes/Moderation/components/ModerationQueue.js @@ -4,7 +4,6 @@ import PropTypes from 'prop-types'; import Comment from '../containers/Comment'; import styles from './ModerationQueue.css'; import EmptyCard from '../../../components/EmptyCard'; -import {actionsMap} from '../../../utils/moderationQueueActionsMap'; import LoadMore from '../../../components/LoadMore'; import ViewMore from './ViewMore'; import t from 'coral-framework/services/i18n'; @@ -140,7 +139,6 @@ class ModerationQueue extends React.Component { if (singleView) { const index = comments.findIndex((comment) => comment.id === selectedCommentId); const comment = comments[index]; - const status = comment.action_summaries ? 'FLAGGED' : comment.status; return (
    { - const status = comment.action_summaries ? 'FLAGGED' : comment.status; return gql` organizationName moderation } + ...${getDefinitionName(Comment.fragments.root)} } + ${Comment.fragments.root} ${commentConnectionFragment} `, { options: (props) => { diff --git a/client/coral-admin/src/utils/moderationQueueActionsMap.js b/client/coral-admin/src/utils/moderationQueueActionsMap.js deleted file mode 100644 index 95b0ecb55..000000000 --- a/client/coral-admin/src/utils/moderationQueueActionsMap.js +++ /dev/null @@ -1,14 +0,0 @@ -export const actionsMap = { - PREMOD: ['APPROVE', 'REJECT'], - FLAGGED: ['APPROVE', 'REJECT'], - REJECTED: ['APPROVE', 'REJECTED'] -}; - -export const menuActionsMap = { - 'REJECT': {status: 'REJECTED', text: 'reject', icon: 'close', key: 'f'}, - 'REJECTED': {status: 'REJECTED', text: 'rejected', icon: 'close'}, - 'APPROVE': {status: 'ACCEPTED', text: 'approve', icon: 'done', key: 'd'}, - 'FLAGGED': {status: 'FLAGGED', text: 'flag', icon: 'flag', filter: 'Untouched'}, - 'BAN': {status: 'BANNED', text: 'ban_user', icon: 'not interested'}, - '': {icon: 'done'} -}; diff --git a/client/coral-ui/components/Button.css b/client/coral-ui/components/Button.css index 1b7efb205..ce2cff350 100644 --- a/client/coral-ui/components/Button.css +++ b/client/coral-ui/components/Button.css @@ -130,59 +130,6 @@ background: #00a291; } -.type--approve { - display: block; - color: #519954; - border: solid 2px rgba(81, 153, 84, 0.75); - background: white; - padding: 10px 12px; - box-sizing: border-box; - vertical-align: middle; - line-height: 24px; - font-size: 17px; - height: 47px; - border-radius: 3px; - text-transform: capitalize; - box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.03), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.09); - width: 129px; - - &:hover { - box-shadow: none; - color: white; - background-color: #519954; - } -} - -.type--reject, .type--rejected { - display: block; - color: #D03235; - border: solid 1px #D03235; - background: white; - padding: 10px 11px; - box-sizing: border-box; - vertical-align: middle; - line-height: 24px; - font-size: 17px; - height: 47px; - border-radius: 3px; - text-transform: capitalize; - box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.03), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.09); - width: 129px; - - &:hover { - color: white; - background-color: #D03235; - box-shadow: none; - } -} - -.type--rejected { - color: white; - background-color: #D03235; - box-shadow: none; - cursor: not-allowed; -} - .type--ban, .type--actions { display: block; color: #616161; diff --git a/plugins/talk-plugin-flag-details/.eslintrc.json b/plugins/talk-plugin-flag-details/.eslintrc.json new file mode 100644 index 000000000..78f7c2397 --- /dev/null +++ b/plugins/talk-plugin-flag-details/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "@coralproject/eslint-config-talk" +} diff --git a/plugins/talk-plugin-flag-details/client/.babelrc b/plugins/talk-plugin-flag-details/client/.babelrc new file mode 100644 index 000000000..60be246eb --- /dev/null +++ b/plugins/talk-plugin-flag-details/client/.babelrc @@ -0,0 +1,14 @@ +{ + "presets": [ + "es2015" + ], + "plugins": [ + "add-module-exports", + "transform-class-properties", + "transform-decorators-legacy", + "transform-object-assign", + "transform-object-rest-spread", + "transform-async-to-generator", + "transform-react-jsx" + ] +} \ No newline at end of file diff --git a/plugins/talk-plugin-flag-details/client/.eslintrc.json b/plugins/talk-plugin-flag-details/client/.eslintrc.json new file mode 100644 index 000000000..c8a6db18a --- /dev/null +++ b/plugins/talk-plugin-flag-details/client/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "@coralproject/eslint-config-talk/client" +} diff --git a/plugins/talk-plugin-flag-details/client/components/FlagDetails.css b/plugins/talk-plugin-flag-details/client/components/FlagDetails.css new file mode 100644 index 000000000..302e24858 --- /dev/null +++ b/plugins/talk-plugin-flag-details/client/components/FlagDetails.css @@ -0,0 +1,43 @@ + +.info { + vertical-align: middle; + list-style: none; + display: inline-block; + padding: 0; + font-size: 12px; +} + +.detail { + padding: 0; + list-style: none; + font-size: 12px; + font-weight: 500; +} + +.subDetail { + margin-left:10px; + padding: 0; + list-style: none; + font-size: 12px; + font-weight: normal; + color: #888; +} + +.lessDetail { + display: inline-block; + margin-right: 10px; +} + +.username { + color: #393B44; + text-decoration: none; + cursor: pointer; + font-weight: 600; + padding: 2px 5px; + border-radius: 2px; + margin-left: -5px; + transition: background-color 200ms ease; + &:hover { + background-color: #E0E0E0; + } +} diff --git a/plugins/talk-plugin-flag-details/client/components/FlagDetails.js b/plugins/talk-plugin-flag-details/client/components/FlagDetails.js new file mode 100644 index 000000000..0d415217d --- /dev/null +++ b/plugins/talk-plugin-flag-details/client/components/FlagDetails.js @@ -0,0 +1,79 @@ +import React, {Component} from 'react'; +import PropTypes from 'prop-types'; +import styles from './FlagDetails.css'; +import {t} from 'plugin-api/beta/client/services'; +import CommentDetail from 'coral-admin/src/components/CommentDetail'; + +class FlagDetails extends Component { + + render() { + const {comment: {actions}, viewUserDetail, more} = this.props; + + const flagActions = actions && actions.filter((a) => a.__typename === 'FlagAction'); + const summaries = flagActions.reduce((sum, action) => { + if (!(action.reason in sum)) { + sum[action.reason] = {count: 0, userFlagged: false, actions: []}; + } + sum[action.reason].count++; + if (action.user) { + sum[action.reason].userFlagged = true; + } + sum[action.reason].actions.push(action); + return sum; + }, {}); + + const userFlagReasons = Object.keys(summaries).filter((reason) => summaries[reason].userFlagged); + + return ( + + {Object.keys(summaries).map((reason) => +
  • + {reason} {summaries[reason].userFlagged && `(${summaries[reason].count})`} +
  • + )} + + }> + {more && userFlagReasons.length > 0 && ( + + )} +
    + ); + } +} + +FlagDetails.propTypes = { + more: PropTypes.bool, + comment: PropTypes.shape({ + actions: PropTypes.arrayOf(PropTypes.shape({ + message: PropTypes.string, + user: PropTypes.shape({username: PropTypes.string}) + })).isRequired, + }).isRequired, + viewUserDetail: PropTypes.func.isRequired, +}; + +export default FlagDetails; diff --git a/plugins/talk-plugin-flag-details/client/containers/FlagDetails.js b/plugins/talk-plugin-flag-details/client/containers/FlagDetails.js new file mode 100644 index 000000000..2ee88d2dd --- /dev/null +++ b/plugins/talk-plugin-flag-details/client/containers/FlagDetails.js @@ -0,0 +1,37 @@ +import {compose, gql} from 'react-apollo'; +import FlagDetails from '../components/FlagDetails'; +import {bindActionCreators} from 'redux'; +import {withFragments, excludeIf} from 'plugin-api/beta/client/hocs'; +import {viewUserDetail} from 'coral-admin/src/actions/userDetail'; +import {connect} from 'react-redux'; + +const mapDispatchToProps = (dispatch) => ({ + ...bindActionCreators({ + viewUserDetail, + }, dispatch) +}); + +const enhance = compose( + connect(null, mapDispatchToProps), + withFragments({ + comment: gql` + fragment CoralAdmin_FlagDetails_comment on Comment { + actions { + __typename + ... on FlagAction { + id + reason + message + user { + id + username + } + } + } + } + ` + }), + excludeIf(({comment: {actions}}) => !actions.some((action) => action.__typename === 'FlagAction')), +); + +export default enhance(FlagDetails); diff --git a/plugins/talk-plugin-flag-details/client/index.js b/plugins/talk-plugin-flag-details/client/index.js new file mode 100644 index 000000000..045194872 --- /dev/null +++ b/plugins/talk-plugin-flag-details/client/index.js @@ -0,0 +1,9 @@ +import FlagDetails from './containers/FlagDetails'; +import translations from './translations.yml'; + +export default { + translations, + slots: { + adminCommentDetailArea: [FlagDetails], + } +}; diff --git a/plugins/talk-plugin-flag-details/client/translations.yml b/plugins/talk-plugin-flag-details/client/translations.yml new file mode 100644 index 000000000..3b2511025 --- /dev/null +++ b/plugins/talk-plugin-flag-details/client/translations.yml @@ -0,0 +1,3 @@ +en: + talk-plugin-fag-details: + diff --git a/plugins/talk-plugin-flag-details/index.js b/plugins/talk-plugin-flag-details/index.js new file mode 100644 index 000000000..f053ebf79 --- /dev/null +++ b/plugins/talk-plugin-flag-details/index.js @@ -0,0 +1 @@ +module.exports = {}; diff --git a/plugins/talk-plugin-toxic-comments/client/containers/ToxicDetail.js b/plugins/talk-plugin-toxic-comments/client/containers/ToxicDetail.js index 32b83fbb3..28f75de37 100644 --- a/plugins/talk-plugin-toxic-comments/client/containers/ToxicDetail.js +++ b/plugins/talk-plugin-toxic-comments/client/containers/ToxicDetail.js @@ -15,7 +15,7 @@ const enhance = compose( } }`, }), - excludeIf(({comment: {toxicity}}) => toxicity === null), + excludeIf(({comment: {toxicity}, more}) => !more || toxicity === null), ); export default enhance(ToxicDetail); From 90470b8331292fd235f9ecd77aea71d6f4533442 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Fri, 29 Sep 2017 23:33:12 +0700 Subject: [PATCH 04/17] Make IfSlotIsEmpty and IfSloIsNotEmpty accept an array of slot names --- client/coral-framework/components/IfSlotIsEmpty.js | 7 ++++--- client/coral-framework/components/IfSlotIsNotEmpty.js | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/client/coral-framework/components/IfSlotIsEmpty.js b/client/coral-framework/components/IfSlotIsEmpty.js index 72dc8c988..51a849448 100644 --- a/client/coral-framework/components/IfSlotIsEmpty.js +++ b/client/coral-framework/components/IfSlotIsEmpty.js @@ -23,8 +23,9 @@ class IfSlotIsEmpty extends React.Component { } isSlotEmpty(props = this.props) { - const {slot, className: _a, reduxState, component: _b = 'div', children: _c, ...rest} = props; - return this.context.plugins.isSlotEmpty(slot, reduxState, rest); + const {slot, className: _a, reduxState, component: _b = 'div', children: _c, queryData, ...rest} = props; + const slots = Array.isArray(slot) ? slot : [slot]; + return slots.every((slot) => this.context.plugins.isSlotEmpty(slot, reduxState, rest, queryData)); } render() { @@ -34,7 +35,7 @@ class IfSlotIsEmpty extends React.Component { } IfSlotIsEmpty.propTypes = { - slot: PropTypes.string, + slot: PropTypes.oneOfType([PropTypes.string, PropTypes.array]), }; const mapStateToProps = (state) => ({ diff --git a/client/coral-framework/components/IfSlotIsNotEmpty.js b/client/coral-framework/components/IfSlotIsNotEmpty.js index 46e68fe60..6186e2166 100644 --- a/client/coral-framework/components/IfSlotIsNotEmpty.js +++ b/client/coral-framework/components/IfSlotIsNotEmpty.js @@ -23,8 +23,9 @@ class IfSlotIsNotEmpty extends React.Component { } isSlotEmpty(props = this.props) { - const {slot, className: _a, reduxState, component: _b = 'div', children: _c, ...rest} = props; - return this.context.plugins.isSlotEmpty(slot, reduxState, rest); + const {slot, className: _a, reduxState, component: _b = 'div', children: _c, queryData, ...rest} = props; + const slots = Array.isArray(slot) ? slot : [slot]; + return slots.every((slot) => this.context.plugins.isSlotEmpty(slot, reduxState, rest, queryData)); } render() { @@ -34,7 +35,7 @@ class IfSlotIsNotEmpty extends React.Component { } IfSlotIsNotEmpty.propTypes = { - slot: PropTypes.string, + slot: PropTypes.oneOfType([PropTypes.string, PropTypes.array]), }; const mapStateToProps = (state) => ({ From 9bd55b267e3d6b10400709efdb2616c0063b3a9b Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Fri, 29 Sep 2017 23:33:37 +0700 Subject: [PATCH 05/17] excludeIf now returns a new component --- client/coral-framework/hocs/excludeIf.js | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/client/coral-framework/hocs/excludeIf.js b/client/coral-framework/hocs/excludeIf.js index ec2f0f27a..524c97eb3 100644 --- a/client/coral-framework/hocs/excludeIf.js +++ b/client/coral-framework/hocs/excludeIf.js @@ -1,4 +1,19 @@ -export default (condition) => (BaseComponent) => { - BaseComponent.isExcluded = condition; - return BaseComponent; -}; +import React from 'react'; +import hoistStatics from 'recompose/hoistStatics'; + +/** + * ExcludeIf provides a property `emit: (eventName, value)` + * to the wrapped component. + */ +export default (condition) => hoistStatics((WrappedComponent) => { + class ExcludeIf extends React.Component { + render() { + return ; + } + } + + WrappedComponent.isExcluded = condition; + return ExcludeIf; +}); From 7d41421526eb7e826f042ca5781a34efd7019185 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Fri, 29 Sep 2017 23:34:40 +0700 Subject: [PATCH 06/17] adminCommentMoreFlagDetails slot and more --- .../src/components/CommentDetail.css | 5 +- .../src/components/CommentDetails.css | 4 +- .../src/components/CommentDetails.js | 15 +++- .../src/components/FlagDetails.css | 43 ----------- .../coral-admin/src/components/FlagDetails.js | 75 ------------------- .../src/components/UserDetailComment.css | 1 + .../src/components/UserDetailComment.js | 4 +- .../src/containers/CommentDetails.js | 1 + .../routes/Moderation/components/Comment.css | 1 + .../client/components/FlagDetails.css | 2 + .../client/components/FlagDetails.js | 20 ++++- .../client/containers/FlagDetails.js | 12 +++ .../client/containers/ToxicCommentDetail.js | 10 +++ .../containers/ToxicCommentFlagDetail.js | 10 +++ .../client/containers/ToxicDetail.js | 3 +- .../client/index.js | 6 +- 16 files changed, 83 insertions(+), 129 deletions(-) delete mode 100644 client/coral-admin/src/components/FlagDetails.css delete mode 100644 client/coral-admin/src/components/FlagDetails.js create mode 100644 plugins/talk-plugin-toxic-comments/client/containers/ToxicCommentDetail.js create mode 100644 plugins/talk-plugin-toxic-comments/client/containers/ToxicCommentFlagDetail.js diff --git a/client/coral-admin/src/components/CommentDetail.css b/client/coral-admin/src/components/CommentDetail.css index 259d4e1c5..4806b9522 100644 --- a/client/coral-admin/src/components/CommentDetail.css +++ b/client/coral-admin/src/components/CommentDetail.css @@ -1,5 +1,4 @@ .root { - margin-left: 16px; } .headerContainer { @@ -25,6 +24,10 @@ .details { padding: 0 20px 16px; font-size: 12px; + + &:empty { + display: none; + } } .icon { diff --git a/client/coral-admin/src/components/CommentDetails.css b/client/coral-admin/src/components/CommentDetails.css index ff3679cc7..c34a32cb3 100644 --- a/client/coral-admin/src/components/CommentDetails.css +++ b/client/coral-admin/src/components/CommentDetails.css @@ -1,6 +1,6 @@ .root { - margin-top: 10px; - padding-top: 10px; + min-height: 24px; + padding: 0 16px; } .moreDetail { diff --git a/client/coral-admin/src/components/CommentDetails.js b/client/coral-admin/src/components/CommentDetails.js index d984ce0c1..cd504a40f 100644 --- a/client/coral-admin/src/components/CommentDetails.js +++ b/client/coral-admin/src/components/CommentDetails.js @@ -3,6 +3,7 @@ import PropTypes from 'prop-types'; import styles from './CommentDetails.css'; import t from 'coral-framework/services/i18n'; import Slot from 'coral-framework/components/Slot'; +import IfSlotIsNotEmpty from 'coral-framework/components/IfSlotIsNotEmpty'; class CommentDetails extends Component { state = { @@ -32,13 +33,25 @@ class CommentDetails extends Component { return ( ); } diff --git a/client/coral-admin/src/components/FlagDetails.css b/client/coral-admin/src/components/FlagDetails.css deleted file mode 100644 index 302e24858..000000000 --- a/client/coral-admin/src/components/FlagDetails.css +++ /dev/null @@ -1,43 +0,0 @@ - -.info { - vertical-align: middle; - list-style: none; - display: inline-block; - padding: 0; - font-size: 12px; -} - -.detail { - padding: 0; - list-style: none; - font-size: 12px; - font-weight: 500; -} - -.subDetail { - margin-left:10px; - padding: 0; - list-style: none; - font-size: 12px; - font-weight: normal; - color: #888; -} - -.lessDetail { - display: inline-block; - margin-right: 10px; -} - -.username { - color: #393B44; - text-decoration: none; - cursor: pointer; - font-weight: 600; - padding: 2px 5px; - border-radius: 2px; - margin-left: -5px; - transition: background-color 200ms ease; - &:hover { - background-color: #E0E0E0; - } -} diff --git a/client/coral-admin/src/components/FlagDetails.js b/client/coral-admin/src/components/FlagDetails.js deleted file mode 100644 index 74bff8f24..000000000 --- a/client/coral-admin/src/components/FlagDetails.js +++ /dev/null @@ -1,75 +0,0 @@ -import React, {Component} from 'react'; -import PropTypes from 'prop-types'; -import styles from './FlagDetails.css'; -import t from 'coral-framework/services/i18n'; -import CommentDetail from './CommentDetail'; - -class FlagDetails extends Component { - - render() { - const {actions, viewUserDetail, more} = this.props; - const summaries = actions.reduce((sum, action) => { - if (!(action.reason in sum)) { - sum[action.reason] = {count: 0, userFlagged: false, actions: []}; - } - sum[action.reason].count++; - if (action.user) { - sum[action.reason].userFlagged = true; - } - sum[action.reason].actions.push(action); - return sum; - }, {}); - - const userFlagReasons = Object.keys(summaries).filter((reason) => summaries[reason].userFlagged); - - return ( - - {Object.keys(summaries).map((reason) => -
  • - {reason} {summaries[reason].userFlagged && `(${summaries[reason].count})`} -
  • - )} - - }> - {more && userFlagReasons.length > 0 && ( - - )} -
    - ); - } -} - -FlagDetails.propTypes = { - more: PropTypes.bool, - actions: PropTypes.arrayOf(PropTypes.shape({ - message: PropTypes.string, - user: PropTypes.shape({username: PropTypes.string}) - })).isRequired, - viewUserDetail: PropTypes.func.isRequired, -}; - -export default FlagDetails; diff --git a/client/coral-admin/src/components/UserDetailComment.css b/client/coral-admin/src/components/UserDetailComment.css index d1e2b007a..50e37e28e 100644 --- a/client/coral-admin/src/components/UserDetailComment.css +++ b/client/coral-admin/src/components/UserDetailComment.css @@ -1,4 +1,5 @@ .root { + position: relative; display: block; margin: 0; border-bottom: 1px solid #e0e0e0; diff --git a/client/coral-admin/src/components/UserDetailComment.js b/client/coral-admin/src/components/UserDetailComment.js index 29f3242a1..f8d81ce8b 100644 --- a/client/coral-admin/src/components/UserDetailComment.js +++ b/client/coral-admin/src/components/UserDetailComment.js @@ -70,7 +70,7 @@ class UserDetailComment extends React.Component {
    -

    +

    {t('comment.view_context')} -

    +
    diff --git a/client/coral-admin/src/containers/CommentDetails.js b/client/coral-admin/src/containers/CommentDetails.js index a72a8eee4..cf8c2c307 100644 --- a/client/coral-admin/src/containers/CommentDetails.js +++ b/client/coral-admin/src/containers/CommentDetails.js @@ -5,6 +5,7 @@ import withFragments from 'coral-framework/hocs/withFragments'; const slots = [ 'adminCommentDetailArea', + 'adminCommentMoreDetails', ]; export default withFragments({ diff --git a/client/coral-admin/src/routes/Moderation/components/Comment.css b/client/coral-admin/src/routes/Moderation/components/Comment.css index a1862640f..10cc707fb 100644 --- a/client/coral-admin/src/routes/Moderation/components/Comment.css +++ b/client/coral-admin/src/routes/Moderation/components/Comment.css @@ -58,6 +58,7 @@ font-size: 14px; line-height: 1.5; font-weight: 300; + margin-bottom: 8px; } .body { diff --git a/plugins/talk-plugin-flag-details/client/components/FlagDetails.css b/plugins/talk-plugin-flag-details/client/components/FlagDetails.css index 302e24858..3b59653c2 100644 --- a/plugins/talk-plugin-flag-details/client/components/FlagDetails.css +++ b/plugins/talk-plugin-flag-details/client/components/FlagDetails.css @@ -5,9 +5,11 @@ display: inline-block; padding: 0; font-size: 12px; + margin: 0; } .detail { + margin: 0; padding: 0; list-style: none; font-size: 12px; diff --git a/plugins/talk-plugin-flag-details/client/components/FlagDetails.js b/plugins/talk-plugin-flag-details/client/components/FlagDetails.js index 0d415217d..eadd779d9 100644 --- a/plugins/talk-plugin-flag-details/client/components/FlagDetails.js +++ b/plugins/talk-plugin-flag-details/client/components/FlagDetails.js @@ -3,11 +3,12 @@ import PropTypes from 'prop-types'; import styles from './FlagDetails.css'; import {t} from 'plugin-api/beta/client/services'; import CommentDetail from 'coral-admin/src/components/CommentDetail'; +import {Slot, IfSlotIsNotEmpty} from 'plugin-api/beta/client/components'; class FlagDetails extends Component { render() { - const {comment: {actions}, viewUserDetail, more} = this.props; + const {comment: {actions}, viewUserDetail, more, data, root, comment} = this.props; const flagActions = actions && actions.filter((a) => a.__typename === 'FlagAction'); const summaries = flagActions.reduce((sum, action) => { @@ -24,6 +25,11 @@ class FlagDetails extends Component { const userFlagReasons = Object.keys(summaries).filter((reason) => summaries[reason].userFlagged); + const queryData = { + root, + comment, + }; + return ( )} + {more && ( + + + + )} ); } diff --git a/plugins/talk-plugin-flag-details/client/containers/FlagDetails.js b/plugins/talk-plugin-flag-details/client/containers/FlagDetails.js index 2ee88d2dd..5c22e66d5 100644 --- a/plugins/talk-plugin-flag-details/client/containers/FlagDetails.js +++ b/plugins/talk-plugin-flag-details/client/containers/FlagDetails.js @@ -4,6 +4,11 @@ import {bindActionCreators} from 'redux'; import {withFragments, excludeIf} from 'plugin-api/beta/client/hocs'; import {viewUserDetail} from 'coral-admin/src/actions/userDetail'; import {connect} from 'react-redux'; +import {getSlotFragmentSpreads} from 'plugin-api/beta/client/utils'; + +const slots = [ + 'adminCommentMoreFlagDetails', +]; const mapDispatchToProps = (dispatch) => ({ ...bindActionCreators({ @@ -14,6 +19,12 @@ const mapDispatchToProps = (dispatch) => ({ const enhance = compose( connect(null, mapDispatchToProps), withFragments({ + root: gql` + fragment CoralAdmin_FlagDetails_root on RootQuery { + __typename + ${getSlotFragmentSpreads(slots, 'root')} + } + `, comment: gql` fragment CoralAdmin_FlagDetails_comment on Comment { actions { @@ -28,6 +39,7 @@ const enhance = compose( } } } + ${getSlotFragmentSpreads(slots, 'comment')} } ` }), diff --git a/plugins/talk-plugin-toxic-comments/client/containers/ToxicCommentDetail.js b/plugins/talk-plugin-toxic-comments/client/containers/ToxicCommentDetail.js new file mode 100644 index 000000000..5c98fc29d --- /dev/null +++ b/plugins/talk-plugin-toxic-comments/client/containers/ToxicCommentDetail.js @@ -0,0 +1,10 @@ +import {compose} from 'react-apollo'; +import {excludeIf} from 'plugin-api/beta/client/hocs'; +import ToxicDetail from './ToxicDetail'; +import {isToxic} from '../utils'; + +const enhance = compose( + excludeIf(({comment: {toxicity, actions}}) => toxicity === null || isToxic(actions)), +); + +export default enhance(ToxicDetail); diff --git a/plugins/talk-plugin-toxic-comments/client/containers/ToxicCommentFlagDetail.js b/plugins/talk-plugin-toxic-comments/client/containers/ToxicCommentFlagDetail.js new file mode 100644 index 000000000..a43501ea4 --- /dev/null +++ b/plugins/talk-plugin-toxic-comments/client/containers/ToxicCommentFlagDetail.js @@ -0,0 +1,10 @@ +import {compose} from 'react-apollo'; +import {excludeIf} from 'plugin-api/beta/client/hocs'; +import ToxicDetail from './ToxicDetail'; +import {isToxic} from '../utils'; + +const enhance = compose( + excludeIf(({comment: {toxicity, actions}}) => toxicity === null || !isToxic(actions)), +); + +export default enhance(ToxicDetail); diff --git a/plugins/talk-plugin-toxic-comments/client/containers/ToxicDetail.js b/plugins/talk-plugin-toxic-comments/client/containers/ToxicDetail.js index 28f75de37..78681261a 100644 --- a/plugins/talk-plugin-toxic-comments/client/containers/ToxicDetail.js +++ b/plugins/talk-plugin-toxic-comments/client/containers/ToxicDetail.js @@ -1,5 +1,5 @@ import {compose, gql} from 'react-apollo'; -import {withFragments, excludeIf} from 'plugin-api/beta/client/hocs'; +import {withFragments} from 'plugin-api/beta/client/hocs'; import ToxicDetail from '../components/ToxicDetail'; const enhance = compose( @@ -15,7 +15,6 @@ const enhance = compose( } }`, }), - excludeIf(({comment: {toxicity}, more}) => !more || toxicity === null), ); export default enhance(ToxicDetail); diff --git a/plugins/talk-plugin-toxic-comments/client/index.js b/plugins/talk-plugin-toxic-comments/client/index.js index 1db520891..742e002d1 100644 --- a/plugins/talk-plugin-toxic-comments/client/index.js +++ b/plugins/talk-plugin-toxic-comments/client/index.js @@ -1,13 +1,15 @@ import translations from './translations.yml'; import CheckToxicityHook from './containers/CheckToxicityHook'; import ToxicLabel from './containers/ToxicLabel'; -import ToxicDetail from './containers/ToxicDetail'; +import ToxicCommentDetail from './containers/ToxicCommentDetail'; +import ToxicCommentFlagDetail from './containers/ToxicCommentFlagDetail'; export default { translations, slots: { commentInputDetailArea: [CheckToxicityHook], adminCommentLabels: [ToxicLabel], - adminCommentDetailArea: [ToxicDetail], + adminCommentMoreDetails: [ToxicCommentDetail], + adminCommentMoreFlagDetails: [ToxicCommentFlagDetail], }, }; From 43cb0efe7e31bbd30f317115067e57813de19784 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Mon, 2 Oct 2017 01:03:20 -0300 Subject: [PATCH 07/17] bug: usertags --- .../coral-embed-stream/src/graphql/index.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/client/coral-embed-stream/src/graphql/index.js b/client/coral-embed-stream/src/graphql/index.js index 20ed8a1d6..228efb25b 100644 --- a/client/coral-embed-stream/src/graphql/index.js +++ b/client/coral-embed-stream/src/graphql/index.js @@ -96,6 +96,11 @@ export default { user { id username + tags { + tag { + name + } + } } action_summaries { count @@ -129,7 +134,19 @@ export default { user: { __typename: 'User', id: auth.user.id, - username: auth.user.username + username: auth.user.username, + tags: tags.map((tag) => ({ + tag: { + name: tag, + created_at: new Date().toISOString(), + __typename: 'Tag' + }, + assigned_by: { + id: auth.user.id, + __typename: 'User' + }, + __typename: 'TagLink' + })), }, created_at: new Date().toISOString(), body, From 7aaad6ccd9078443fed94312ddedecc8a32b4e3f Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Mon, 2 Oct 2017 01:06:08 -0300 Subject: [PATCH 08/17] Adds subscriber plugin --- .eslintignore | 1 + .gitignore | 1 + .../talk-plugin-subscriber/client/.babelrc | 14 +++++++++++ .../client/.eslintrc.json | 23 ++++++++++++++++++ .../client/components/SubscriberBadge.css | 12 ++++++++++ .../client/components/SubscriberBadge.js | 9 +++++++ .../client/containers/SubscriberBadge.js | 24 +++++++++++++++++++ .../talk-plugin-subscriber/client/index.js | 10 ++++++++ .../client/translations.yml | 6 +++++ plugins/talk-plugin-subscriber/index.js | 14 +++++++++++ plugins/talk-plugin-subscriber/package.json | 11 +++++++++ plugins/talk-plugin-subscriber/yarn.lock | 11 +++++++++ 12 files changed, 136 insertions(+) create mode 100644 plugins/talk-plugin-subscriber/client/.babelrc create mode 100644 plugins/talk-plugin-subscriber/client/.eslintrc.json create mode 100644 plugins/talk-plugin-subscriber/client/components/SubscriberBadge.css create mode 100644 plugins/talk-plugin-subscriber/client/components/SubscriberBadge.js create mode 100644 plugins/talk-plugin-subscriber/client/containers/SubscriberBadge.js create mode 100644 plugins/talk-plugin-subscriber/client/index.js create mode 100644 plugins/talk-plugin-subscriber/client/translations.yml create mode 100644 plugins/talk-plugin-subscriber/index.js create mode 100644 plugins/talk-plugin-subscriber/package.json create mode 100644 plugins/talk-plugin-subscriber/yarn.lock diff --git a/.eslintignore b/.eslintignore index fc0214dd2..a5f6aa1a2 100644 --- a/.eslintignore +++ b/.eslintignore @@ -26,5 +26,6 @@ plugins/* !plugins/talk-plugin-toxic-comments !plugins/talk-plugin-remember-sort !plugins/talk-plugin-deep-reply-count +!plugins/talk-plugin-subscriber node_modules diff --git a/.gitignore b/.gitignore index bcc7c89b1..7ccad87c4 100644 --- a/.gitignore +++ b/.gitignore @@ -43,5 +43,6 @@ plugins/* !plugins/talk-plugin-toxic-comments !plugins/talk-plugin-remember-sort !plugins/talk-plugin-deep-reply-count +!plugins/talk-plugin-subscriber **/node_modules/* diff --git a/plugins/talk-plugin-subscriber/client/.babelrc b/plugins/talk-plugin-subscriber/client/.babelrc new file mode 100644 index 000000000..60be246eb --- /dev/null +++ b/plugins/talk-plugin-subscriber/client/.babelrc @@ -0,0 +1,14 @@ +{ + "presets": [ + "es2015" + ], + "plugins": [ + "add-module-exports", + "transform-class-properties", + "transform-decorators-legacy", + "transform-object-assign", + "transform-object-rest-spread", + "transform-async-to-generator", + "transform-react-jsx" + ] +} \ No newline at end of file diff --git a/plugins/talk-plugin-subscriber/client/.eslintrc.json b/plugins/talk-plugin-subscriber/client/.eslintrc.json new file mode 100644 index 000000000..9fe56bd14 --- /dev/null +++ b/plugins/talk-plugin-subscriber/client/.eslintrc.json @@ -0,0 +1,23 @@ +{ + "env": { + "browser": true, + "es6": true, + "mocha": true + }, + "parserOptions": { + "sourceType": "module", + "ecmaFeatures": { + "experimentalObjectRestSpread": true, + "jsx": true + } + }, + "parser": "babel-eslint", + "plugins": [ + "react" + ], + "rules": { + "react/jsx-uses-react": "error", + "react/jsx-uses-vars": "error", + "no-console": ["warn", { "allow": ["warn", "error"] }] + } +} diff --git a/plugins/talk-plugin-subscriber/client/components/SubscriberBadge.css b/plugins/talk-plugin-subscriber/client/components/SubscriberBadge.css new file mode 100644 index 000000000..42edfd8ff --- /dev/null +++ b/plugins/talk-plugin-subscriber/client/components/SubscriberBadge.css @@ -0,0 +1,12 @@ +.badge { + background-color: #616161; + color: white; + display: inline-block; + margin: 0px 5px; + padding: 5px 5px; + border-radius: 2px; + font-size: 12px; + text-transform: uppercase; + letter-spacing: 0.6px; + font-weight: bold; +} \ No newline at end of file diff --git a/plugins/talk-plugin-subscriber/client/components/SubscriberBadge.js b/plugins/talk-plugin-subscriber/client/components/SubscriberBadge.js new file mode 100644 index 000000000..60fe19dc9 --- /dev/null +++ b/plugins/talk-plugin-subscriber/client/components/SubscriberBadge.js @@ -0,0 +1,9 @@ +import React from 'react'; +import styles from './SubscriberBadge.css'; +import {t} from 'plugin-api/beta/client/services'; + +export default () =>( + + {t('talk-plugin-subscriber.subscriber')} + +); diff --git a/plugins/talk-plugin-subscriber/client/containers/SubscriberBadge.js b/plugins/talk-plugin-subscriber/client/containers/SubscriberBadge.js new file mode 100644 index 000000000..a0789cf04 --- /dev/null +++ b/plugins/talk-plugin-subscriber/client/containers/SubscriberBadge.js @@ -0,0 +1,24 @@ +import React from 'react'; +import SubscriberBadge from '../components/SubscriberBadge'; +import {compose, gql} from 'react-apollo'; +import {withFragments, excludeIf} from 'plugin-api/beta/client/hocs'; + +const isSubscriber = (tags = []) => tags.some((t) => t.tag.name === 'SUBSCRIBER'); + +const enhance = compose( + withFragments({ + comment: gql` + fragment TalkSubscriberBadge_SubscriberBadge_comment on Comment { + user { + tags { + tag { + name + } + } + } + }` + }), + excludeIf(({comment}) => !isSubscriber(comment.user.tags)) +); + +export default enhance(SubscriberBadge); diff --git a/plugins/talk-plugin-subscriber/client/index.js b/plugins/talk-plugin-subscriber/client/index.js new file mode 100644 index 000000000..c01d84620 --- /dev/null +++ b/plugins/talk-plugin-subscriber/client/index.js @@ -0,0 +1,10 @@ +import SubscriberBadge from './containers/SubscriberBadge'; +import translations from './translations.yml'; +import {gql} from 'react-apollo'; + +export default { + translations, + slots: { + commentAuthorTags: [SubscriberBadge] + } +}; \ No newline at end of file diff --git a/plugins/talk-plugin-subscriber/client/translations.yml b/plugins/talk-plugin-subscriber/client/translations.yml new file mode 100644 index 000000000..851f818b7 --- /dev/null +++ b/plugins/talk-plugin-subscriber/client/translations.yml @@ -0,0 +1,6 @@ +en: + talk-plugin-subscriber: + subscriber: "Subscriber" +es: + talk-plugin-subscriber: + subscriber: "Subscriptor" diff --git a/plugins/talk-plugin-subscriber/index.js b/plugins/talk-plugin-subscriber/index.js new file mode 100644 index 000000000..ad47ef264 --- /dev/null +++ b/plugins/talk-plugin-subscriber/index.js @@ -0,0 +1,14 @@ +module.exports = { + tags: [ + { + name: 'SUBSCRIBER', + permissions: { + public: true, + self: false, + roles: [] + }, + models: ['USERS'], + created_at: new Date() + } + ] +}; diff --git a/plugins/talk-plugin-subscriber/package.json b/plugins/talk-plugin-subscriber/package.json new file mode 100644 index 000000000..4725abb9e --- /dev/null +++ b/plugins/talk-plugin-subscriber/package.json @@ -0,0 +1,11 @@ +{ + "name": "@coralproject/talk-plugin-subscriber", + "version": "0.1.0", + "description": "A Recipe to display a user badge", + "main": "index.js", + "author": "The Coral Project Team ", + "license": "Apache-2.0", + "dependencies": { + "moment": "^2.18.1" + } +} \ No newline at end of file diff --git a/plugins/talk-plugin-subscriber/yarn.lock b/plugins/talk-plugin-subscriber/yarn.lock new file mode 100644 index 000000000..60fdd97df --- /dev/null +++ b/plugins/talk-plugin-subscriber/yarn.lock @@ -0,0 +1,11 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +moment@^2.18.1: + version "2.18.1" + resolved "https://registry.yarnpkg.com/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f" + +momentjs@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/momentjs/-/momentjs-2.0.0.tgz#73df904b4fa418f6e3c605e831cef6ed5518ebd4" From 02dff0c7263701811529f321685f4669fe888059 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Mon, 2 Oct 2017 01:32:36 -0300 Subject: [PATCH 09/17] linting --- .../client/containers/SubscriberBadge.js | 1 - plugins/talk-plugin-subscriber/client/index.js | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/plugins/talk-plugin-subscriber/client/containers/SubscriberBadge.js b/plugins/talk-plugin-subscriber/client/containers/SubscriberBadge.js index a0789cf04..d00e5fc05 100644 --- a/plugins/talk-plugin-subscriber/client/containers/SubscriberBadge.js +++ b/plugins/talk-plugin-subscriber/client/containers/SubscriberBadge.js @@ -1,4 +1,3 @@ -import React from 'react'; import SubscriberBadge from '../components/SubscriberBadge'; import {compose, gql} from 'react-apollo'; import {withFragments, excludeIf} from 'plugin-api/beta/client/hocs'; diff --git a/plugins/talk-plugin-subscriber/client/index.js b/plugins/talk-plugin-subscriber/client/index.js index c01d84620..937191d41 100644 --- a/plugins/talk-plugin-subscriber/client/index.js +++ b/plugins/talk-plugin-subscriber/client/index.js @@ -1,10 +1,9 @@ import SubscriberBadge from './containers/SubscriberBadge'; import translations from './translations.yml'; -import {gql} from 'react-apollo'; export default { translations, slots: { commentAuthorTags: [SubscriberBadge] } -}; \ No newline at end of file +}; From 075d62a32a56356d5514f6ef59b7bc83a44c9652 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 2 Oct 2017 20:50:43 +0700 Subject: [PATCH 10/17] Move CommentDetails to plugin-api --- .../src => coral-framework}/components/CommentDetail.css | 0 .../src => coral-framework}/components/CommentDetail.js | 0 plugin-api/beta/client/components/index.js | 1 + .../talk-plugin-flag-details/client/components/FlagDetails.js | 3 +-- .../client/components/ToxicDetail.js | 2 +- 5 files changed, 3 insertions(+), 3 deletions(-) rename client/{coral-admin/src => coral-framework}/components/CommentDetail.css (100%) rename client/{coral-admin/src => coral-framework}/components/CommentDetail.js (100%) diff --git a/client/coral-admin/src/components/CommentDetail.css b/client/coral-framework/components/CommentDetail.css similarity index 100% rename from client/coral-admin/src/components/CommentDetail.css rename to client/coral-framework/components/CommentDetail.css diff --git a/client/coral-admin/src/components/CommentDetail.js b/client/coral-framework/components/CommentDetail.js similarity index 100% rename from client/coral-admin/src/components/CommentDetail.js rename to client/coral-framework/components/CommentDetail.js diff --git a/plugin-api/beta/client/components/index.js b/plugin-api/beta/client/components/index.js index a0ae0f3da..b87dec73b 100644 --- a/plugin-api/beta/client/components/index.js +++ b/plugin-api/beta/client/components/index.js @@ -4,3 +4,4 @@ export {default as IfSlotIsEmpty} from 'coral-framework/components/IfSlotIsEmpty export {default as IfSlotIsNotEmpty} from 'coral-framework/components/IfSlotIsNotEmpty'; export {default as CommentAuthorName} from 'coral-framework/components/CommentAuthorName'; export {default as CommentTimestamp} from 'coral-framework/components/CommentTimestamp'; +export {default as CommentDetail} from 'coral-framework/components/CommentDetail'; diff --git a/plugins/talk-plugin-flag-details/client/components/FlagDetails.js b/plugins/talk-plugin-flag-details/client/components/FlagDetails.js index eadd779d9..3b1f222da 100644 --- a/plugins/talk-plugin-flag-details/client/components/FlagDetails.js +++ b/plugins/talk-plugin-flag-details/client/components/FlagDetails.js @@ -2,8 +2,7 @@ import React, {Component} from 'react'; import PropTypes from 'prop-types'; import styles from './FlagDetails.css'; import {t} from 'plugin-api/beta/client/services'; -import CommentDetail from 'coral-admin/src/components/CommentDetail'; -import {Slot, IfSlotIsNotEmpty} from 'plugin-api/beta/client/components'; +import {Slot, IfSlotIsNotEmpty, CommentDetail} from 'plugin-api/beta/client/components'; class FlagDetails extends Component { diff --git a/plugins/talk-plugin-toxic-comments/client/components/ToxicDetail.js b/plugins/talk-plugin-toxic-comments/client/components/ToxicDetail.js index de8a0337c..3726d2b77 100644 --- a/plugins/talk-plugin-toxic-comments/client/components/ToxicDetail.js +++ b/plugins/talk-plugin-toxic-comments/client/components/ToxicDetail.js @@ -1,5 +1,5 @@ import React from 'react'; -import CommentDetail from 'coral-admin/src/components/CommentDetail'; +import {CommentDetail} from 'plugin-api/beta/client/components'; import {isToxic} from '../utils'; import styles from './ToxicDetail.css'; import cn from 'classnames'; From 9b39017f25b2d6671036ec64e275a12e7eb54737 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 2 Oct 2017 20:54:49 +0700 Subject: [PATCH 11/17] Export viewUserDetail in plugin-api --- plugin-api/beta/client/actions/admin.js | 1 + .../talk-plugin-flag-details/client/containers/FlagDetails.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 plugin-api/beta/client/actions/admin.js diff --git a/plugin-api/beta/client/actions/admin.js b/plugin-api/beta/client/actions/admin.js new file mode 100644 index 000000000..2a32e57bf --- /dev/null +++ b/plugin-api/beta/client/actions/admin.js @@ -0,0 +1 @@ +export {viewUserDetail} from 'coral-admin/src/actions/userDetail'; diff --git a/plugins/talk-plugin-flag-details/client/containers/FlagDetails.js b/plugins/talk-plugin-flag-details/client/containers/FlagDetails.js index 5c22e66d5..5a9bb3cae 100644 --- a/plugins/talk-plugin-flag-details/client/containers/FlagDetails.js +++ b/plugins/talk-plugin-flag-details/client/containers/FlagDetails.js @@ -2,7 +2,7 @@ import {compose, gql} from 'react-apollo'; import FlagDetails from '../components/FlagDetails'; import {bindActionCreators} from 'redux'; import {withFragments, excludeIf} from 'plugin-api/beta/client/hocs'; -import {viewUserDetail} from 'coral-admin/src/actions/userDetail'; +import {viewUserDetail} from 'plugin-api/beta/client/actions/admin'; import {connect} from 'react-redux'; import {getSlotFragmentSpreads} from 'plugin-api/beta/client/utils'; From c2f22bbf98a5abc284f7e1ecdfe669fafb1bb851 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 2 Oct 2017 21:37:47 +0700 Subject: [PATCH 12/17] Implement user flag details as slot component --- .../client/components/FlagDetails.js | 36 ++--------- .../client/components/UserFlagDetails.css | 45 ++++++++++++++ .../client/components/UserFlagDetails.js | 59 +++++++++++++++++++ .../client/containers/FlagDetails.js | 10 ---- .../client/containers/UserFlagDetails.js | 39 ++++++++++++ .../talk-plugin-flag-details/client/index.js | 2 + 6 files changed, 151 insertions(+), 40 deletions(-) create mode 100644 plugins/talk-plugin-flag-details/client/components/UserFlagDetails.css create mode 100644 plugins/talk-plugin-flag-details/client/components/UserFlagDetails.js create mode 100644 plugins/talk-plugin-flag-details/client/containers/UserFlagDetails.js diff --git a/plugins/talk-plugin-flag-details/client/components/FlagDetails.js b/plugins/talk-plugin-flag-details/client/components/FlagDetails.js index 3b1f222da..026aebd95 100644 --- a/plugins/talk-plugin-flag-details/client/components/FlagDetails.js +++ b/plugins/talk-plugin-flag-details/client/components/FlagDetails.js @@ -7,23 +7,21 @@ import {Slot, IfSlotIsNotEmpty, CommentDetail} from 'plugin-api/beta/client/comp class FlagDetails extends Component { render() { - const {comment: {actions}, viewUserDetail, more, data, root, comment} = this.props; + const {comment: {actions}, more, data, root, comment} = this.props; const flagActions = actions && actions.filter((a) => a.__typename === 'FlagAction'); const summaries = flagActions.reduce((sum, action) => { if (!(action.reason in sum)) { - sum[action.reason] = {count: 0, userFlagged: false, actions: []}; + sum[action.reason] = {count: 0, actions: []}; } sum[action.reason].count++; if (action.user) { sum[action.reason].userFlagged = true; } - sum[action.reason].actions.push(action); return sum; }, {}); - const userFlagReasons = Object.keys(summaries).filter((reason) => summaries[reason].userFlagged); - + const reasons = Object.keys(summaries); const queryData = { root, comment, @@ -35,36 +33,13 @@ class FlagDetails extends Component { header={`${t('community.flags')} (${Object.keys(summaries).length})`} info={
      - {Object.keys(summaries).map((reason) => + {reasons.map((reason) =>
    • {reason} {summaries[reason].userFlagged && `(${summaries[reason].count})`}
    • )}
    }> - {more && userFlagReasons.length > 0 && ( - - )} {more && ( a.__typename === 'FlagAction'); + const summaries = flagActions.reduce((sum, action) => { + if (!action.user) { + return sum; + } + if (!(action.reason in sum)) { + sum[action.reason] = {count: 0, actions: []}; + } + sum[action.reason].count++; + sum[action.reason].actions.push(action); + return sum; + }, {}); + + return ( + + ); + } +} + +UserFlagDetails.propTypes = { + comment: PropTypes.shape({ + actions: PropTypes.arrayOf(PropTypes.shape({ + message: PropTypes.string, + user: PropTypes.shape({username: PropTypes.string}) + })).isRequired, + }).isRequired, + viewUserDetail: PropTypes.func.isRequired, +}; + +export default UserFlagDetails; diff --git a/plugins/talk-plugin-flag-details/client/containers/FlagDetails.js b/plugins/talk-plugin-flag-details/client/containers/FlagDetails.js index 5a9bb3cae..da04dd65f 100644 --- a/plugins/talk-plugin-flag-details/client/containers/FlagDetails.js +++ b/plugins/talk-plugin-flag-details/client/containers/FlagDetails.js @@ -1,23 +1,13 @@ import {compose, gql} from 'react-apollo'; import FlagDetails from '../components/FlagDetails'; -import {bindActionCreators} from 'redux'; import {withFragments, excludeIf} from 'plugin-api/beta/client/hocs'; -import {viewUserDetail} from 'plugin-api/beta/client/actions/admin'; -import {connect} from 'react-redux'; import {getSlotFragmentSpreads} from 'plugin-api/beta/client/utils'; const slots = [ 'adminCommentMoreFlagDetails', ]; -const mapDispatchToProps = (dispatch) => ({ - ...bindActionCreators({ - viewUserDetail, - }, dispatch) -}); - const enhance = compose( - connect(null, mapDispatchToProps), withFragments({ root: gql` fragment CoralAdmin_FlagDetails_root on RootQuery { diff --git a/plugins/talk-plugin-flag-details/client/containers/UserFlagDetails.js b/plugins/talk-plugin-flag-details/client/containers/UserFlagDetails.js new file mode 100644 index 000000000..aedbb1de5 --- /dev/null +++ b/plugins/talk-plugin-flag-details/client/containers/UserFlagDetails.js @@ -0,0 +1,39 @@ +import {compose, gql} from 'react-apollo'; +import UserFlagDetails from '../components/UserFlagDetails'; +import {bindActionCreators} from 'redux'; +import {withFragments, excludeIf} from 'plugin-api/beta/client/hocs'; +import {viewUserDetail} from 'plugin-api/beta/client/actions/admin'; +import {connect} from 'react-redux'; + +const mapDispatchToProps = (dispatch) => ({ + ...bindActionCreators({ + viewUserDetail, + }, dispatch) +}); + +const enhance = compose( + connect(null, mapDispatchToProps), + withFragments({ + comment: gql` + fragment CoralAdmin_UserFlagDetails_comment on Comment { + actions { + __typename + ... on FlagAction { + id + reason + message + user { + id + username + } + } + } + } + ` + }), + excludeIf(({comment: {actions}}) => + !actions.some((action) => action.__typename === 'FlagAction' && action.user + )), +); + +export default enhance(UserFlagDetails); diff --git a/plugins/talk-plugin-flag-details/client/index.js b/plugins/talk-plugin-flag-details/client/index.js index 045194872..95f579da5 100644 --- a/plugins/talk-plugin-flag-details/client/index.js +++ b/plugins/talk-plugin-flag-details/client/index.js @@ -1,9 +1,11 @@ import FlagDetails from './containers/FlagDetails'; +import UserFlagDetails from './containers/UserFlagDetails'; import translations from './translations.yml'; export default { translations, slots: { adminCommentDetailArea: [FlagDetails], + adminCommentMoreFlagDetails: [UserFlagDetails], } }; From d3d7f909d85c94bc6556729c2df3e41f97953167 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 2 Oct 2017 22:22:00 +0700 Subject: [PATCH 13/17] Translations --- locales/en.yml | 5 ----- locales/es.yml | 5 ----- locales/fr.yml | 5 ----- locales/pt_BR.yml | 4 ---- .../client/components/FlagDetails.js | 2 +- .../talk-plugin-flag-details/client/translations.yml | 7 +++++-- .../client/components/ToxicDetail.js | 11 ++++++----- .../client/translations.yml | 5 +++++ 8 files changed, 17 insertions(+), 27 deletions(-) diff --git a/locales/en.yml b/locales/en.yml index 13ca8eb14..0c13fe1cc 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -262,11 +262,9 @@ en: ban_user: "Ban" billion: B close: Close - dont_like_username: "Don't like username" empty_queue: "No more comments to moderate! You're all caught up. Go have some ☕️" flagged: flagged reported: reported - impersonating: Impersonating less_detail: "Less detail" likes: likes million: M @@ -277,9 +275,7 @@ en: newest_first: "Newest First" navigation: Navigation next_comment: "Go to the next comment" - offensive: Offensive oldest_first: "Oldest First" - other: Other premod: pre-mod prev_comment: "Go to the previous comment" reject: "Reject" @@ -290,7 +286,6 @@ en: shortcuts: "Shortcuts" show_shortcuts: "Show Shortcuts" singleview: "Toggle single comment edit view" - spam_ads: Spam/Ads thismenu: "Open this menu" thousand: k try_these: "Try these" diff --git a/locales/es.yml b/locales/es.yml index 4cb630273..e9844667d 100644 --- a/locales/es.yml +++ b/locales/es.yml @@ -255,10 +255,8 @@ es: approved: "Aprobado" billion: B close: Cerrar - dont_like_username: "No me gusta el nombre de usuario" empty_queue: "¡No hay más comentarios para moderar! Tiempo para un ☕️" flagged: Reportado - impersonating: Impersonando less_detail: "Menos detalles" likes: likes million: M @@ -269,9 +267,7 @@ es: newest_first: "Primero el más nuevo" navigation: Navegación next_comment: "Ir al siguiente comentario" - offensive: Ofensivo oldest_first: "Primero el más antiguo" - other: Otro premod: pre-mod prev_comment: "Ir al comentario anterior" reject: "Rechazar" @@ -282,7 +278,6 @@ es: shortcuts: Atajos show_shortcuts: "Mostrar Atajos" singleview: "Colocar vista de edición de comentario único" - spam_ads: Spam/Publicidad thismenu: "Abrir este menu" thousand: k try_these: "Intentar estos" diff --git a/locales/fr.yml b/locales/fr.yml index 1370d47c6..11a46d38f 100644 --- a/locales/fr.yml +++ b/locales/fr.yml @@ -41,22 +41,17 @@ fr: banned: Banni banned_user: "Utilisateur banni" cancel: Signalé - dont_like_username: "Je n'aime pas ce nom d'utilisateur" flaggedaccounts: "Noms d'utilisateurs signalés" flags: Signalements - impersonating: "Cet utilisateur se fait passer pour quelqu'un d'autre" loading: "Chargement des résultats" moderator: Modérateur newsroom_role: "Rôle de la salle de presse" no_flagged_accounts: "La liste des comptes signalés est vide." no_results: "Aucun utilisateur n'a été trouvé avec ce nom d'utilisateur ou cette adresse de messagerie. Ils se cachent !" note: "Remarque: bannir cet utilisateur ne lui permettra pas de modifier les commentaires ou de supprimer quoi que ce soit." - offensive: "Ce commentaire est offensant" - other: Autre people: Gens role: "Sélectionnez le rôle ..." select_status: "Sélectionnez l'état ..." - spam_ads: "Spam / Annonces" staff: "Équipe" status: Statut username_and_email: "Nom d'utilisateur et e-mail" diff --git a/locales/pt_BR.yml b/locales/pt_BR.yml index 99c39fe41..82f160525 100644 --- a/locales/pt_BR.yml +++ b/locales/pt_BR.yml @@ -51,7 +51,6 @@ pt_BR: banned: Proibida banned_user: "Usuário proibido" cancel: Cancelar - dont_like_username: "Não gostei do nome de usuário" flaggedaccounts: "Nomes de usuários marcados" flags: Marcadas impersonating: "Representação" @@ -60,12 +59,9 @@ pt_BR: newsroom_role: "Papel de empresa" no_flagged_accounts: "A fila de nomes de usuários marcados está atualmente vazia." no_results: "Nenhum usuário encontrado com esse nome de usuário ou e-mail. Eles estão se escondendo!" - offensive: "Ofensiva" - other: Outra people: Pessoas role: "Selecione um papel..." select_status: "Selecione um status..." - spam_ads: "Spam/anúncios" staff: "Funcionários" status: Status username_and_email: "Nome de usuário e email" diff --git a/plugins/talk-plugin-flag-details/client/components/FlagDetails.js b/plugins/talk-plugin-flag-details/client/components/FlagDetails.js index 026aebd95..9e1d03c72 100644 --- a/plugins/talk-plugin-flag-details/client/components/FlagDetails.js +++ b/plugins/talk-plugin-flag-details/client/components/FlagDetails.js @@ -30,7 +30,7 @@ class FlagDetails extends Component { return ( {reasons.map((reason) => diff --git a/plugins/talk-plugin-flag-details/client/translations.yml b/plugins/talk-plugin-flag-details/client/translations.yml index 3b2511025..7f4e8d1b7 100644 --- a/plugins/talk-plugin-flag-details/client/translations.yml +++ b/plugins/talk-plugin-flag-details/client/translations.yml @@ -1,3 +1,6 @@ en: - talk-plugin-fag-details: - + talk-plugin-flag-details: + flags: Flags +es: + talk-plugin-flag-details: + flags: Reportes diff --git a/plugins/talk-plugin-toxic-comments/client/components/ToxicDetail.js b/plugins/talk-plugin-toxic-comments/client/components/ToxicDetail.js index 3726d2b77..1c06c7dfa 100644 --- a/plugins/talk-plugin-toxic-comments/client/components/ToxicDetail.js +++ b/plugins/talk-plugin-toxic-comments/client/components/ToxicDetail.js @@ -4,18 +4,19 @@ import {isToxic} from '../utils'; import styles from './ToxicDetail.css'; import cn from 'classnames'; import PropTypes from 'prop-types'; +import {t} from 'plugin-api/beta/client/services'; const getInfo = (toxicity, actions) => { const toxic = isToxic(actions); - let text = 'Unlikely'; + let text = t('talk-plugin-toxic-comments.unlikely'); if (toxicity > 0.8) { - text = 'Highly Likely'; + text = t('talk-plugin-toxic-comments.highly_likely'); } else if (toxicity >= 0.5) { - text = 'Possibly'; + text = t('talk-plugin-toxic-comments.possibly'); } else if (toxicity >= 0.7) { - text = 'Likely'; + text = t('talk-plugin-toxic-comments.likely'); } return ( @@ -31,7 +32,7 @@ const getInfo = (toxicity, actions) => { const ToxicLabel = ({comment: {actions, toxicity}}) => ( ); diff --git a/plugins/talk-plugin-toxic-comments/client/translations.yml b/plugins/talk-plugin-toxic-comments/client/translations.yml index 787095046..95e546e50 100644 --- a/plugins/talk-plugin-toxic-comments/client/translations.yml +++ b/plugins/talk-plugin-toxic-comments/client/translations.yml @@ -4,6 +4,11 @@ en: Are you sure? The language in this comment might violate our community guidelines. You can edit the comment or submit it for moderator review. talk-plugin-toxic-comments: + unlikely: Unlikely + highly_likely: Highly Likely + possibly: Possibly + likely: Likely + toxic_comment: Toxic Comment still_toxic: | This edited comment might still violate our community guidelines. Our moderation team will review your comment shortly. From 8724cfe325baab1d5850f71cb872ae7956f8b853 Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 2 Oct 2017 22:22:55 +0700 Subject: [PATCH 14/17] Add talk-plugin-flag-details as default plugins --- plugins.default.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins.default.json b/plugins.default.json index 6ce126983..a26a38c8e 100644 --- a/plugins.default.json +++ b/plugins.default.json @@ -21,6 +21,7 @@ "talk-plugin-author-menu", "talk-plugin-member-since", "talk-plugin-ignore-user", - "talk-plugin-moderation-actions" + "talk-plugin-moderation-actions", + "talk-plugin-flag-details" ] } From b1bc97c8d5701def07daa647ac2862b53b1c1b9c Mon Sep 17 00:00:00 2001 From: Chi Vinh Le Date: Mon, 2 Oct 2017 22:34:12 +0700 Subject: [PATCH 15/17] Improve styling --- client/coral-admin/src/components/CommentDetails.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/coral-admin/src/components/CommentDetails.css b/client/coral-admin/src/components/CommentDetails.css index c34a32cb3..1ee1c46dd 100644 --- a/client/coral-admin/src/components/CommentDetails.css +++ b/client/coral-admin/src/components/CommentDetails.css @@ -1,5 +1,5 @@ .root { - min-height: 24px; + min-height: 25px; padding: 0 16px; } From 343d4418b073ce2876799a8a841e0d306441c42e Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Mon, 2 Oct 2017 16:23:56 -0300 Subject: [PATCH 16/17] eslint updated --- plugins/talk-plugin-subscriber/.eslintrc.json | 4 ++++ .../client/.eslintrc.json | 22 +------------------ 2 files changed, 5 insertions(+), 21 deletions(-) create mode 100644 plugins/talk-plugin-subscriber/.eslintrc.json diff --git a/plugins/talk-plugin-subscriber/.eslintrc.json b/plugins/talk-plugin-subscriber/.eslintrc.json new file mode 100644 index 000000000..d7d291614 --- /dev/null +++ b/plugins/talk-plugin-subscriber/.eslintrc.json @@ -0,0 +1,4 @@ +{ + "extends": "@coralproject/eslint-config-talk" + } + \ No newline at end of file diff --git a/plugins/talk-plugin-subscriber/client/.eslintrc.json b/plugins/talk-plugin-subscriber/client/.eslintrc.json index 9fe56bd14..c8a6db18a 100644 --- a/plugins/talk-plugin-subscriber/client/.eslintrc.json +++ b/plugins/talk-plugin-subscriber/client/.eslintrc.json @@ -1,23 +1,3 @@ { - "env": { - "browser": true, - "es6": true, - "mocha": true - }, - "parserOptions": { - "sourceType": "module", - "ecmaFeatures": { - "experimentalObjectRestSpread": true, - "jsx": true - } - }, - "parser": "babel-eslint", - "plugins": [ - "react" - ], - "rules": { - "react/jsx-uses-react": "error", - "react/jsx-uses-vars": "error", - "no-console": ["warn", { "allow": ["warn", "error"] }] - } + "extends": "@coralproject/eslint-config-talk/client" } From dde1f7b5be42bc548e762113c4eca9a98dd33248 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Mon, 2 Oct 2017 16:26:21 -0300 Subject: [PATCH 17/17] Assigned by removed --- client/coral-embed-stream/src/graphql/index.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/client/coral-embed-stream/src/graphql/index.js b/client/coral-embed-stream/src/graphql/index.js index 228efb25b..3f6fd4832 100644 --- a/client/coral-embed-stream/src/graphql/index.js +++ b/client/coral-embed-stream/src/graphql/index.js @@ -157,10 +157,6 @@ export default { created_at: new Date().toISOString(), __typename: 'Tag' }, - assigned_by: { - id: auth.user.id, - __typename: 'User' - }, __typename: 'TagLink' })), status: 'NONE',