From 8866366d3cf5f95e2a4d3c244fb13fea76dc8634 Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Fri, 17 Feb 2017 16:07:34 -0700 Subject: [PATCH 001/132] storing my place in case we want to come back to this --- .../coral-admin/src/components/FlagWidget.js | 2 +- .../coral-admin/src/components/LikeWidget.js | 34 +++++++++++++++++++ client/coral-admin/src/components/Widget.css | 34 +++++++++++++++++++ .../src/containers/Dashboard/Dashboard.js | 11 ++++-- .../coral-admin/src/graphql/queries/index.js | 20 +++++++++-- .../src/graphql/queries/metrics.graphql | 24 +++++++++++++ 6 files changed, 119 insertions(+), 6 deletions(-) create mode 100644 client/coral-admin/src/components/LikeWidget.js create mode 100644 client/coral-admin/src/components/Widget.css create mode 100644 client/coral-admin/src/graphql/queries/metrics.graphql diff --git a/client/coral-admin/src/components/FlagWidget.js b/client/coral-admin/src/components/FlagWidget.js index 187306c8c..96e21ac0b 100644 --- a/client/coral-admin/src/components/FlagWidget.js +++ b/client/coral-admin/src/components/FlagWidget.js @@ -1,6 +1,6 @@ import React, {PropTypes} from 'react'; import {Link} from 'react-router'; -import styles from './FlagWidget.css'; +import styles from './Widget.css'; import I18n from 'coral-framework/modules/i18n/i18n'; import translations from 'coral-admin/src/translations'; diff --git a/client/coral-admin/src/components/LikeWidget.js b/client/coral-admin/src/components/LikeWidget.js new file mode 100644 index 000000000..33df3e2b4 --- /dev/null +++ b/client/coral-admin/src/components/LikeWidget.js @@ -0,0 +1,34 @@ +import React, {PropTypes} from 'react'; +import {Link} from 'react-router'; +import styles from './Widget.css'; +import I18n from 'coral-framework/modules/i18n/i18n'; +import translations from 'coral-admin/src/translations'; + +const lang = new I18n(translations); + +const LikeWidget = ({assets}) => { + return ( + +
+ ); +}; + +LikeWidget.propTypes = { + assets: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.string, + title: PropTypes.string, + url: PropTypes.string, + commentCount: PropTypes.number, + action_summaries: PropTypes.arrayOf( + PropTypes.shape({ + __typename: PropTypes.string.isRequired, + actionCount: PropTypes.number.isRequired, + actionableItemCount: PropTypes.number.isRequired + }) + ) + }) + ).isRequired +}; + +export default LikeWidget; diff --git a/client/coral-admin/src/components/Widget.css b/client/coral-admin/src/components/Widget.css new file mode 100644 index 000000000..f40da403d --- /dev/null +++ b/client/coral-admin/src/components/Widget.css @@ -0,0 +1,34 @@ +.heading { + margin: 0; + font-size: 1.5rem; + font-weight: bold; +} + +.widgetTable { + width: 100%; + border-collapse: collapse; + box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.2); +} + +.widgetTable thead th { + border-bottom: 1px solid #f47e6b; + padding: 10px; + text-align: left; +} + +.widgetTable tbody tr { + border-bottom: 1px solid lightgrey; +} + +.widgetTable tbody tr:last-child { + border-bottom: none; +} + +.widgetTable tbody td { + padding: 10px; +} + +.lede { + font-size: 0.9em; + color: grey; +} diff --git a/client/coral-admin/src/containers/Dashboard/Dashboard.js b/client/coral-admin/src/containers/Dashboard/Dashboard.js index 6baa16af1..253c0980b 100644 --- a/client/coral-admin/src/containers/Dashboard/Dashboard.js +++ b/client/coral-admin/src/containers/Dashboard/Dashboard.js @@ -1,14 +1,16 @@ import React from 'react'; import {compose} from 'react-apollo'; -import {mostFlags} from 'coral-admin/src/graphql/queries'; +import {mostFlags, mostLikes} from 'coral-admin/src/graphql/queries'; import {Spinner} from 'coral-ui'; import styles from './Dashboard.css'; import FlagWidget from '../../components/FlagWidget'; +import LikeWidget from '../../components/LikeWidget'; class Dashboard extends React.Component { render () { const {data} = this.props; + console.log('data', data); const {metrics: assets} = data; if (data.loading) { @@ -28,11 +30,16 @@ class Dashboard extends React.Component {

Top ten comments with the most likes

+
+

Top Ten Articles with the most likes

+ +
); } } export default compose( - mostFlags + mostFlags, + mostLikes )(Dashboard); diff --git a/client/coral-admin/src/graphql/queries/index.js b/client/coral-admin/src/graphql/queries/index.js index 3325249e1..f98b40091 100644 --- a/client/coral-admin/src/graphql/queries/index.js +++ b/client/coral-admin/src/graphql/queries/index.js @@ -1,14 +1,14 @@ import {graphql} from 'react-apollo'; -import MOST_FLAGS from './mostFlags.graphql'; +import METRICS from './metrics.graphql'; import MOD_QUEUE_QUERY from './modQueueQuery.graphql'; -export const mostFlags = graphql(MOST_FLAGS, { +export const mostFlags = graphql(METRICS, { options: () => { // currently hard-coded per Greg's advice const fiveMinutesAgo = new Date(); - fiveMinutesAgo.setMinutes(fiveMinutesAgo.getMinutes() - 305); + fiveMinutesAgo.setMinutes(fiveMinutesAgo.getMinutes() - 5); return { variables: { sort: 'FLAG', @@ -19,6 +19,20 @@ export const mostFlags = graphql(MOST_FLAGS, { } }); +export const mostLikes = graphql(METRICS, { + options: () => { + const fiveMinutesAgo = new Date(); + fiveMinutesAgo.setMinutes(fiveMinutesAgo.getMinutes() - 5); + return { + variables: { + sort: 'LIKE', + from: fiveMinutesAgo.toISOString(), + to: new Date().toISOString() + } + }; + } +}); + export const modQueueQuery = graphql(MOD_QUEUE_QUERY, { options: ({params: {id = null}}) => { return { diff --git a/client/coral-admin/src/graphql/queries/metrics.graphql b/client/coral-admin/src/graphql/queries/metrics.graphql new file mode 100644 index 000000000..2f9afe621 --- /dev/null +++ b/client/coral-admin/src/graphql/queries/metrics.graphql @@ -0,0 +1,24 @@ +fragment metrics on Asset { + id + title + action_summaries { + type: __typename + actionCount + actionableItemCount + } +} + +query Metrics ($from: Date!, $to: Date!, $sort: ACTION_TYPE!) { + metrics(from: $from, to: $to, sort: $sort) { + id + title + url + commentCount + author + created_at + action_summaries { + actionCount + actionableItemCount + } + } +} From 364cf1808e107551218beec3f329d121e4d42dbf Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Tue, 21 Feb 2017 10:28:33 -0700 Subject: [PATCH 002/132] assets by like? --- .../src/containers/Dashboard/Dashboard.js | 6 +++--- .../{metrics.graphql => assetsByFlag.graphql} | 17 ++++++----------- .../src/graphql/queries/assetsByLike.graphql | 19 +++++++++++++++++++ .../coral-admin/src/graphql/queries/index.js | 7 ++++--- 4 files changed, 32 insertions(+), 17 deletions(-) rename client/coral-admin/src/graphql/queries/{metrics.graphql => assetsByFlag.graphql} (51%) create mode 100644 client/coral-admin/src/graphql/queries/assetsByLike.graphql diff --git a/client/coral-admin/src/containers/Dashboard/Dashboard.js b/client/coral-admin/src/containers/Dashboard/Dashboard.js index 253c0980b..0cc015e00 100644 --- a/client/coral-admin/src/containers/Dashboard/Dashboard.js +++ b/client/coral-admin/src/containers/Dashboard/Dashboard.js @@ -11,7 +11,7 @@ class Dashboard extends React.Component { const {data} = this.props; console.log('data', data); - const {metrics: assets} = data; + const {assetsByLike, assetsByFlag} = data; if (data.loading) { return ; @@ -25,14 +25,14 @@ class Dashboard extends React.Component {

Top Ten Articles with the most flagged comments

- +

Top ten comments with the most likes

Top Ten Articles with the most likes

- +
); diff --git a/client/coral-admin/src/graphql/queries/metrics.graphql b/client/coral-admin/src/graphql/queries/assetsByFlag.graphql similarity index 51% rename from client/coral-admin/src/graphql/queries/metrics.graphql rename to client/coral-admin/src/graphql/queries/assetsByFlag.graphql index 2f9afe621..c6f0900ac 100644 --- a/client/coral-admin/src/graphql/queries/metrics.graphql +++ b/client/coral-admin/src/graphql/queries/assetsByFlag.graphql @@ -1,6 +1,10 @@ fragment metrics on Asset { id title + url + commentCount + author + created_at action_summaries { type: __typename actionCount @@ -9,16 +13,7 @@ fragment metrics on Asset { } query Metrics ($from: Date!, $to: Date!, $sort: ACTION_TYPE!) { - metrics(from: $from, to: $to, sort: $sort) { - id - title - url - commentCount - author - created_at - action_summaries { - actionCount - actionableItemCount - } + assetsByFlag: metrics(from: $from, to: $to, sort: $sort) { + ...metrics } } diff --git a/client/coral-admin/src/graphql/queries/assetsByLike.graphql b/client/coral-admin/src/graphql/queries/assetsByLike.graphql new file mode 100644 index 000000000..853afee41 --- /dev/null +++ b/client/coral-admin/src/graphql/queries/assetsByLike.graphql @@ -0,0 +1,19 @@ +fragment metrics on Asset { + id + title + url + commentCount + author + created_at + action_summaries { + type: __typename + actionCount + actionableItemCount + } +} + +query Metrics ($from: Date!, $to: Date!, $sort: ACTION_TYPE!) { + assetsByLike: metrics(from: $from, to: $to, sort: $sort) { + ...metrics + } +} diff --git a/client/coral-admin/src/graphql/queries/index.js b/client/coral-admin/src/graphql/queries/index.js index f98b40091..96cb319c9 100644 --- a/client/coral-admin/src/graphql/queries/index.js +++ b/client/coral-admin/src/graphql/queries/index.js @@ -1,9 +1,10 @@ import {graphql} from 'react-apollo'; -import METRICS from './metrics.graphql'; +import BY_LIKES from './assetsByLike.graphql'; +import BY_FLAGS from './assetsByFlag.graphql'; import MOD_QUEUE_QUERY from './modQueueQuery.graphql'; -export const mostFlags = graphql(METRICS, { +export const mostFlags = graphql(BY_FLAGS, { options: () => { // currently hard-coded per Greg's advice @@ -19,7 +20,7 @@ export const mostFlags = graphql(METRICS, { } }); -export const mostLikes = graphql(METRICS, { +export const mostLikes = graphql(BY_LIKES, { options: () => { const fiveMinutesAgo = new Date(); fiveMinutesAgo.setMinutes(fiveMinutesAgo.getMinutes() - 5); From 5d94a98305bfaa5c07b87746d40565dc41ff6337 Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Tue, 21 Feb 2017 14:05:49 -0700 Subject: [PATCH 003/132] Like and Flag summaries work again --- .../coral-admin/src/components/FlagWidget.js | 102 +++++++++--------- .../coral-admin/src/components/LikeWidget.js | 73 +++++++++---- .../src/containers/Dashboard/Dashboard.js | 53 +++------ .../src/graphql/queries/assetsByLike.graphql | 19 ---- .../coral-admin/src/graphql/queries/index.js | 9 +- .../{assetsByFlag.graphql => metrics.graphql} | 2 +- client/coral-admin/src/translations.json | 2 + 7 files changed, 121 insertions(+), 139 deletions(-) delete mode 100644 client/coral-admin/src/graphql/queries/assetsByLike.graphql rename client/coral-admin/src/graphql/queries/{assetsByFlag.graphql => metrics.graphql} (80%) diff --git a/client/coral-admin/src/components/FlagWidget.js b/client/coral-admin/src/components/FlagWidget.js index 96e21ac0b..a37ddcd2c 100644 --- a/client/coral-admin/src/components/FlagWidget.js +++ b/client/coral-admin/src/components/FlagWidget.js @@ -1,66 +1,60 @@ -import React, {PropTypes} from 'react'; +import React from 'react'; +import {compose} from 'react-apollo'; +import {mostFlags} from 'coral-admin/src/graphql/queries'; import {Link} from 'react-router'; import styles from './Widget.css'; import I18n from 'coral-framework/modules/i18n/i18n'; import translations from 'coral-admin/src/translations'; +import {Spinner} from 'coral-ui'; const lang = new I18n(translations); -const FlagWidget = ({assets}) => { +const FlagWidget = (props) => { + + if (props.data.loading) { + return ; + } + + const {data: {metrics: assets}} = props; return ( - - - - {/* empty on purpose */} - - - - - - - - { - assets.length - ? assets.map((asset, index) => { - const flagSummary = asset.action_summaries.find(s => s.__typename === 'FlagAssetActionSummary'); - const likeSummary = asset.action_summaries.find(s => s.__typename === 'LikeAssetActionSummary'); - return ( - - - - - - - - ); - }) - : - } - -
{lang.t('streams.article')}{lang.t('modqueue.flagged')}{lang.t('modqueue.likes')}{lang.t('dashboard.comment_count')}
{index + 1}. - {asset.title} -

{asset.author} - Published: {new Date(asset.created_at).toLocaleDateString()}

-
{flagSummary ? flagSummary.actionCount : 0}{likeSummary ? likeSummary.actionCount : 0}{asset.commentCount}
{lang.t('dashboard.no_flags')}
+
+

Top Ten Articles with the most flagged comments

+ + + + {/* empty on purpose */} + + + + + + + + { + assets.length + ? assets.map((asset, index) => { + const flagSummary = asset.action_summaries.find(s => s.type === 'FlagAssetActionSummary'); + const likeSummary = asset.action_summaries.find(s => s.type === 'LikeAssetActionSummary'); + return ( + + + + + + + + ); + }) + : + } + +
{lang.t('streams.article')}{lang.t('modqueue.flagged')}{lang.t('modqueue.likes')}{lang.t('dashboard.comment_count')}
{index + 1}. + {asset.title} +

{asset.author} - Published: {new Date(asset.created_at).toLocaleDateString()}

+
{flagSummary ? flagSummary.actionCount : 0}{likeSummary ? likeSummary.actionCount : 0}{asset.commentCount}
{lang.t('dashboard.no_flags')}
+
); }; -FlagWidget.propTypes = { - assets: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string, - title: PropTypes.string, - url: PropTypes.string, - commentCount: PropTypes.number, - action_summaries: PropTypes.arrayOf( - PropTypes.shape({ - __typename: PropTypes.string.isRequired, - actionCount: PropTypes.number.isRequired, - actionableItemCount: PropTypes.number.isRequired - }) - ) - }) - ).isRequired -}; - -export default FlagWidget; +export default compose(mostFlags)(FlagWidget); diff --git a/client/coral-admin/src/components/LikeWidget.js b/client/coral-admin/src/components/LikeWidget.js index 33df3e2b4..ac9e111ea 100644 --- a/client/coral-admin/src/components/LikeWidget.js +++ b/client/coral-admin/src/components/LikeWidget.js @@ -1,34 +1,61 @@ -import React, {PropTypes} from 'react'; +import React from 'react'; +import {compose} from 'react-apollo'; +import {mostLikes} from 'coral-admin/src/graphql/queries'; import {Link} from 'react-router'; +import {Spinner} from 'coral-ui'; import styles from './Widget.css'; import I18n from 'coral-framework/modules/i18n/i18n'; import translations from 'coral-admin/src/translations'; const lang = new I18n(translations); -const LikeWidget = ({assets}) => { +const LikeWidget = (props) => { + + if (props.data.loading) { + return ; + } + + const {data: {metrics: assets}} = props; + return ( - -
+
+

Top Ten Articles with the most likes

+ + + + {/* empty on purpose */} + + + + + + + + { + assets.length + ? assets.map((asset, index) => { + const flagSummary = asset.action_summaries.find(s => s.type === 'FlagAssetActionSummary'); + const likeSummary = asset.action_summaries.find(s => s.type === 'LikeAssetActionSummary'); + console.log('LikeWidget', likeSummary); + return ( + + + + + + + + ); + }) + : + } + +
{lang.t('streams.article')}{lang.t('modqueue.flagged')}{lang.t('modqueue.likes')}{lang.t('dashboard.comment_count')}
{index + 1}. + {asset.title} +

{asset.author} - Published: {new Date(asset.created_at).toLocaleDateString()}

+
{flagSummary ? flagSummary.actionCount : 0}{likeSummary ? likeSummary.actionCount : 0}{asset.commentCount}
{lang.t('dashboard.no_likes')}
+
); }; -LikeWidget.propTypes = { - assets: PropTypes.arrayOf( - PropTypes.shape({ - id: PropTypes.string, - title: PropTypes.string, - url: PropTypes.string, - commentCount: PropTypes.number, - action_summaries: PropTypes.arrayOf( - PropTypes.shape({ - __typename: PropTypes.string.isRequired, - actionCount: PropTypes.number.isRequired, - actionableItemCount: PropTypes.number.isRequired - }) - ) - }) - ).isRequired -}; - -export default LikeWidget; +export default compose(mostLikes)(LikeWidget); diff --git a/client/coral-admin/src/containers/Dashboard/Dashboard.js b/client/coral-admin/src/containers/Dashboard/Dashboard.js index 0cc015e00..fcccb36b3 100644 --- a/client/coral-admin/src/containers/Dashboard/Dashboard.js +++ b/client/coral-admin/src/containers/Dashboard/Dashboard.js @@ -1,45 +1,22 @@ import React from 'react'; -import {compose} from 'react-apollo'; -import {mostFlags, mostLikes} from 'coral-admin/src/graphql/queries'; -import {Spinner} from 'coral-ui'; import styles from './Dashboard.css'; import FlagWidget from '../../components/FlagWidget'; import LikeWidget from '../../components/LikeWidget'; -class Dashboard extends React.Component { - render () { - - const {data} = this.props; - console.log('data', data); - const {assetsByLike, assetsByFlag} = data; - - if (data.loading) { - return ; - } - - if (data.error) { - return
{data.error}
; - } - - return ( -
-
-

Top Ten Articles with the most flagged comments

- -
-
-

Top ten comments with the most likes

-
-
-

Top Ten Articles with the most likes

- -
+const Dashboard = () => { + return ( +
+
+
- ); - } -} +
+

Top ten comments with the most likes

+
+
+ +
+
+ ); +}; -export default compose( - mostFlags, - mostLikes -)(Dashboard); +export default Dashboard; diff --git a/client/coral-admin/src/graphql/queries/assetsByLike.graphql b/client/coral-admin/src/graphql/queries/assetsByLike.graphql deleted file mode 100644 index 853afee41..000000000 --- a/client/coral-admin/src/graphql/queries/assetsByLike.graphql +++ /dev/null @@ -1,19 +0,0 @@ -fragment metrics on Asset { - id - title - url - commentCount - author - created_at - action_summaries { - type: __typename - actionCount - actionableItemCount - } -} - -query Metrics ($from: Date!, $to: Date!, $sort: ACTION_TYPE!) { - assetsByLike: metrics(from: $from, to: $to, sort: $sort) { - ...metrics - } -} diff --git a/client/coral-admin/src/graphql/queries/index.js b/client/coral-admin/src/graphql/queries/index.js index 96cb319c9..1628a4ac8 100644 --- a/client/coral-admin/src/graphql/queries/index.js +++ b/client/coral-admin/src/graphql/queries/index.js @@ -1,10 +1,9 @@ import {graphql} from 'react-apollo'; -import BY_LIKES from './assetsByLike.graphql'; -import BY_FLAGS from './assetsByFlag.graphql'; +import METRICS from './metrics.graphql'; import MOD_QUEUE_QUERY from './modQueueQuery.graphql'; -export const mostFlags = graphql(BY_FLAGS, { +export const mostFlags = graphql(METRICS, { options: () => { // currently hard-coded per Greg's advice @@ -20,8 +19,10 @@ export const mostFlags = graphql(BY_FLAGS, { } }); -export const mostLikes = graphql(BY_LIKES, { +export const mostLikes = graphql(METRICS, { options: () => { + + // currently hard-coded per Greg's advice const fiveMinutesAgo = new Date(); fiveMinutesAgo.setMinutes(fiveMinutesAgo.getMinutes() - 5); return { diff --git a/client/coral-admin/src/graphql/queries/assetsByFlag.graphql b/client/coral-admin/src/graphql/queries/metrics.graphql similarity index 80% rename from client/coral-admin/src/graphql/queries/assetsByFlag.graphql rename to client/coral-admin/src/graphql/queries/metrics.graphql index c6f0900ac..9a226d8bc 100644 --- a/client/coral-admin/src/graphql/queries/assetsByFlag.graphql +++ b/client/coral-admin/src/graphql/queries/metrics.graphql @@ -13,7 +13,7 @@ fragment metrics on Asset { } query Metrics ($from: Date!, $to: Date!, $sort: ACTION_TYPE!) { - assetsByFlag: metrics(from: $from, to: $to, sort: $sort) { + metrics(from: $from, to: $to, sort: $sort) { ...metrics } } diff --git a/client/coral-admin/src/translations.json b/client/coral-admin/src/translations.json index 5b15564d7..13d482d6c 100644 --- a/client/coral-admin/src/translations.json +++ b/client/coral-admin/src/translations.json @@ -110,6 +110,7 @@ }, "dashboard": { "no_flags": "There have been no flags in the last 5 minutes! Hooray!", + "no_likes": "There have been no likes in the last 5 minutes. All quiet.", "comment_count": "Comments" }, "streams": { @@ -217,6 +218,7 @@ }, "dashbord": { "no_flags": "¡Nadie ha marcado nada en los últimos 5 minutos! ¡Bravo!", + "no_likes": "A nadie le ha gustado algún comentario en los últimos 5 minutos. Todo tranquilo.", "comment_count": "Comentarios" }, "streams": { From f32fe2629ce74e3214c590fc7014b6109440c4e0 Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Tue, 21 Feb 2017 14:16:02 -0700 Subject: [PATCH 004/132] css is the worst --- .../src/containers/Dashboard/Dashboard.css | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/client/coral-admin/src/containers/Dashboard/Dashboard.css b/client/coral-admin/src/containers/Dashboard/Dashboard.css index be2cd9f7a..0e46fb642 100644 --- a/client/coral-admin/src/containers/Dashboard/Dashboard.css +++ b/client/coral-admin/src/containers/Dashboard/Dashboard.css @@ -1,19 +1,14 @@ .Dashboard { display: flex; - padding: 5px; + flex-wrap: wrap; } .widget { - margin-top: 10px; - flex: 1; + box-sizing: border-box; + margin: 10px 5px 5px 5px; box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.2); - margin-right: 10px; padding: 15px; - -} - -.widget:last-child { - margin-right: 0; + width: calc(50% - 10px); } .heading { From 2360f280d2015849954e4d911ee0f78f7781f03c Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Tue, 21 Feb 2017 14:17:56 -0700 Subject: [PATCH 005/132] Added commentMetrics edge. --- graph/loaders/metrics.js | 65 +++++++++++++++++++++++++++++++++-- graph/resolvers/comment.js | 6 +++- graph/resolvers/root_query.js | 12 +++++-- graph/typeDefs.graphql | 10 ++++-- 4 files changed, 85 insertions(+), 8 deletions(-) diff --git a/graph/loaders/metrics.js b/graph/loaders/metrics.js index a842165c0..7cdecbc8e 100644 --- a/graph/loaders/metrics.js +++ b/graph/loaders/metrics.js @@ -5,7 +5,10 @@ const {objectCacheKeyFn} = require('./util'); const CommentModel = require('../../models/comment'); const ActionModel = require('../../models/action'); -const getMetrics = ({loaders: {Metrics, Assets}}, {from, to, sort, limit}) => { +/** + * Returns a list of assets with action metadata included on the models. + */ +const getAssetMetrics = ({loaders: {Metrics, Assets}}, {from, to, sort, limit}) => { let commentMetrics = {}; let assetMetrics = []; @@ -99,6 +102,59 @@ const getMetrics = ({loaders: {Metrics, Assets}}, {from, to, sort, limit}) => { }); }; +/** + * Returns a list of comments that are retrieved based on most activity within + * the indicated time range. + */ +const getCommentMetrics = ({loaders: {Metrics, Assets}}, {from, to, sort, limit}) => { + + let commentActionSummaries = {}; + + return Metrics.getRecentActions.load({from, to}) + .then((actionSummaries) => { + + actionSummaries.sort((a, b) => { + let aActionSummary = a.action_type === sort ? a : null; + let bActionSummary = b.action_type === sort ? b : null; + + // If either a or b don't have this action type, then one of them will + // automatically win. + if (aActionSummary == null || bActionSummary == null) { + if (bActionSummary != null) { + return 1; + } + + if (aActionSummary != null) { + return -1; + } + + return 0; + } + + // Both of them had an actionCount, hence we can determine that we could + // compare the actual values directly. + return bActionSummary.count - aActionSummary.count; + }); + + commentActionSummaries = _.groupBy(actionSummaries, 'item_id'); + + let commentIDs = _.uniq(actionSummaries.map(({item_id}) => item_id)); + + // Only keep the top `limit`. + commentIDs = commentIDs.slice(0, limit); + + // Find those comments. + return Metrics.getSpecificComments.loadMany(commentIDs); + }) + .then((comments) => comments.map((comment) => { + + // Add in the action summaries genrerated. + comment.action_summaries = commentActionSummaries[comment.id]; + + return comment; + })); +}; + const getRecentActions = (context, {from, to}) => { return ActionModel.aggregate([ @@ -150,6 +206,11 @@ module.exports = (context) => ({ batch: false, cacheKeyFn: objectCacheKeyFn('from', 'to') }), - get: ({from, to, sort, limit}) => getMetrics(context, {from, to, sort, limit}) + Assets: { + get: ({from, to, sort, limit}) => getAssetMetrics(context, {from, to, sort, limit}) + }, + Comments: { + get: ({from, to, sort, limit}) => getCommentMetrics(context, {from, to, sort, limit}) + } } }); diff --git a/graph/resolvers/comment.js b/graph/resolvers/comment.js index ef77ff6b5..de1909df1 100644 --- a/graph/resolvers/comment.js +++ b/graph/resolvers/comment.js @@ -25,7 +25,11 @@ const Comment = { return null; }, - action_summaries({id}, _, {loaders: {Actions}}) { + action_summaries({id, action_summaries}, _, {loaders: {Actions}}) { + if (action_summaries) { + return action_summaries; + } + return Actions.getSummariesByItemID.load(id); }, asset({asset_id}, _, {loaders: {Assets}}) { diff --git a/graph/resolvers/root_query.js b/graph/resolvers/root_query.js index ced4e65cf..8800bfebf 100644 --- a/graph/resolvers/root_query.js +++ b/graph/resolvers/root_query.js @@ -56,12 +56,20 @@ const RootQuery = { return Comments.getCountByQuery({statuses, asset_id, parent_id}); }, - metrics(_, {from, to, sort, limit = 10}, {user, loaders: {Metrics}}) { + assetMetrics(_, {from, to, sort, limit = 10}, {user, loaders: {Metrics: {Assets}}}) { if (user == null || !user.hasRoles('ADMIN')) { return null; } - return Metrics.get({from, to, sort, limit}); + return Assets.get({from, to, sort, limit}); + }, + + commentMetrics(_, {from, to, sort, limit = 10}, {user, loaders: {Metrics: {Comments}}}) { + if (user == null || !user.hasRoles('ADMIN')) { + return null; + } + + return Comments.get({from, to, sort, limit}); }, // This returns the current user, ensure that if we aren't logged in, we diff --git a/graph/typeDefs.graphql b/graph/typeDefs.graphql index 72a54a0cd..0eec34b54 100644 --- a/graph/typeDefs.graphql +++ b/graph/typeDefs.graphql @@ -456,9 +456,13 @@ type RootQuery { # role. me: User - # Metrics related to user actions are saturated into the assets returned. The - # sort will affect if it will allow - metrics(from: Date!, to: Date!, sort: ACTION_TYPE!, limit: Int = 10): [Asset] + # Asset metrics related to user actions are saturated into the assets + # returned. + assetMetrics(from: Date!, to: Date!, sort: ACTION_TYPE!, limit: Int = 10): [Asset] + + # Comment metrics related to user actions are saturated into the comments + # returned. + commentMetrics(from: Date!, to: Date!, sort: ACTION_TYPE!, limit: Int = 10): [Comment] } ################################################################################ From 6398e2faad14b3e3728a774e8352d2c06ea84a8d Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 22 Feb 2017 09:32:51 -0700 Subject: [PATCH 006/132] Fixed issue with comment hydration --- graph/loaders/comments.js | 16 ++++++++++++++++ graph/loaders/metrics.js | 13 ++++++++++--- graph/typeDefs.graphql | 4 ++-- 3 files changed, 28 insertions(+), 5 deletions(-) diff --git a/graph/loaders/comments.js b/graph/loaders/comments.js index ad78a1e92..47a8095dc 100644 --- a/graph/loaders/comments.js +++ b/graph/loaders/comments.js @@ -270,6 +270,21 @@ const genRecentComments = (_, ids) => { .then(util.arrayJoinBy(ids, 'asset_id')); }; +/** + * Returns the comment's by their id. + * @param {Object} context graph context + * @param {Array} ids the comment id's to fetch + * @return {Promise} resolves to the comments + */ +const genCommentsByID = (context, ids) => { + return CommentModel.find({ + id: { + $in: ids + } + }) + .then(util.singleJoinBy(ids, 'id')); +}; + /** * Creates a set of loaders based on a GraphQL context. * @param {Object} context the context of the GraphQL request @@ -277,6 +292,7 @@ const genRecentComments = (_, ids) => { */ module.exports = (context) => ({ Comments: { + get: new DataLoader((ids) => genCommentsByID(context, ids)), getByQuery: (query) => getCommentsByQuery(context, query), getCountByQuery: (query) => getCommentCountByQuery(context, query), countByAssetID: new util.SharedCacheDataLoader('Comments.countByAssetID', 3600, (ids) => getCountsByAssetID(context, ids)), diff --git a/graph/loaders/metrics.js b/graph/loaders/metrics.js index 7cdecbc8e..8591ecefe 100644 --- a/graph/loaders/metrics.js +++ b/graph/loaders/metrics.js @@ -106,7 +106,7 @@ const getAssetMetrics = ({loaders: {Metrics, Assets}}, {from, to, sort, limit}) * Returns a list of comments that are retrieved based on most activity within * the indicated time range. */ -const getCommentMetrics = ({loaders: {Metrics, Assets}}, {from, to, sort, limit}) => { +const getCommentMetrics = ({loaders: {Metrics, Comments}}, {from, to, sort, limit}) => { let commentActionSummaries = {}; @@ -143,8 +143,15 @@ const getCommentMetrics = ({loaders: {Metrics, Assets}}, {from, to, sort, limit} // Only keep the top `limit`. commentIDs = commentIDs.slice(0, limit); - // Find those comments. - return Metrics.getSpecificComments.loadMany(commentIDs); + // If there are no comment's to get, then just continue with an empty + // array. + if (commentIDs.length === 0) { + return []; + } + + // Find those comments, this is the final stage, so let's get all the + // fields. + return Comments.get.loadMany(commentIDs); }) .then((comments) => comments.map((comment) => { diff --git a/graph/typeDefs.graphql b/graph/typeDefs.graphql index 0eec34b54..c61312255 100644 --- a/graph/typeDefs.graphql +++ b/graph/typeDefs.graphql @@ -458,11 +458,11 @@ type RootQuery { # Asset metrics related to user actions are saturated into the assets # returned. - assetMetrics(from: Date!, to: Date!, sort: ACTION_TYPE!, limit: Int = 10): [Asset] + assetMetrics(from: Date!, to: Date!, sort: ACTION_TYPE!, limit: Int = 10): [Asset!] # Comment metrics related to user actions are saturated into the comments # returned. - commentMetrics(from: Date!, to: Date!, sort: ACTION_TYPE!, limit: Int = 10): [Comment] + commentMetrics(from: Date!, to: Date!, sort: ACTION_TYPE!, limit: Int = 10): [Comment!] } ################################################################################ From bc4849632794a2a1947d92b3ecd27113bb92902b Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Wed, 22 Feb 2017 10:47:23 -0700 Subject: [PATCH 007/132] add most liked comments widget --- .../src/containers/Dashboard/Dashboard.css | 8 ----- .../src/containers/Dashboard/Dashboard.js | 17 ++++----- .../Dashboard}/FlagWidget.js | 2 +- .../Dashboard}/LikeWidget.js | 2 +- .../Dashboard/MostLikedCommentsWidget.js | 35 +++++++++++++++++++ .../Dashboard}/Widget.css | 8 +++++ .../ModerationQueue/ModerationContainer.js | 5 +-- .../ModerationQueue/ModerationQueue.js | 6 ++-- .../{metrics.graphql => assetMetrics.graphql} | 2 +- .../graphql/queries/commentMetrics.graphql | 19 ++++++++++ .../coral-admin/src/graphql/queries/index.js | 23 ++++++++++-- .../coral-sign-in/components/SignUpContent.js | 9 ++--- 12 files changed, 100 insertions(+), 36 deletions(-) rename client/coral-admin/src/{components => containers/Dashboard}/FlagWidget.js (98%) rename client/coral-admin/src/{components => containers/Dashboard}/LikeWidget.js (98%) create mode 100644 client/coral-admin/src/containers/Dashboard/MostLikedCommentsWidget.js rename client/coral-admin/src/{components => containers/Dashboard}/Widget.css (75%) rename client/coral-admin/src/graphql/queries/{metrics.graphql => assetMetrics.graphql} (80%) create mode 100644 client/coral-admin/src/graphql/queries/commentMetrics.graphql diff --git a/client/coral-admin/src/containers/Dashboard/Dashboard.css b/client/coral-admin/src/containers/Dashboard/Dashboard.css index 0e46fb642..a23927d8a 100644 --- a/client/coral-admin/src/containers/Dashboard/Dashboard.css +++ b/client/coral-admin/src/containers/Dashboard/Dashboard.css @@ -3,14 +3,6 @@ flex-wrap: wrap; } -.widget { - box-sizing: border-box; - margin: 10px 5px 5px 5px; - box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.2); - padding: 15px; - width: calc(50% - 10px); -} - .heading { margin: 0; font-size: 1.5rem; diff --git a/client/coral-admin/src/containers/Dashboard/Dashboard.js b/client/coral-admin/src/containers/Dashboard/Dashboard.js index fcccb36b3..282772403 100644 --- a/client/coral-admin/src/containers/Dashboard/Dashboard.js +++ b/client/coral-admin/src/containers/Dashboard/Dashboard.js @@ -1,20 +1,15 @@ import React from 'react'; import styles from './Dashboard.css'; -import FlagWidget from '../../components/FlagWidget'; -import LikeWidget from '../../components/LikeWidget'; +import FlagWidget from './FlagWidget'; +import LikeWidget from './LikeWidget'; +import MostLikedCommentsWidget from './MostLikedCommentsWidget'; const Dashboard = () => { return (
-
- -
-
-

Top ten comments with the most likes

-
-
- -
+ + +
); }; diff --git a/client/coral-admin/src/components/FlagWidget.js b/client/coral-admin/src/containers/Dashboard/FlagWidget.js similarity index 98% rename from client/coral-admin/src/components/FlagWidget.js rename to client/coral-admin/src/containers/Dashboard/FlagWidget.js index a37ddcd2c..4fb993d35 100644 --- a/client/coral-admin/src/components/FlagWidget.js +++ b/client/coral-admin/src/containers/Dashboard/FlagWidget.js @@ -18,7 +18,7 @@ const FlagWidget = (props) => { const {data: {metrics: assets}} = props; return ( -
+

Top Ten Articles with the most flagged comments

diff --git a/client/coral-admin/src/components/LikeWidget.js b/client/coral-admin/src/containers/Dashboard/LikeWidget.js similarity index 98% rename from client/coral-admin/src/components/LikeWidget.js rename to client/coral-admin/src/containers/Dashboard/LikeWidget.js index ac9e111ea..0f6ea2ba0 100644 --- a/client/coral-admin/src/components/LikeWidget.js +++ b/client/coral-admin/src/containers/Dashboard/LikeWidget.js @@ -18,7 +18,7 @@ const LikeWidget = (props) => { const {data: {metrics: assets}} = props; return ( -
+

Top Ten Articles with the most likes

diff --git a/client/coral-admin/src/containers/Dashboard/MostLikedCommentsWidget.js b/client/coral-admin/src/containers/Dashboard/MostLikedCommentsWidget.js new file mode 100644 index 000000000..6e7d03185 --- /dev/null +++ b/client/coral-admin/src/containers/Dashboard/MostLikedCommentsWidget.js @@ -0,0 +1,35 @@ +import React from 'react'; +import {compose} from 'react-apollo'; +import {mostLikedComments} from 'coral-admin/src/graphql/queries'; +import I18n from 'coral-framework/modules/i18n/i18n'; +import translations from 'coral-admin/src/translations'; +import ModerationQueue from 'coral-admin/src/containers/ModerationQueue/ModerationQueue'; +import {Spinner} from 'coral-ui'; +import styles from './Widget.css'; + +const lang = new I18n(translations); + +const MostLikedCommentsWidget = props => { + + if (props.data.loading) { + return ; + } + + const {data: {comments}} = props; + + console.log('MostLikedCommentsWidget', comments); + + return ( +
+

most liked comments

+ {}} + acceptComment={() => {}} + rejectComment={() => {}} /> +
+ ); +}; + +export default compose(mostLikedComments)(MostLikedCommentsWidget); diff --git a/client/coral-admin/src/components/Widget.css b/client/coral-admin/src/containers/Dashboard/Widget.css similarity index 75% rename from client/coral-admin/src/components/Widget.css rename to client/coral-admin/src/containers/Dashboard/Widget.css index f40da403d..d9cce2043 100644 --- a/client/coral-admin/src/components/Widget.css +++ b/client/coral-admin/src/containers/Dashboard/Widget.css @@ -1,3 +1,11 @@ +.widget { + box-sizing: border-box; + margin: 10px 5px 5px 5px; + box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.2); + padding: 15px; + width: calc(50% - 10px); +} + .heading { margin: 0; font-size: 1.5rem; diff --git a/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js b/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js index f685ac094..9c68d0728 100644 --- a/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js +++ b/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js @@ -66,6 +66,8 @@ class ModerationContainer extends Component { } } + const comments = data[activeTab]; + return (
@@ -76,9 +78,8 @@ class ModerationContainer extends Component { flaggedCount={data.flaggedCount} /> { +const ModerationQueue = ({comments, ...props}) => { return (
    { - props.data[activeTab].map((comment, i) => { + comments.map((comment, i) => { const status = comment.action_summaries ? 'FLAGGED' : comment.status; return { }; ModerationQueue.propTypes = { - data: PropTypes.object.isRequired + comments: PropTypes.array.isRequired }; export default ModerationQueue; diff --git a/client/coral-admin/src/graphql/queries/metrics.graphql b/client/coral-admin/src/graphql/queries/assetMetrics.graphql similarity index 80% rename from client/coral-admin/src/graphql/queries/metrics.graphql rename to client/coral-admin/src/graphql/queries/assetMetrics.graphql index 9a226d8bc..caed174b4 100644 --- a/client/coral-admin/src/graphql/queries/metrics.graphql +++ b/client/coral-admin/src/graphql/queries/assetMetrics.graphql @@ -13,7 +13,7 @@ fragment metrics on Asset { } query Metrics ($from: Date!, $to: Date!, $sort: ACTION_TYPE!) { - metrics(from: $from, to: $to, sort: $sort) { + metrics: assetMetrics(from: $from, to: $to, sort: $sort) { ...metrics } } diff --git a/client/coral-admin/src/graphql/queries/commentMetrics.graphql b/client/coral-admin/src/graphql/queries/commentMetrics.graphql new file mode 100644 index 000000000..59a89739c --- /dev/null +++ b/client/coral-admin/src/graphql/queries/commentMetrics.graphql @@ -0,0 +1,19 @@ +query CommentMetrics ($from: Date!, $to: Date!, $sort: ACTION_TYPE!) { + comments: commentMetrics(from: $from, to: $to, sort: $sort) { + id + body + user { + status + username + } + asset { + id + title + } + created_at + action_summaries { + type: __typename + count + } + } +} diff --git a/client/coral-admin/src/graphql/queries/index.js b/client/coral-admin/src/graphql/queries/index.js index 1628a4ac8..ceedffd9d 100644 --- a/client/coral-admin/src/graphql/queries/index.js +++ b/client/coral-admin/src/graphql/queries/index.js @@ -1,9 +1,10 @@ import {graphql} from 'react-apollo'; -import METRICS from './metrics.graphql'; +import ASSET_METRICS from './assetMetrics.graphql'; +import COMMENT_METRICS from './commentMetrics.graphql'; import MOD_QUEUE_QUERY from './modQueueQuery.graphql'; -export const mostFlags = graphql(METRICS, { +export const mostFlags = graphql(ASSET_METRICS, { options: () => { // currently hard-coded per Greg's advice @@ -19,7 +20,23 @@ export const mostFlags = graphql(METRICS, { } }); -export const mostLikes = graphql(METRICS, { +export const mostLikes = graphql(ASSET_METRICS, { + options: () => { + + // currently hard-coded per Greg's advice + const fiveMinutesAgo = new Date(); + fiveMinutesAgo.setMinutes(fiveMinutesAgo.getMinutes() - 5); + return { + variables: { + sort: 'LIKE', + from: fiveMinutesAgo.toISOString(), + to: new Date().toISOString() + } + }; + } +}); + +export const mostLikedComments = graphql(COMMENT_METRICS, { options: () => { // currently hard-coded per Greg's advice diff --git a/client/coral-sign-in/components/SignUpContent.js b/client/coral-sign-in/components/SignUpContent.js index 6a781675b..216349412 100644 --- a/client/coral-sign-in/components/SignUpContent.js +++ b/client/coral-sign-in/components/SignUpContent.js @@ -138,12 +138,9 @@ class SignUpContent extends React.Component {
}
- - {lang.t('signIn.alreadyHaveAnAccount')} - changeView('SIGNIN')}> - {lang.t('signIn.signIn')} - - + {lang.t('signIn.alreadyHaveAnAccount')} changeView('SIGNIN')}> + {lang.t('signIn.signIn')} +
); From 691d00121366f7f2e14bc2a65cd1e76b61343d2d Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Wed, 22 Feb 2017 10:49:48 -0700 Subject: [PATCH 008/132] simplify a bit --- client/coral-admin/src/containers/Dashboard/FlagWidget.js | 2 +- client/coral-admin/src/containers/Dashboard/LikeWidget.js | 2 +- client/coral-admin/src/graphql/queries/assetMetrics.graphql | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/client/coral-admin/src/containers/Dashboard/FlagWidget.js b/client/coral-admin/src/containers/Dashboard/FlagWidget.js index 4fb993d35..8c334d2b8 100644 --- a/client/coral-admin/src/containers/Dashboard/FlagWidget.js +++ b/client/coral-admin/src/containers/Dashboard/FlagWidget.js @@ -15,7 +15,7 @@ const FlagWidget = (props) => { return ; } - const {data: {metrics: assets}} = props; + const {data: {assets}} = props; return (
diff --git a/client/coral-admin/src/containers/Dashboard/LikeWidget.js b/client/coral-admin/src/containers/Dashboard/LikeWidget.js index 0f6ea2ba0..09dc5606e 100644 --- a/client/coral-admin/src/containers/Dashboard/LikeWidget.js +++ b/client/coral-admin/src/containers/Dashboard/LikeWidget.js @@ -15,7 +15,7 @@ const LikeWidget = (props) => { return ; } - const {data: {metrics: assets}} = props; + const {data: {assets}} = props; return (
diff --git a/client/coral-admin/src/graphql/queries/assetMetrics.graphql b/client/coral-admin/src/graphql/queries/assetMetrics.graphql index caed174b4..de0eb1fe8 100644 --- a/client/coral-admin/src/graphql/queries/assetMetrics.graphql +++ b/client/coral-admin/src/graphql/queries/assetMetrics.graphql @@ -13,7 +13,7 @@ fragment metrics on Asset { } query Metrics ($from: Date!, $to: Date!, $sort: ACTION_TYPE!) { - metrics: assetMetrics(from: $from, to: $to, sort: $sort) { + assets: assetMetrics(from: $from, to: $to, sort: $sort) { ...metrics } } From 111b956522df820b008b112406cf51f3c4b7e744 Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Wed, 22 Feb 2017 13:10:50 -0700 Subject: [PATCH 009/132] change index route to Dashboard component --- client/coral-admin/src/AppRouter.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/coral-admin/src/AppRouter.js b/client/coral-admin/src/AppRouter.js index d96bacfe0..38d06dcb1 100644 --- a/client/coral-admin/src/AppRouter.js +++ b/client/coral-admin/src/AppRouter.js @@ -15,7 +15,7 @@ const routes = (
- + From e6b78a3e63fe3b5f336c1470ccbeee702afa1277 Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Wed, 22 Feb 2017 13:33:50 -0700 Subject: [PATCH 010/132] change some copy --- client/coral-admin/src/containers/Dashboard/FlagWidget.js | 2 +- client/coral-admin/src/containers/Dashboard/LikeWidget.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/coral-admin/src/containers/Dashboard/FlagWidget.js b/client/coral-admin/src/containers/Dashboard/FlagWidget.js index 8c334d2b8..370010c35 100644 --- a/client/coral-admin/src/containers/Dashboard/FlagWidget.js +++ b/client/coral-admin/src/containers/Dashboard/FlagWidget.js @@ -19,7 +19,7 @@ const FlagWidget = (props) => { return (
-

Top Ten Articles with the most flagged comments

+

Articles with the most flags

diff --git a/client/coral-admin/src/containers/Dashboard/LikeWidget.js b/client/coral-admin/src/containers/Dashboard/LikeWidget.js index 09dc5606e..9c46fbbe0 100644 --- a/client/coral-admin/src/containers/Dashboard/LikeWidget.js +++ b/client/coral-admin/src/containers/Dashboard/LikeWidget.js @@ -19,7 +19,7 @@ const LikeWidget = (props) => { return (
-

Top Ten Articles with the most likes

+

Articles with the most likes

From 9e759c7667ceebd1fd4b975f78db3f1333866b9d Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 22 Feb 2017 13:55:48 -0700 Subject: [PATCH 011/132] Adjusted BE beheviour --- .../Dashboard/MostLikedCommentsWidget.js | 8 ++- graph/loaders/metrics.js | 42 +++++++----- test/graph/loaders/metrics.js | 66 +++++++++++++++++++ 3 files changed, 96 insertions(+), 20 deletions(-) create mode 100644 test/graph/loaders/metrics.js diff --git a/client/coral-admin/src/containers/Dashboard/MostLikedCommentsWidget.js b/client/coral-admin/src/containers/Dashboard/MostLikedCommentsWidget.js index 6e7d03185..39f01b41b 100644 --- a/client/coral-admin/src/containers/Dashboard/MostLikedCommentsWidget.js +++ b/client/coral-admin/src/containers/Dashboard/MostLikedCommentsWidget.js @@ -1,13 +1,15 @@ import React from 'react'; import {compose} from 'react-apollo'; import {mostLikedComments} from 'coral-admin/src/graphql/queries'; -import I18n from 'coral-framework/modules/i18n/i18n'; -import translations from 'coral-admin/src/translations'; + +// import I18n from 'coral-framework/modules/i18n/i18n'; +// import translations from 'coral-admin/src/translations'; + import ModerationQueue from 'coral-admin/src/containers/ModerationQueue/ModerationQueue'; import {Spinner} from 'coral-ui'; import styles from './Widget.css'; -const lang = new I18n(translations); +// const lang = new I18n(translations); const MostLikedCommentsWidget = props => { diff --git a/graph/loaders/metrics.js b/graph/loaders/metrics.js index 8591ecefe..1b0719d0f 100644 --- a/graph/loaders/metrics.js +++ b/graph/loaders/metrics.js @@ -17,6 +17,10 @@ const getAssetMetrics = ({loaders: {Metrics, Assets}}, {from, to, sort, limit}) .then((actionSummaries) => { commentMetrics = actionSummaries.reduce((acc, {item_id, action_type, count}) => { + if (action_type !== sort) { + return acc; + } + if (!(item_id in acc)) { acc[item_id] = []; } @@ -47,29 +51,24 @@ const getAssetMetrics = ({loaders: {Metrics, Assets}}, {from, to, sort, limit}) })); return {action_summaries, id: asset_id}; - }); + }) + + .filter((asset) => { + let contextActionSummary = asset.action_summaries.find((({action_type}) => action_type === sort)); + if (contextActionSummary === null) { + return false; + } + + return true; + }) // Sort these metrics by the predefined sort order. This will ensure that // if the action summary does not exist on the object, that it is less // prefered over the one that does have it. - assetMetrics.sort((a, b) => { + .sort((a, b) => { let aActionSummary = a.action_summaries.find((({action_type}) => action_type === sort)); let bActionSummary = b.action_summaries.find((({action_type}) => action_type === sort)); - // If either a or b don't have this action type, then one of them will - // automatically win. - if (aActionSummary == null || bActionSummary == null) { - if (bActionSummary != null) { - return 1; - } - - if (aActionSummary != null) { - return -1; - } - - return 0; - } - // Both of them had an actionCount, hence we can determine that we could // compare the actual values directly. return bActionSummary.actionCount - aActionSummary.actionCount; @@ -138,7 +137,16 @@ const getCommentMetrics = ({loaders: {Metrics, Comments}}, {from, to, sort, limi commentActionSummaries = _.groupBy(actionSummaries, 'item_id'); - let commentIDs = _.uniq(actionSummaries.map(({item_id}) => item_id)); + // Grab the comment id's for comment where they have at least one of the + // actions being sorted by. + let commentIDs = Object.keys(commentActionSummaries).filter((item_id) => { + let contextActionSummary = commentActionSummaries[item_id].find(({action_type}) => action_type === sort); + if (contextActionSummary == null) { + return false; + } + + return true; + }); // Only keep the top `limit`. commentIDs = commentIDs.slice(0, limit); diff --git a/test/graph/loaders/metrics.js b/test/graph/loaders/metrics.js new file mode 100644 index 000000000..303b40897 --- /dev/null +++ b/test/graph/loaders/metrics.js @@ -0,0 +1,66 @@ +const {expect} = require('chai'); +const {graphql} = require('graphql'); + +const schema = require('../../../graph/schema'); +const Context = require('../../../graph/context'); +const UserModel = require('../../../models/user'); +const SettingsService = require('../../../services/settings'); +const ActionModel = require('../../../models/action'); +const CommentModel = require('../../../models/comment'); + +describe('graph.loaders.Metrics', () => { + beforeEach(() => SettingsService.init()); + + describe('#Comments', () => { + const query = ` + query CommentMetrics($from: Date!, $to: Date!) { + liked: commentMetrics(from: $from, to: $to, sort: LIKE) { + id + } + flagged: commentMetrics(from: $from, to: $to, sort: FLAG) { + id + } + } + `; + + describe('different comment states', () => { + + beforeEach(() => CommentModel.create([ + {id: '1', body: 'a new comment!'} + ])); + + [ + {liked: 0, flagged: 0, actions: []}, + {liked: 1, flagged: 0, actions: [{action_type: 'LIKE', item_id: '1', item_type: 'COMMENTS'}]}, + {liked: 0, flagged: 1, actions: [{action_type: 'FLAG', item_id: '1', item_type: 'COMMENTS'}]}, + {liked: 1, flagged: 1, actions: [ + {action_type: 'FLAG', item_id: '1', item_type: 'COMMENTS'}, + {action_type: 'LIKE', item_id: '1', item_type: 'COMMENTS'} + ]} + ].forEach(({liked, flagged, actions}) => { + + describe(`with actions=${actions.length}`, () => { + + beforeEach(() => ActionModel.create(actions)); + + it(`returns the correct amount of metrics liked=${liked} flagged=${flagged}`, () => { + const context = new Context({user: new UserModel({roles: ['ADMIN']})}); + + return graphql(schema, query, {}, context, { + from: (new Date()).setMinutes((new Date()).getMinutes() - 5), + to: (new Date()).setMinutes((new Date()).getMinutes() + 5) + }) + .then(({data, errors}) => { + expect(errors).to.be.undefined; + expect(data.liked).to.have.length(liked); + expect(data.flagged).to.have.length(flagged); + }); + }); + + }); + + }); + + }); + }); +}); From 2f314c6937069819b510502fa1a6a26c44220167 Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Thu, 23 Feb 2017 14:29:51 -0700 Subject: [PATCH 012/132] omg, a bunch of UI madness --- .../src/containers/Dashboard/Dashboard.js | 79 ++++++++++++++++--- .../src/containers/Dashboard/FlagWidget.js | 12 +-- .../src/containers/Dashboard/LikeWidget.js | 8 +- .../Dashboard/MostLikedCommentsWidget.js | 63 ++++++++------- .../src/graphql/queries/assetMetrics.graphql | 19 ----- .../graphql/queries/commentMetrics.graphql | 19 ----- .../coral-admin/src/graphql/queries/index.js | 66 ++++------------ .../src/graphql/queries/metrics.graphql | 39 +++++++++ .../src/graphql/queries/mostFlags.graphql | 14 ---- 9 files changed, 164 insertions(+), 155 deletions(-) delete mode 100644 client/coral-admin/src/graphql/queries/assetMetrics.graphql delete mode 100644 client/coral-admin/src/graphql/queries/commentMetrics.graphql create mode 100644 client/coral-admin/src/graphql/queries/metrics.graphql delete mode 100644 client/coral-admin/src/graphql/queries/mostFlags.graphql diff --git a/client/coral-admin/src/containers/Dashboard/Dashboard.js b/client/coral-admin/src/containers/Dashboard/Dashboard.js index 282772403..74bbce9fb 100644 --- a/client/coral-admin/src/containers/Dashboard/Dashboard.js +++ b/client/coral-admin/src/containers/Dashboard/Dashboard.js @@ -1,17 +1,76 @@ import React from 'react'; import styles from './Dashboard.css'; +import {graphql} from 'react-apollo'; +import {connect} from 'react-redux'; import FlagWidget from './FlagWidget'; import LikeWidget from './LikeWidget'; -import MostLikedCommentsWidget from './MostLikedCommentsWidget'; +import METRICS from 'coral-admin/src/graphql/queries/metrics.graphql'; +// import MostLikedCommentsWidget from './MostLikedCommentsWidget'; +import {showBanUserDialog, hideBanUserDialog} from 'coral-admin/src/actions/moderation'; +import {Spinner} from 'coral-ui'; -const Dashboard = () => { - return ( -
- - - -
- ); +class Dashboard extends React.Component { + + render () { + + if (this.props.data && this.props.data.loading) { + return ; + } + + console.log(this.props.data); + + const {data: {assetsByLike, assetsByFlag}} = this.props; + + console.log('assetsByLike', assetsByLike); + console.log('assetsByFlag', assetsByFlag); + + // const {moderation, settings} = this.props; + + return ( +
+ {assetsByFlag && } + {/**/} + {assetsByLike && } +
+ ); + } +} + +let fiveMinutesAgo = new Date(); +fiveMinutesAgo.setMinutes(fiveMinutesAgo.getMinutes() - 5); +fiveMinutesAgo = fiveMinutesAgo.toISOString(); +const now = new Date().toISOString(); + +const getMetrics = graphql(METRICS, { + options: () => { + + return { + variables: { + from: fiveMinutesAgo, + // from: '2017-02-23T16:09:44.235Z', + to: now + // to: '2017-02-23T19:30:23.251Z' + } + }; + } +}); + +const DashboardWithData = getMetrics(Dashboard); + +const mapStateToProps = state => { + return { + settings: state.settings.toJS(), + moderation: state.moderation.toJS() + }; }; -export default Dashboard; +const mapDispatchToProps = dispatch => ({ + showBanUserDialog: (user, commentId) => dispatch(showBanUserDialog(user, commentId)), + hideBanUserDialog: () => dispatch(hideBanUserDialog(false)) +}); + +export default connect(mapStateToProps, mapDispatchToProps)(DashboardWithData); diff --git a/client/coral-admin/src/containers/Dashboard/FlagWidget.js b/client/coral-admin/src/containers/Dashboard/FlagWidget.js index 370010c35..ada1f03f3 100644 --- a/client/coral-admin/src/containers/Dashboard/FlagWidget.js +++ b/client/coral-admin/src/containers/Dashboard/FlagWidget.js @@ -1,21 +1,13 @@ import React from 'react'; -import {compose} from 'react-apollo'; -import {mostFlags} from 'coral-admin/src/graphql/queries'; import {Link} from 'react-router'; import styles from './Widget.css'; import I18n from 'coral-framework/modules/i18n/i18n'; import translations from 'coral-admin/src/translations'; -import {Spinner} from 'coral-ui'; const lang = new I18n(translations); const FlagWidget = (props) => { - - if (props.data.loading) { - return ; - } - - const {data: {assets}} = props; + const {assets} = props; return (
@@ -57,4 +49,4 @@ const FlagWidget = (props) => { ); }; -export default compose(mostFlags)(FlagWidget); +export default FlagWidget; diff --git a/client/coral-admin/src/containers/Dashboard/LikeWidget.js b/client/coral-admin/src/containers/Dashboard/LikeWidget.js index 9c46fbbe0..9358b1f63 100644 --- a/client/coral-admin/src/containers/Dashboard/LikeWidget.js +++ b/client/coral-admin/src/containers/Dashboard/LikeWidget.js @@ -11,11 +11,7 @@ const lang = new I18n(translations); const LikeWidget = (props) => { - if (props.data.loading) { - return ; - } - - const {data: {assets}} = props; + const {assets} = props; return (
@@ -58,4 +54,4 @@ const LikeWidget = (props) => { ); }; -export default compose(mostLikes)(LikeWidget); +export default LikeWidget; diff --git a/client/coral-admin/src/containers/Dashboard/MostLikedCommentsWidget.js b/client/coral-admin/src/containers/Dashboard/MostLikedCommentsWidget.js index 39f01b41b..600a09c13 100644 --- a/client/coral-admin/src/containers/Dashboard/MostLikedCommentsWidget.js +++ b/client/coral-admin/src/containers/Dashboard/MostLikedCommentsWidget.js @@ -1,37 +1,44 @@ import React from 'react'; -import {compose} from 'react-apollo'; -import {mostLikedComments} from 'coral-admin/src/graphql/queries'; - -// import I18n from 'coral-framework/modules/i18n/i18n'; -// import translations from 'coral-admin/src/translations'; - +import I18n from 'coral-framework/modules/i18n/i18n'; +import translations from 'coral-admin/src/translations'; import ModerationQueue from 'coral-admin/src/containers/ModerationQueue/ModerationQueue'; import {Spinner} from 'coral-ui'; import styles from './Widget.css'; +import BanUserDialog from 'coral-admin/src/components/BanUserDialog'; -// const lang = new I18n(translations); +const lang = new I18n(translations); -const MostLikedCommentsWidget = props => { +class MostLikedCommentsWidget extends React.Component { - if (props.data.loading) { - return ; + render () { + // console.log('render! loading?', this.props.data.loading); + + // if (this.props.data.loading) { + // return ; + // } + + // const { + // comments, + // moderation, + // settings, + // showBanUserDialog, + // hideBanUserDialog + // } = this.props; + + // console.log('MostLikedCommentsWidget', comments); + + return ( +
+

{lang.t('most_liked_comments')}

+ {/* {}} + rejectComment={() => {}} />*/} +
+ ); } +} - const {data: {comments}} = props; - - console.log('MostLikedCommentsWidget', comments); - - return ( -
-

most liked comments

- {}} - acceptComment={() => {}} - rejectComment={() => {}} /> -
- ); -}; - -export default compose(mostLikedComments)(MostLikedCommentsWidget); +export default MostLikedCommentsWidget; diff --git a/client/coral-admin/src/graphql/queries/assetMetrics.graphql b/client/coral-admin/src/graphql/queries/assetMetrics.graphql deleted file mode 100644 index de0eb1fe8..000000000 --- a/client/coral-admin/src/graphql/queries/assetMetrics.graphql +++ /dev/null @@ -1,19 +0,0 @@ -fragment metrics on Asset { - id - title - url - commentCount - author - created_at - action_summaries { - type: __typename - actionCount - actionableItemCount - } -} - -query Metrics ($from: Date!, $to: Date!, $sort: ACTION_TYPE!) { - assets: assetMetrics(from: $from, to: $to, sort: $sort) { - ...metrics - } -} diff --git a/client/coral-admin/src/graphql/queries/commentMetrics.graphql b/client/coral-admin/src/graphql/queries/commentMetrics.graphql deleted file mode 100644 index 59a89739c..000000000 --- a/client/coral-admin/src/graphql/queries/commentMetrics.graphql +++ /dev/null @@ -1,19 +0,0 @@ -query CommentMetrics ($from: Date!, $to: Date!, $sort: ACTION_TYPE!) { - comments: commentMetrics(from: $from, to: $to, sort: $sort) { - id - body - user { - status - username - } - asset { - id - title - } - created_at - action_summaries { - type: __typename - count - } - } -} diff --git a/client/coral-admin/src/graphql/queries/index.js b/client/coral-admin/src/graphql/queries/index.js index ceedffd9d..d6011e056 100644 --- a/client/coral-admin/src/graphql/queries/index.js +++ b/client/coral-admin/src/graphql/queries/index.js @@ -1,56 +1,24 @@ import {graphql} from 'react-apollo'; -import ASSET_METRICS from './assetMetrics.graphql'; -import COMMENT_METRICS from './commentMetrics.graphql'; +import METRICS from './metrics.graphql'; import MOD_QUEUE_QUERY from './modQueueQuery.graphql'; -export const mostFlags = graphql(ASSET_METRICS, { - options: () => { - - // currently hard-coded per Greg's advice - const fiveMinutesAgo = new Date(); - fiveMinutesAgo.setMinutes(fiveMinutesAgo.getMinutes() - 5); - return { - variables: { - sort: 'FLAG', - from: fiveMinutesAgo.toISOString(), - to: new Date().toISOString() - } - }; - } -}); - -export const mostLikes = graphql(ASSET_METRICS, { - options: () => { - - // currently hard-coded per Greg's advice - const fiveMinutesAgo = new Date(); - fiveMinutesAgo.setMinutes(fiveMinutesAgo.getMinutes() - 5); - return { - variables: { - sort: 'LIKE', - from: fiveMinutesAgo.toISOString(), - to: new Date().toISOString() - } - }; - } -}); - -export const mostLikedComments = graphql(COMMENT_METRICS, { - options: () => { - - // currently hard-coded per Greg's advice - const fiveMinutesAgo = new Date(); - fiveMinutesAgo.setMinutes(fiveMinutesAgo.getMinutes() - 5); - return { - variables: { - sort: 'LIKE', - from: fiveMinutesAgo.toISOString(), - to: new Date().toISOString() - } - }; - } -}); +// export const getMetrics = graphql(METRICS, { +// options: () => { +// +// // currently hard-coded per Greg's advice +// const fiveMinutesAgo = new Date(); +// fiveMinutesAgo.setMinutes(fiveMinutesAgo.getMinutes() - 5); +// return { +// variables: { +// // from: fiveMinutesAgo.toISOString(), +// from: '2017-02-23T16:09:44.235Z', +// // to: new Date().toISOString() +// to: '2017-02-23T19:30:23.251Z' +// } +// }; +// } +// }); export const modQueueQuery = graphql(MOD_QUEUE_QUERY, { options: ({params: {id = null}}) => { diff --git a/client/coral-admin/src/graphql/queries/metrics.graphql b/client/coral-admin/src/graphql/queries/metrics.graphql new file mode 100644 index 000000000..4e713c0b7 --- /dev/null +++ b/client/coral-admin/src/graphql/queries/metrics.graphql @@ -0,0 +1,39 @@ +fragment metrics on Asset { + id + title + url + commentCount + author + created_at + action_summaries { + type: __typename + actionCount + actionableItemCount + } +} + +query Metrics ($from: Date!, $to: Date!) { + assetsByFlag: assetMetrics(from: $from, to: $to, sort: FLAG) { + ...metrics + } + assetsByLike: assetMetrics(from: $from, to: $to, sort: LIKE) { + ...metrics + } + mostLikedComments: commentMetrics(from: $from, to: $to, sort: LIKE) { + id + body + user { + status + username + } + asset { + id + title + } + created_at + action_summaries { + type: __typename + count + } + } +} diff --git a/client/coral-admin/src/graphql/queries/mostFlags.graphql b/client/coral-admin/src/graphql/queries/mostFlags.graphql deleted file mode 100644 index 182ea0c8b..000000000 --- a/client/coral-admin/src/graphql/queries/mostFlags.graphql +++ /dev/null @@ -1,14 +0,0 @@ -query Metrics ($from: Date!, $to: Date!, $sort: ACTION_TYPE!) { - metrics(from: $from, to: $to, sort: $sort) { - id - title - url - commentCount - author - created_at - action_summaries { - actionCount - actionableItemCount - } - } -} From 30b6259e872dfd65851d6bffc913df96f54f3a21 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Thu, 23 Feb 2017 14:43:25 -0700 Subject: [PATCH 013/132] Patched bug with asset metrics --- graph/loaders/metrics.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graph/loaders/metrics.js b/graph/loaders/metrics.js index 1b0719d0f..a22cbb58f 100644 --- a/graph/loaders/metrics.js +++ b/graph/loaders/metrics.js @@ -31,7 +31,7 @@ const getAssetMetrics = ({loaders: {Metrics, Assets}}, {from, to, sort, limit}) }, {}); // Collect just the comment id's. - let commentIDs = _.uniq(actionSummaries.map((as) => as.item_id)); + let commentIDs = Object.keys(commentMetrics); // Find those comments. return Metrics.getSpecificComments.loadMany(commentIDs); From be25d6f56d9b2770493e05ee7886559e6ebb1587 Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Thu, 23 Feb 2017 15:46:44 -0700 Subject: [PATCH 014/132] "works" --- .../src/containers/Dashboard/Dashboard.css | 1 - .../src/containers/Dashboard/Dashboard.js | 33 ++++++----- .../Dashboard/MostLikedCommentsWidget.js | 59 +++++++++---------- .../src/containers/Dashboard/Widget.css | 2 +- 4 files changed, 47 insertions(+), 48 deletions(-) diff --git a/client/coral-admin/src/containers/Dashboard/Dashboard.css b/client/coral-admin/src/containers/Dashboard/Dashboard.css index a23927d8a..72b9bd90c 100644 --- a/client/coral-admin/src/containers/Dashboard/Dashboard.css +++ b/client/coral-admin/src/containers/Dashboard/Dashboard.css @@ -1,6 +1,5 @@ .Dashboard { display: flex; - flex-wrap: wrap; } .heading { diff --git a/client/coral-admin/src/containers/Dashboard/Dashboard.js b/client/coral-admin/src/containers/Dashboard/Dashboard.js index 74bbce9fb..10d3b3ba3 100644 --- a/client/coral-admin/src/containers/Dashboard/Dashboard.js +++ b/client/coral-admin/src/containers/Dashboard/Dashboard.js @@ -1,12 +1,13 @@ import React from 'react'; import styles from './Dashboard.css'; -import {graphql} from 'react-apollo'; +import {graphql, compose} from 'react-apollo'; import {connect} from 'react-redux'; import FlagWidget from './FlagWidget'; import LikeWidget from './LikeWidget'; import METRICS from 'coral-admin/src/graphql/queries/metrics.graphql'; -// import MostLikedCommentsWidget from './MostLikedCommentsWidget'; +import MostLikedCommentsWidget from './MostLikedCommentsWidget'; import {showBanUserDialog, hideBanUserDialog} from 'coral-admin/src/actions/moderation'; +import {banUser, setCommentStatus} from 'coral-admin/src/graphql/mutations'; import {Spinner} from 'coral-ui'; class Dashboard extends React.Component { @@ -19,30 +20,34 @@ class Dashboard extends React.Component { console.log(this.props.data); - const {data: {assetsByLike, assetsByFlag}} = this.props; + const {data: {assetsByLike, assetsByFlag, mostLikedComments}} = this.props; console.log('assetsByLike', assetsByLike); console.log('assetsByFlag', assetsByFlag); - // const {moderation, settings} = this.props; + const {moderation, settings} = this.props; return (
- {assetsByFlag && } - {/* + */} - {assetsByLike && } + hideBanUserDialog={this.props.hideBanUserDialog} /> +
); } } -let fiveMinutesAgo = new Date(); -fiveMinutesAgo.setMinutes(fiveMinutesAgo.getMinutes() - 5); -fiveMinutesAgo = fiveMinutesAgo.toISOString(); +let then = new Date(); +then.setMinutes(then.getMinutes() - 205); +then = then.toISOString(); const now = new Date().toISOString(); const getMetrics = graphql(METRICS, { @@ -50,16 +55,14 @@ const getMetrics = graphql(METRICS, { return { variables: { - from: fiveMinutesAgo, - // from: '2017-02-23T16:09:44.235Z', + from: then, to: now - // to: '2017-02-23T19:30:23.251Z' } }; } }); -const DashboardWithData = getMetrics(Dashboard); +const DashboardWithData = compose(getMetrics, setCommentStatus, banUser)(Dashboard); const mapStateToProps = state => { return { diff --git a/client/coral-admin/src/containers/Dashboard/MostLikedCommentsWidget.js b/client/coral-admin/src/containers/Dashboard/MostLikedCommentsWidget.js index 600a09c13..5b0427acb 100644 --- a/client/coral-admin/src/containers/Dashboard/MostLikedCommentsWidget.js +++ b/client/coral-admin/src/containers/Dashboard/MostLikedCommentsWidget.js @@ -8,37 +8,34 @@ import BanUserDialog from 'coral-admin/src/components/BanUserDialog'; const lang = new I18n(translations); -class MostLikedCommentsWidget extends React.Component { +const MostLikedCommentsWidget = props => { + const { + comments, + moderation, + settings, + handleBanUser, + showBanUserDialog, + hideBanUserDialog, + acceptComment, + rejectComment + } = props; - render () { - // console.log('render! loading?', this.props.data.loading); - - // if (this.props.data.loading) { - // return ; - // } - - // const { - // comments, - // moderation, - // settings, - // showBanUserDialog, - // hideBanUserDialog - // } = this.props; - - // console.log('MostLikedCommentsWidget', comments); - - return ( -
-

{lang.t('most_liked_comments')}

- {/* {}} - rejectComment={() => {}} />*/} -
- ); - } -} + return ( +
+

{lang.t('most_liked_comments')}

+ + +
+ ); +}; export default MostLikedCommentsWidget; diff --git a/client/coral-admin/src/containers/Dashboard/Widget.css b/client/coral-admin/src/containers/Dashboard/Widget.css index d9cce2043..624b72519 100644 --- a/client/coral-admin/src/containers/Dashboard/Widget.css +++ b/client/coral-admin/src/containers/Dashboard/Widget.css @@ -3,7 +3,7 @@ margin: 10px 5px 5px 5px; box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.2); padding: 15px; - width: calc(50% - 10px); + flex: 1; } .heading { From dc5f95ec7f20cba1f6cdcd6e88fe18dcff04a19c Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Fri, 24 Feb 2017 08:50:52 -0700 Subject: [PATCH 015/132] simplify moderationqueue --- .../src/containers/ModerationQueue/ModerationQueue.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/client/coral-admin/src/containers/ModerationQueue/ModerationQueue.js b/client/coral-admin/src/containers/ModerationQueue/ModerationQueue.js index a0e6332b5..b1792f720 100644 --- a/client/coral-admin/src/containers/ModerationQueue/ModerationQueue.js +++ b/client/coral-admin/src/containers/ModerationQueue/ModerationQueue.js @@ -12,7 +12,8 @@ const ModerationQueue = ({comments, ...props}) => {
    { - comments.map((comment, i) => { + comments.length + ? comments.map((comment, i) => { const status = comment.action_summaries ? 'FLAGGED' : comment.status; return { }; ModerationQueue.propTypes = { - suspectWords: PropTypes.arrayOf(PropTypes.string).isRequired + suspectWords: PropTypes.arrayOf(PropTypes.string).isRequired, currentAsset: PropTypes.object, showBanUserDialog: PropTypes.func.isRequired, rejectComment: PropTypes.func.isRequired, From c8c3c4acaf2adcc2c0e35b782ccfb6e63650c5ff Mon Sep 17 00:00:00 2001 From: riley Date: Fri, 24 Feb 2017 08:59:23 -0700 Subject: [PATCH 016/132] lint --- .../src/containers/Dashboard/LikeWidget.js | 3 --- .../Dashboard/MostLikedCommentsWidget.js | 1 - .../coral-admin/src/graphql/queries/index.js | 18 ------------------ 3 files changed, 22 deletions(-) diff --git a/client/coral-admin/src/containers/Dashboard/LikeWidget.js b/client/coral-admin/src/containers/Dashboard/LikeWidget.js index 9358b1f63..076958bcd 100644 --- a/client/coral-admin/src/containers/Dashboard/LikeWidget.js +++ b/client/coral-admin/src/containers/Dashboard/LikeWidget.js @@ -1,8 +1,5 @@ import React from 'react'; -import {compose} from 'react-apollo'; -import {mostLikes} from 'coral-admin/src/graphql/queries'; import {Link} from 'react-router'; -import {Spinner} from 'coral-ui'; import styles from './Widget.css'; import I18n from 'coral-framework/modules/i18n/i18n'; import translations from 'coral-admin/src/translations'; diff --git a/client/coral-admin/src/containers/Dashboard/MostLikedCommentsWidget.js b/client/coral-admin/src/containers/Dashboard/MostLikedCommentsWidget.js index 5b0427acb..0c41ac7c6 100644 --- a/client/coral-admin/src/containers/Dashboard/MostLikedCommentsWidget.js +++ b/client/coral-admin/src/containers/Dashboard/MostLikedCommentsWidget.js @@ -2,7 +2,6 @@ import React from 'react'; import I18n from 'coral-framework/modules/i18n/i18n'; import translations from 'coral-admin/src/translations'; import ModerationQueue from 'coral-admin/src/containers/ModerationQueue/ModerationQueue'; -import {Spinner} from 'coral-ui'; import styles from './Widget.css'; import BanUserDialog from 'coral-admin/src/components/BanUserDialog'; diff --git a/client/coral-admin/src/graphql/queries/index.js b/client/coral-admin/src/graphql/queries/index.js index d6011e056..022522500 100644 --- a/client/coral-admin/src/graphql/queries/index.js +++ b/client/coral-admin/src/graphql/queries/index.js @@ -1,25 +1,7 @@ import {graphql} from 'react-apollo'; -import METRICS from './metrics.graphql'; import MOD_QUEUE_QUERY from './modQueueQuery.graphql'; -// export const getMetrics = graphql(METRICS, { -// options: () => { -// -// // currently hard-coded per Greg's advice -// const fiveMinutesAgo = new Date(); -// fiveMinutesAgo.setMinutes(fiveMinutesAgo.getMinutes() - 5); -// return { -// variables: { -// // from: fiveMinutesAgo.toISOString(), -// from: '2017-02-23T16:09:44.235Z', -// // to: new Date().toISOString() -// to: '2017-02-23T19:30:23.251Z' -// } -// }; -// } -// }); - export const modQueueQuery = graphql(MOD_QUEUE_QUERY, { options: ({params: {id = null}}) => { return { From c283f193deceb61e5f07b423cd0e103933ff341c Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Fri, 24 Feb 2017 09:07:03 -0700 Subject: [PATCH 017/132] remove console.log --- client/coral-admin/src/containers/Dashboard/Dashboard.js | 6 ------ client/coral-admin/src/containers/Dashboard/LikeWidget.js | 1 - 2 files changed, 7 deletions(-) diff --git a/client/coral-admin/src/containers/Dashboard/Dashboard.js b/client/coral-admin/src/containers/Dashboard/Dashboard.js index 10d3b3ba3..51e46408d 100644 --- a/client/coral-admin/src/containers/Dashboard/Dashboard.js +++ b/client/coral-admin/src/containers/Dashboard/Dashboard.js @@ -18,13 +18,7 @@ class Dashboard extends React.Component { return ; } - console.log(this.props.data); - const {data: {assetsByLike, assetsByFlag, mostLikedComments}} = this.props; - - console.log('assetsByLike', assetsByLike); - console.log('assetsByFlag', assetsByFlag); - const {moderation, settings} = this.props; return ( diff --git a/client/coral-admin/src/containers/Dashboard/LikeWidget.js b/client/coral-admin/src/containers/Dashboard/LikeWidget.js index 076958bcd..82eecb049 100644 --- a/client/coral-admin/src/containers/Dashboard/LikeWidget.js +++ b/client/coral-admin/src/containers/Dashboard/LikeWidget.js @@ -29,7 +29,6 @@ const LikeWidget = (props) => { ? assets.map((asset, index) => { const flagSummary = asset.action_summaries.find(s => s.type === 'FlagAssetActionSummary'); const likeSummary = asset.action_summaries.find(s => s.type === 'LikeAssetActionSummary'); - console.log('LikeWidget', likeSummary); return (
From f5277ce5e3cdbabd9423b8b825bfec52951d9677 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Fri, 24 Feb 2017 09:56:18 -0700 Subject: [PATCH 018/132] Patched silly bug --- client/.eslintrc.json | 3 +- graph/loaders/metrics.js | 18 +------ test/graph/loaders/metrics.js | 89 ++++++++++++++++++++++++++++++++++- 3 files changed, 92 insertions(+), 18 deletions(-) diff --git a/client/.eslintrc.json b/client/.eslintrc.json index a935eaec6..1144f985d 100644 --- a/client/.eslintrc.json +++ b/client/.eslintrc.json @@ -18,6 +18,7 @@ ], "rules": { "react/jsx-uses-react": "error", - "react/jsx-uses-vars": "error" + "react/jsx-uses-vars": "error", + "no-console": ["warn", { "allow": ["warn", "error"] }] } } diff --git a/graph/loaders/metrics.js b/graph/loaders/metrics.js index a22cbb58f..2627d82d9 100644 --- a/graph/loaders/metrics.js +++ b/graph/loaders/metrics.js @@ -2,13 +2,12 @@ const _ = require('lodash'); const DataLoader = require('dataloader'); const {objectCacheKeyFn} = require('./util'); -const CommentModel = require('../../models/comment'); const ActionModel = require('../../models/action'); /** * Returns a list of assets with action metadata included on the models. */ -const getAssetMetrics = ({loaders: {Metrics, Assets}}, {from, to, sort, limit}) => { +const getAssetMetrics = ({loaders: {Metrics, Assets, Comments}}, {from, to, sort, limit}) => { let commentMetrics = {}; let assetMetrics = []; @@ -34,7 +33,7 @@ const getAssetMetrics = ({loaders: {Metrics, Assets}}, {from, to, sort, limit}) let commentIDs = Object.keys(commentMetrics); // Find those comments. - return Metrics.getSpecificComments.loadMany(commentIDs); + return Comments.get.loadMany(commentIDs); }) .then((comments) => { @@ -202,21 +201,8 @@ const getRecentActions = (context, {from, to}) => { ]); }; -const getSpecificComments = (context, ids) => { - return CommentModel.find({ - id: { - $in: ids - } - }) - .select({ - id: 1, - asset_id: 1 - }); -}; - module.exports = (context) => ({ Metrics: { - getSpecificComments: new DataLoader((ids) => getSpecificComments(context, ids)), getRecentActions: new DataLoader(([{from, to}]) => getRecentActions(context, {from, to}).then((as) => [as]), { batch: false, cacheKeyFn: objectCacheKeyFn('from', 'to') diff --git a/test/graph/loaders/metrics.js b/test/graph/loaders/metrics.js index 303b40897..032a59536 100644 --- a/test/graph/loaders/metrics.js +++ b/test/graph/loaders/metrics.js @@ -4,6 +4,7 @@ const {graphql} = require('graphql'); const schema = require('../../../graph/schema'); const Context = require('../../../graph/context'); const UserModel = require('../../../models/user'); +const AssetModel = require('../../../models/asset'); const SettingsService = require('../../../services/settings'); const ActionModel = require('../../../models/action'); const CommentModel = require('../../../models/comment'); @@ -26,7 +27,9 @@ describe('graph.loaders.Metrics', () => { describe('different comment states', () => { beforeEach(() => CommentModel.create([ - {id: '1', body: 'a new comment!'} + {id: '1', body: 'a new comment!'}, + {id: '2', body: 'a new comment!'}, + {id: '3', body: 'a new comment!'} ])); [ @@ -36,6 +39,12 @@ describe('graph.loaders.Metrics', () => { {liked: 1, flagged: 1, actions: [ {action_type: 'FLAG', item_id: '1', item_type: 'COMMENTS'}, {action_type: 'LIKE', item_id: '1', item_type: 'COMMENTS'} + ]}, + {liked: 3, flagged: 1, actions: [ + {action_type: 'LIKE', item_id: '1', item_type: 'COMMENTS'}, + {action_type: 'LIKE', item_id: '2', item_type: 'COMMENTS'}, + {action_type: 'LIKE', item_id: '3', item_type: 'COMMENTS'}, + {action_type: 'FLAG', item_id: '3', item_type: 'COMMENTS'} ]} ].forEach(({liked, flagged, actions}) => { @@ -63,4 +72,82 @@ describe('graph.loaders.Metrics', () => { }); }); + + describe('#Assets', () => { + const query = ` + fragment metrics on Asset { + id + action_summaries { + type: __typename + actionCount + actionableItemCount + } + } + + query Metrics($from: Date!, $to: Date!) { + assetsByFlag: assetMetrics(from: $from, to: $to, sort: FLAG) { + ...metrics + } + assetsByLike: assetMetrics(from: $from, to: $to, sort: LIKE) { + ...metrics + } + } + `; + + describe('different comment states', () => { + + beforeEach(() => Promise.all([ + AssetModel.create([ + {id: 'a1', url: 'http://localhost:3030/article/1'}, + {id: 'a2', url: 'http://localhost:3030/article/2'} + ]), + CommentModel.create([ + {id: 'c1', asset_id: 'a1', body: 'a new comment!'}, + {id: 'c2', asset_id: 'a1', body: 'a new comment!'}, + {id: 'c3', asset_id: 'a1', body: 'a new comment!'} + ]) + ])); + + [ + {liked: 0, flagged: 0, actions: []}, + {liked: 1, flagged: 0, actions: [{action_type: 'LIKE', item_id: 'c1', item_type: 'COMMENTS'}]}, + {liked: 0, flagged: 1, actions: [{action_type: 'FLAG', item_id: 'c1', item_type: 'COMMENTS'}]}, + {liked: 1, flagged: 1, actions: [ + {action_type: 'FLAG', item_id: 'c1', item_type: 'COMMENTS'}, + {action_type: 'LIKE', item_id: 'c1', item_type: 'COMMENTS'} + ]}, + {liked: 1, flagged: 1, actions: [ + {action_type: 'LIKE', item_id: 'c1', item_type: 'COMMENTS'}, + {action_type: 'LIKE', item_id: 'c2', item_type: 'COMMENTS'}, + {action_type: 'LIKE', item_id: 'c3', item_type: 'COMMENTS'}, + {action_type: 'FLAG', item_id: 'c3', item_type: 'COMMENTS'} + ]} + ].forEach(({liked, flagged, actions}) => { + + describe(`with actions=${actions.length}`, () => { + + beforeEach(() => ActionModel.create(actions)); + + it(`returns the correct amount of metrics liked=${liked} flagged=${flagged}`, () => { + const context = new Context({user: new UserModel({roles: ['ADMIN']})}); + + return graphql(schema, query, {}, context, { + from: (new Date()).setMinutes((new Date()).getMinutes() - 5), + to: (new Date()).setMinutes((new Date()).getMinutes() + 5) + }) + .then(({data, errors}) => { + console.log(JSON.stringify(errors, null, 2)); + + expect(errors).to.be.undefined; + expect(data.assetsByLike).to.have.length(liked); + expect(data.assetsByFlag).to.have.length(flagged); + }); + }); + + }); + + }); + + }); + }); }); From 799727264e6a42ad7c82925269af8760bbfe9628 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Fri, 24 Feb 2017 09:57:57 -0700 Subject: [PATCH 019/132] Removed log --- test/graph/loaders/metrics.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/graph/loaders/metrics.js b/test/graph/loaders/metrics.js index 032a59536..29f2eeff1 100644 --- a/test/graph/loaders/metrics.js +++ b/test/graph/loaders/metrics.js @@ -136,8 +136,6 @@ describe('graph.loaders.Metrics', () => { to: (new Date()).setMinutes((new Date()).getMinutes() + 5) }) .then(({data, errors}) => { - console.log(JSON.stringify(errors, null, 2)); - expect(errors).to.be.undefined; expect(data.assetsByLike).to.have.length(liked); expect(data.assetsByFlag).to.have.length(flagged); From 38e093aac32e48db9606ec46047ae4a79c4503c1 Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Fri, 24 Feb 2017 11:26:23 -0700 Subject: [PATCH 020/132] remove most liked comments widget --- .../src/containers/Dashboard/Dashboard.js | 12 ++++--- .../src/containers/Dashboard/FlagWidget.js | 3 -- .../src/containers/Dashboard/LikeWidget.js | 3 -- .../src/graphql/queries/metrics.graphql | 34 +++++++++---------- client/coral-admin/src/translations.json | 4 +-- 5 files changed, 27 insertions(+), 29 deletions(-) diff --git a/client/coral-admin/src/containers/Dashboard/Dashboard.js b/client/coral-admin/src/containers/Dashboard/Dashboard.js index 51e46408d..ba840c627 100644 --- a/client/coral-admin/src/containers/Dashboard/Dashboard.js +++ b/client/coral-admin/src/containers/Dashboard/Dashboard.js @@ -5,7 +5,8 @@ import {connect} from 'react-redux'; import FlagWidget from './FlagWidget'; import LikeWidget from './LikeWidget'; import METRICS from 'coral-admin/src/graphql/queries/metrics.graphql'; -import MostLikedCommentsWidget from './MostLikedCommentsWidget'; + +// import MostLikedCommentsWidget from './MostLikedCommentsWidget'; import {showBanUserDialog, hideBanUserDialog} from 'coral-admin/src/actions/moderation'; import {banUser, setCommentStatus} from 'coral-admin/src/graphql/mutations'; import {Spinner} from 'coral-ui'; @@ -18,12 +19,14 @@ class Dashboard extends React.Component { return ; } - const {data: {assetsByLike, assetsByFlag, mostLikedComments}} = this.props; - const {moderation, settings} = this.props; + const {data: {assetsByLike, assetsByFlag/* , mostLikedComments*/}} = this.props; + + // const {moderation, settings} = this.props; return (
+ {/* + */}
); @@ -40,7 +44,7 @@ class Dashboard extends React.Component { } let then = new Date(); -then.setMinutes(then.getMinutes() - 205); +then.setMinutes(then.getMinutes() - 5); then = then.toISOString(); const now = new Date().toISOString(); diff --git a/client/coral-admin/src/containers/Dashboard/FlagWidget.js b/client/coral-admin/src/containers/Dashboard/FlagWidget.js index ada1f03f3..34c67086e 100644 --- a/client/coral-admin/src/containers/Dashboard/FlagWidget.js +++ b/client/coral-admin/src/containers/Dashboard/FlagWidget.js @@ -18,7 +18,6 @@ const FlagWidget = (props) => {
{/* empty on purpose */} - @@ -27,7 +26,6 @@ const FlagWidget = (props) => { assets.length ? assets.map((asset, index) => { const flagSummary = asset.action_summaries.find(s => s.type === 'FlagAssetActionSummary'); - const likeSummary = asset.action_summaries.find(s => s.type === 'LikeAssetActionSummary'); return ( @@ -36,7 +34,6 @@ const FlagWidget = (props) => {

{asset.author} - Published: {new Date(asset.created_at).toLocaleDateString()}

- ); diff --git a/client/coral-admin/src/containers/Dashboard/LikeWidget.js b/client/coral-admin/src/containers/Dashboard/LikeWidget.js index 82eecb049..dd92a94ca 100644 --- a/client/coral-admin/src/containers/Dashboard/LikeWidget.js +++ b/client/coral-admin/src/containers/Dashboard/LikeWidget.js @@ -18,7 +18,6 @@ const LikeWidget = (props) => { {/* empty on purpose */} - @@ -27,7 +26,6 @@ const LikeWidget = (props) => { { assets.length ? assets.map((asset, index) => { - const flagSummary = asset.action_summaries.find(s => s.type === 'FlagAssetActionSummary'); const likeSummary = asset.action_summaries.find(s => s.type === 'LikeAssetActionSummary'); return ( @@ -36,7 +34,6 @@ const LikeWidget = (props) => { {asset.title}

{asset.author} - Published: {new Date(asset.created_at).toLocaleDateString()}

- diff --git a/client/coral-admin/src/graphql/queries/metrics.graphql b/client/coral-admin/src/graphql/queries/metrics.graphql index 4e713c0b7..da5125a48 100644 --- a/client/coral-admin/src/graphql/queries/metrics.graphql +++ b/client/coral-admin/src/graphql/queries/metrics.graphql @@ -19,21 +19,21 @@ query Metrics ($from: Date!, $to: Date!) { assetsByLike: assetMetrics(from: $from, to: $to, sort: LIKE) { ...metrics } - mostLikedComments: commentMetrics(from: $from, to: $to, sort: LIKE) { - id - body - user { - status - username - } - asset { - id - title - } - created_at - action_summaries { - type: __typename - count - } - } +# mostLikedComments: commentMetrics(from: $from, to: $to, sort: LIKE) { +# id +# body +# user { +# status +# username +# } +# asset { +# id +# title +# } +# created_at +# action_summaries { +# type: __typename +# count +# } +# } } diff --git a/client/coral-admin/src/translations.json b/client/coral-admin/src/translations.json index f3deb6792..92e5d098a 100644 --- a/client/coral-admin/src/translations.json +++ b/client/coral-admin/src/translations.json @@ -112,7 +112,7 @@ "dashboard": { "no_flags": "There have been no flags in the last 5 minutes! Hooray!", "no_likes": "There have been no likes in the last 5 minutes. All quiet.", - "comment_count": "Comments" + "comment_count": "comments" }, "streams": { "empty_result": "No assets match this search. Maybe try widening your search?", @@ -222,7 +222,7 @@ "dashbord": { "no_flags": "¡Nadie ha marcado nada en los últimos 5 minutos! ¡Bravo!", "no_likes": "A nadie le ha gustado algún comentario en los últimos 5 minutos. Todo tranquilo.", - "comment_count": "Comentarios" + "comment_count": "comentarios" }, "streams": { "empty_result": "No se encuentro articulo con esta busqueda. Tal vez extender la busqueda?", From 1058bff8ad66a194cf1a8516f032c14ba9773c81 Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Fri, 24 Feb 2017 11:30:59 -0700 Subject: [PATCH 021/132] remove logs --- client/coral-admin/src/actions/install.js | 3 +- .../containers/Configure/CommentSettings.js | 1 - .../ModerationQueue/ModerationContainer.js | 1 - client/coral-framework/actions/auth.js | 3 +- client/coral-plugin-commentbox/CommentBox.js | 1 - .../RileysAwesomeCommentBox.js | 58 ---------- client/coral-plugin-stream/Stream.js | 100 ------------------ .../coral-settings/components/NotLoggedIn.js | 1 - 8 files changed, 2 insertions(+), 166 deletions(-) delete mode 100644 client/coral-plugin-stream/RileysAwesomeCommentBox.js delete mode 100644 client/coral-plugin-stream/Stream.js diff --git a/client/coral-admin/src/actions/install.js b/client/coral-admin/src/actions/install.js index c1d05d253..9fc308d2f 100644 --- a/client/coral-admin/src/actions/install.js +++ b/client/coral-admin/src/actions/install.js @@ -75,8 +75,7 @@ export const submitUser = () => (dispatch, getState) => { dispatch(installRequest()); coralApi('/setup', {method: 'POST', body: data}) .then(result => { - console.log(result); - dispatch(installSuccess()); + dispatch(installSuccess(result)); dispatch(nextStep()); }) .catch(error => { diff --git a/client/coral-admin/src/containers/Configure/CommentSettings.js b/client/coral-admin/src/containers/Configure/CommentSettings.js index 5a14cf565..90057c5fe 100644 --- a/client/coral-admin/src/containers/Configure/CommentSettings.js +++ b/client/coral-admin/src/containers/Configure/CommentSettings.js @@ -52,7 +52,6 @@ const updateClosedMessage = (updateSettings) => (event) => { }; const updateCustomCssUrl = (updateSettings) => (event) => { - console.log('updateCustomCssUrl', event.target.value); const customCssUrl = event.target.value; updateSettings({customCssUrl}); }; diff --git a/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js b/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js index 9c68d0728..a7d7110ae 100644 --- a/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js +++ b/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js @@ -54,7 +54,6 @@ class ModerationContainer extends Component { } if (data.error) { - console.log(data); return
Error
; } diff --git a/client/coral-framework/actions/auth.js b/client/coral-framework/actions/auth.js index 4a12245eb..418acc5bb 100644 --- a/client/coral-framework/actions/auth.js +++ b/client/coral-framework/actions/auth.js @@ -192,9 +192,8 @@ export const requestConfirmEmail = (email, redirectUri) => dispatch => { dispatch(verifyEmailSuccess()); }) .catch(err => { - console.log('failed to send email verification', err); // email might have already been verifyed - dispatch(verifyEmailFailure()); + dispatch(verifyEmailFailure(err)); }); }; diff --git a/client/coral-plugin-commentbox/CommentBox.js b/client/coral-plugin-commentbox/CommentBox.js index 3d895df07..004f294b2 100644 --- a/client/coral-plugin-commentbox/CommentBox.js +++ b/client/coral-plugin-commentbox/CommentBox.js @@ -110,7 +110,6 @@ class CommentBox extends Component { cStyle='darkGrey' className={`${name}-cancel-button`} onClick={() => { - console.log('cancel button in comment box'); cancelButtonClicked(''); }}> {lang.t('cancel')} diff --git a/client/coral-plugin-stream/RileysAwesomeCommentBox.js b/client/coral-plugin-stream/RileysAwesomeCommentBox.js deleted file mode 100644 index 73fa6407d..000000000 --- a/client/coral-plugin-stream/RileysAwesomeCommentBox.js +++ /dev/null @@ -1,58 +0,0 @@ -import React, {Component} from 'react'; -import {graphql} from 'react-apollo'; -import gql from 'graphql-tag'; - -export class RileysAwesomeCommentBox extends Component { - - postComment() { - console.log(this.props); - console.log('postComment', this.props.asset_id); - this.props.mutate({ - variables: { - asset_id: this.props.asset_id, - body: this.textarea.value, - parent_id: null - } - }).then(({data}) => { - console.log('it workt'); - console.log(data); - }); - } - - render() { - return
- - -
; - } -} - -const postComment = gql` - fragment commentView on Comment { - id - body - user { - name: username - } - actions { - type: action_type - count - current: current_user { - id - created_at - } - } - } - - mutation CreateComment ($asset_id: ID!, $parent_id: ID, $body: String!) { - createComment(asset_id:$asset_id, parent_id:$parent_id, body:$body) { - ...commentView - } - } -`; - -const RileysAwesomeCommentBoxWithData = graphql( - postComment -)(RileysAwesomeCommentBox); - -export default RileysAwesomeCommentBoxWithData; diff --git a/client/coral-plugin-stream/Stream.js b/client/coral-plugin-stream/Stream.js deleted file mode 100644 index 72e03d4ae..000000000 --- a/client/coral-plugin-stream/Stream.js +++ /dev/null @@ -1,100 +0,0 @@ -import React, {Component} from 'react'; -import {graphql} from 'react-apollo'; -import gql from 'graphql-tag'; -import {fetchSignIn} from 'coral-framework/actions/auth'; -import RileysAwesomeCommentBox from 'coral-plugin-stream/RileysAwesomeCommentBox'; - -const assetID = '6187a94b-0b6d-4a96-ac6b-62b529cd8410'; - -// MyComponent is a "presentational" or apollo-unaware component, -// It could be a simple React class: -class Stream extends Component { - - constructor(props) { - super(props); - } - - logMeIn() { - fetchSignIn({email: 'your@example.com', password: 'dfasidfaisdufoiausdfoiuaspdoifas'})(() => {}); - } - - render() { - const {data} = this.props; - return
- - { - data.loading - ? 'loading!' - :
- -

Asset ID: {data.asset.id}

-
    - { - data.asset.comments.map(comment => { - return
  • - {comment.body} [{comment.id}] -
      - { - comment.replies.map(reply => { - return
    • {reply.body}
    • ; - }) - } -
    -
  • ; - }) - } -
-
- } -
; - } -} - -// Initialize GraphQL queries or mutations with the gql tag -const StreamQuery = gql`fragment commentView on Comment { - id - body - user { - name: username - } - tags { - name - } - actions { - type: action_type - count - current: current_user { - id - created_at - } - } -} - -query AssetQuery($asset_id: ID!) { - asset(id: $asset_id) { - id - title - url - commentCount - comments { - ...commentView - replies { - ...commentView - } - } - } -}`; - -// We then can use `graphql` to pass the query results returned by MyQuery -// to MyComponent as a prop (and update them as the results change) -const StreamWithData = graphql( - StreamQuery, { - options: { - variables: { - asset_id: assetID - } - } - } -)(Stream); - -export default StreamWithData; diff --git a/client/coral-settings/components/NotLoggedIn.js b/client/coral-settings/components/NotLoggedIn.js index 2e2b64181..acd3ae7e6 100644 --- a/client/coral-settings/components/NotLoggedIn.js +++ b/client/coral-settings/components/NotLoggedIn.js @@ -10,7 +10,6 @@ export default ({showSignInDialog}) => ( From dcc16dc5989700b4d44f13360c13fb38305f93f0 Mon Sep 17 00:00:00 2001 From: David Jay Date: Fri, 24 Feb 2017 14:45:47 -0500 Subject: [PATCH 022/132] Removing extra semicolon. --- client/coral-sign-in/components/FakeComment.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/coral-sign-in/components/FakeComment.js b/client/coral-sign-in/components/FakeComment.js index 75d4e51f1..b5af6bf1c 100644 --- a/client/coral-sign-in/components/FakeComment.js +++ b/client/coral-sign-in/components/FakeComment.js @@ -35,7 +35,7 @@ class FakeComment extends React.Component { thumb_up - ; + {}} parentCommentId={'commentID'} From aefcb29877015b15dd4fd2ae4467c5f3c1183ffb Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Fri, 24 Feb 2017 12:58:06 -0700 Subject: [PATCH 023/132] remove comment count from results --- client/coral-admin/src/containers/Dashboard/FlagWidget.js | 2 -- client/coral-admin/src/containers/Dashboard/LikeWidget.js | 2 -- client/coral-admin/src/graphql/queries/metrics.graphql | 1 - 3 files changed, 5 deletions(-) diff --git a/client/coral-admin/src/containers/Dashboard/FlagWidget.js b/client/coral-admin/src/containers/Dashboard/FlagWidget.js index 34c67086e..537b89b8f 100644 --- a/client/coral-admin/src/containers/Dashboard/FlagWidget.js +++ b/client/coral-admin/src/containers/Dashboard/FlagWidget.js @@ -18,7 +18,6 @@ const FlagWidget = (props) => {
{/* empty on purpose */} - @@ -34,7 +33,6 @@ const FlagWidget = (props) => {

{asset.author} - Published: {new Date(asset.created_at).toLocaleDateString()}

- ); }) diff --git a/client/coral-admin/src/containers/Dashboard/LikeWidget.js b/client/coral-admin/src/containers/Dashboard/LikeWidget.js index dd92a94ca..ed6a0c0ae 100644 --- a/client/coral-admin/src/containers/Dashboard/LikeWidget.js +++ b/client/coral-admin/src/containers/Dashboard/LikeWidget.js @@ -19,7 +19,6 @@ const LikeWidget = (props) => { {/* empty on purpose */} - @@ -35,7 +34,6 @@ const LikeWidget = (props) => {

{asset.author} - Published: {new Date(asset.created_at).toLocaleDateString()}

- ); }) diff --git a/client/coral-admin/src/graphql/queries/metrics.graphql b/client/coral-admin/src/graphql/queries/metrics.graphql index da5125a48..68de89cab 100644 --- a/client/coral-admin/src/graphql/queries/metrics.graphql +++ b/client/coral-admin/src/graphql/queries/metrics.graphql @@ -2,7 +2,6 @@ fragment metrics on Asset { id title url - commentCount author created_at action_summaries { From 6a9d8c0436097599cf4a9ae8f0c1ca2e277cc9d8 Mon Sep 17 00:00:00 2001 From: David Jay Date: Fri, 24 Feb 2017 15:51:43 -0500 Subject: [PATCH 024/132] Removing refetch and prevent 0 from displaying on empty comment streams. --- client/coral-embed-stream/src/Comment.js | 3 --- client/coral-embed-stream/src/NewCount.js | 3 ++- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/client/coral-embed-stream/src/Comment.js b/client/coral-embed-stream/src/Comment.js index 8371cec45..f42b22e44 100644 --- a/client/coral-embed-stream/src/Comment.js +++ b/client/coral-embed-stream/src/Comment.js @@ -38,7 +38,6 @@ class Comment extends React.Component { // id of currently opened ReplyBox. tracked in Stream.js activeReplyBox: PropTypes.string.isRequired, setActiveReplyBox: PropTypes.func.isRequired, - refetch: PropTypes.func.isRequired, showSignInDialog: PropTypes.func.isRequired, postFlag: PropTypes.func.isRequired, postLike: PropTypes.func.isRequired, @@ -85,7 +84,6 @@ class Comment extends React.Component { asset, depth, postItem, - refetch, addNotification, showSignInDialog, postLike, @@ -155,7 +153,6 @@ class Comment extends React.Component { comment.replies && comment.replies.map(reply => { return { return
{ - props.countCache && newComments > 0 && + props.countCache && newComments > 0 ? + : null }
; }; From 66a890458c7548883303bd5daf974e126163798d Mon Sep 17 00:00:00 2001 From: David Jay Date: Fri, 24 Feb 2017 17:42:29 -0500 Subject: [PATCH 025/132] Adding sort to moderation queue. --- .../ModerationQueue/ModerationContainer.js | 3 +- .../components/ModerationMenu.js | 82 ++++++++++++------- .../ModerationQueue/components/styles.css | 44 ++++++++++ .../coral-admin/src/graphql/queries/index.js | 20 ++++- .../src/graphql/queries/modQueueQuery.graphql | 11 ++- 5 files changed, 123 insertions(+), 37 deletions(-) diff --git a/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js b/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js index b1a44533e..d3e2f9194 100644 --- a/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js +++ b/client/coral-admin/src/containers/ModerationQueue/ModerationContainer.js @@ -43,7 +43,7 @@ class ModerationContainer extends Component { } render () { - const {data, moderation, settings, assets, ...props} = this.props; + const {data, moderation, settings, assets, modQueueResort, ...props} = this.props; const providedAssetId = this.props.params.id; const activeTab = this.props.route.path === ':id' ? 'premod' : this.props.route.path; @@ -73,6 +73,7 @@ class ModerationContainer extends Component { premodCount={data.premodCount} rejectedCount={data.rejectedCount} flaggedCount={data.flaggedCount} + modQueueResort={modQueueResort} /> { - const premodPath = asset ? `/admin/moderate/premod/${asset.id}` : '/admin/moderate/premod'; - const rejectPath = asset ? `/admin/moderate/rejected/${asset.id}` : '/admin/moderate/rejected'; - const flagPath = asset ? `/admin/moderate/flagged/${asset.id}` : '/admin/moderate/flagged'; - return ( -
-
-
- - {lang.t('modqueue.premod')} - - - {lang.t('modqueue.rejected')} - - - {lang.t('modqueue.flagged')} - +class ModerationMenu extends Component { + state = { + sort: '', + } + + static propTypes = { + premodCount: PropTypes.number.isRequired, + rejectedCount: PropTypes.number.isRequired, + flaggedCount: PropTypes.number.isRequired, + asset: PropTypes.shape({ + id: PropTypes.string + }) + } + + selectSort = (sort) => { + this.setState({sort}); + this.props.modQueueResort(sort); + } + + render() { + const {asset, premodCount, rejectedCount, flaggedCount} = this.props; + const premodPath = asset ? `/admin/moderate/premod/${asset.id}` : '/admin/moderate/premod'; + const rejectPath = asset ? `/admin/moderate/rejected/${asset.id}` : '/admin/moderate/rejected'; + const flagPath = asset ? `/admin/moderate/flagged/${asset.id}` : '/admin/moderate/flagged'; + return ( +
+
+
+
+ + {lang.t('modqueue.premod')} + + + {lang.t('modqueue.rejected')} + + + {lang.t('modqueue.flagged')} + +
+ this.selectSort(sort)}> + + +
-
- ); -}; - -ModerationMenu.propTypes = { - premodCount: PropTypes.number.isRequired, - rejectedCount: PropTypes.number.isRequired, - flaggedCount: PropTypes.number.isRequired, - asset: PropTypes.shape({ - id: PropTypes.string - }) -}; + ); + } +} export default ModerationMenu; diff --git a/client/coral-admin/src/containers/ModerationQueue/components/styles.css b/client/coral-admin/src/containers/ModerationQueue/components/styles.css index e2fd31911..27d5c2533 100644 --- a/client/coral-admin/src/containers/ModerationQueue/components/styles.css +++ b/client/coral-admin/src/containers/ModerationQueue/components/styles.css @@ -8,6 +8,12 @@ .tabBar { background-color: rgba(44, 44, 44, 0.89); z-index: 5; + display: flex; + justify-content: space-between; +} + +.tabBarPadding { + width: 150px; } .tab { @@ -334,3 +340,41 @@ span { font-weight: 500; } } + +.selectField { + position: relative; + width: 140px; + height: 36px; + top: 5px; + margin-right: 10px; + background: #FFF; + padding: 10px 15px; + box-sizing: border-box; + border-radius: 2px; + box-shadow: 0 2px 2px 0 rgba(0,0,0,.14), 0 3px 1px -2px rgba(0,0,0,.2), 0 1px 5px 0 rgba(0,0,0,.12); + + > div { + padding: 0; + } + + i { + position: absolute; + top: 7px; + right: 7px; + } + + input { + padding: 0; + font-size: 13px; + letter-spacing: 0.7px; + font-weight: 400; + } + + label { + top: -4px; + } + + &:hover { + cursor: pointer; + } +} diff --git a/client/coral-admin/src/graphql/queries/index.js b/client/coral-admin/src/graphql/queries/index.js index 3325249e1..809769a13 100644 --- a/client/coral-admin/src/graphql/queries/index.js +++ b/client/coral-admin/src/graphql/queries/index.js @@ -23,8 +23,24 @@ export const modQueueQuery = graphql(MOD_QUEUE_QUERY, { options: ({params: {id = null}}) => { return { variables: { - asset_id: id + asset_id: id, + sort: 'REVERSE_CHRONOLOGICAL' } }; - } + }, + props: ({ownProps: {params: {id = null}}, data}) => ({ + data, + modQueueResort: modQueueResort(id, data.fetchMore) + }) }); + +export const modQueueResort = (id, fetchMore) => (sort) => { + return fetchMore({ + query: MOD_QUEUE_QUERY, + variables: { + asset_id: id, + sort + }, + updateQuery: (oldData, {fetchMoreResult:{data}}) => data + }); +}; diff --git a/client/coral-admin/src/graphql/queries/modQueueQuery.graphql b/client/coral-admin/src/graphql/queries/modQueueQuery.graphql index 86cd26bbd..b4f2a20a0 100644 --- a/client/coral-admin/src/graphql/queries/modQueueQuery.graphql +++ b/client/coral-admin/src/graphql/queries/modQueueQuery.graphql @@ -1,16 +1,18 @@ #import "../fragments/commentView.graphql" -query ModQueue ($asset_id: ID) { +query ModQueue ($asset_id: ID, $sort: SORT_ORDER) { premod: comments(query: { statuses: [PREMOD], - asset_id: $asset_id + asset_id: $asset_id, + sort: $sort }) { ...commentView } flagged: comments(query: { action_type: FLAG, asset_id: $asset_id, - statuses: [NONE, PREMOD] + statuses: [NONE, PREMOD], + sort: $sort }) { ...commentView action_summaries { @@ -22,7 +24,8 @@ query ModQueue ($asset_id: ID) { } rejected: comments(query: { statuses: [REJECTED], - asset_id: $asset_id + asset_id: $asset_id, + sort: $sort }) { ...commentView } From 37b08fd4e400ea26947a340654d46605a5b45300 Mon Sep 17 00:00:00 2001 From: David Jay Date: Mon, 27 Feb 2017 12:28:13 -0500 Subject: [PATCH 026/132] Displaying oldest first by default. --- .../src/containers/ModerationQueue/components/ModerationMenu.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/coral-admin/src/containers/ModerationQueue/components/ModerationMenu.js b/client/coral-admin/src/containers/ModerationQueue/components/ModerationMenu.js index a0f6b970b..d2520f784 100644 --- a/client/coral-admin/src/containers/ModerationQueue/components/ModerationMenu.js +++ b/client/coral-admin/src/containers/ModerationQueue/components/ModerationMenu.js @@ -10,7 +10,7 @@ const lang = new I18n(translations); class ModerationMenu extends Component { state = { - sort: '', + sort: 'REVERSE_CHRONOLOGICAL', } static propTypes = { From b1ec512721ba53c1fda474bd1eb34c0be6dba8cf Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Mon, 27 Feb 2017 14:42:57 -0300 Subject: [PATCH 027/132] Adding whitelist step, sending whitelist --- .../src/containers/Install/InstallContainer.js | 2 ++ .../Install/components/Steps/WhitelistStep.js | 15 +++++++++++++++ client/coral-admin/src/reducers/install.js | 11 +++++++++-- client/coral-ui/components/WizardNav.css | 1 + 4 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 client/coral-admin/src/containers/Install/components/Steps/WhitelistStep.js diff --git a/client/coral-admin/src/containers/Install/InstallContainer.js b/client/coral-admin/src/containers/Install/InstallContainer.js index 7a8634180..b015140ed 100644 --- a/client/coral-admin/src/containers/Install/InstallContainer.js +++ b/client/coral-admin/src/containers/Install/InstallContainer.js @@ -18,6 +18,7 @@ import { import InitialStep from './components/Steps/InitialStep'; import AddOrganizationName from './components/Steps/AddOrganizationName'; import CreateYourAccount from './components/Steps/CreateYourAccount'; +import WhitelistStep from './components/Steps/WhitelistStep'; import FinalStep from './components/Steps/FinalStep'; class InstallContainer extends Component { @@ -43,6 +44,7 @@ class InstallContainer extends Component { +
diff --git a/client/coral-admin/src/containers/Install/components/Steps/WhitelistStep.js b/client/coral-admin/src/containers/Install/components/Steps/WhitelistStep.js new file mode 100644 index 000000000..e246b457e --- /dev/null +++ b/client/coral-admin/src/containers/Install/components/Steps/WhitelistStep.js @@ -0,0 +1,15 @@ +import React from 'react'; +import styles from './style.css'; +import {Button} from 'coral-ui'; + +const WhitelistStep = props => { + const {nextStep} = props; + return ( +
+

Domain Whitelist

+ +
+ ); +}; + +export default WhitelistStep; diff --git a/client/coral-admin/src/reducers/install.js b/client/coral-admin/src/reducers/install.js index 596fd16cd..429d5cce0 100644 --- a/client/coral-admin/src/reducers/install.js +++ b/client/coral-admin/src/reducers/install.js @@ -1,4 +1,4 @@ -import {Map} from 'immutable'; +import {Map, List} from 'immutable'; import * as actions from '../constants/install'; @@ -6,7 +6,10 @@ const initialState = Map({ isLoading: false, data: Map({ settings: Map({ - organizationName: '' + organizationName: '', + domains: Map({ + whitelist: List() + }) }), user: Map({ username: '', @@ -33,6 +36,10 @@ const initialState = Map({ { text: '2. Create your account', step: 2 + }, + { + text: '3. Domain Whitelist', + step: 3 }], installRequest: null, installRequestError: null, diff --git a/client/coral-ui/components/WizardNav.css b/client/coral-ui/components/WizardNav.css index 001ee8603..1f0b78d86 100644 --- a/client/coral-ui/components/WizardNav.css +++ b/client/coral-ui/components/WizardNav.css @@ -13,6 +13,7 @@ position: relative; padding-left: 40px; border-radius: 1px; + min-height: 24px; &:hover { cursor: pointer; From 9305853502ca738bd70211a1d2ee0c15e9862efd Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Mon, 27 Feb 2017 15:50:07 -0300 Subject: [PATCH 028/132] Renamed to PermittedDomains --- client/coral-admin/src/actions/install.js | 34 ++++++++++++------- .../containers/Install/InstallContainer.js | 7 ++-- .../components/Steps/PermittedDomainsStep.js | 31 +++++++++++++++++ .../Install/components/Steps/WhitelistStep.js | 15 -------- .../src/containers/Install/translations.json | 16 +++++++++ client/coral-admin/src/reducers/install.js | 5 +-- 6 files changed, 72 insertions(+), 36 deletions(-) create mode 100644 client/coral-admin/src/containers/Install/components/Steps/PermittedDomainsStep.js delete mode 100644 client/coral-admin/src/containers/Install/components/Steps/WhitelistStep.js create mode 100644 client/coral-admin/src/containers/Install/translations.json diff --git a/client/coral-admin/src/actions/install.js b/client/coral-admin/src/actions/install.js index c1d05d253..73e7aaa82 100644 --- a/client/coral-admin/src/actions/install.js +++ b/client/coral-admin/src/actions/install.js @@ -71,21 +71,31 @@ export const submitSettings = () => (dispatch, getState) => { export const submitUser = () => (dispatch, getState) => { const userFormData = getState().install.toJS().data.user; validation(userFormData, dispatch, function() { - const data = getState().install.toJS().data; - dispatch(installRequest()); - coralApi('/setup', {method: 'POST', body: data}) - .then(result => { - console.log(result); - dispatch(installSuccess()); - dispatch(nextStep()); - }) - .catch(error => { - console.error(error); - dispatch(installFailure(`${error.translation_key}`)); - }); + dispatch(nextStep()); }); }; +export const submitWhitelistDomains = () => (dispatch) => { + submitForm().then(() => { + dispatch(installSuccess()); + }); +}; + +const submitForm = () => (dispatch, getState) => { + const data = getState().install.toJS().data; + dispatch(installRequest()); + return coralApi('/setup', { method: 'POST', body: data }) + .then(result => { + console.log(result); + dispatch(installSuccess()); + dispatch(nextStep()); + }) + .catch(error => { + console.error(error); + dispatch(installFailure(`${error.translation_key}`)); + }); +}; + export const updateSettingsFormData = (name, value) => ({type: actions.UPDATE_FORMDATA_SETTINGS, name, value}); export const updateUserFormData = (name, value) => ({type: actions.UPDATE_FORMDATA_USER, name, value}); diff --git a/client/coral-admin/src/containers/Install/InstallContainer.js b/client/coral-admin/src/containers/Install/InstallContainer.js index b015140ed..fe41e12e4 100644 --- a/client/coral-admin/src/containers/Install/InstallContainer.js +++ b/client/coral-admin/src/containers/Install/InstallContainer.js @@ -18,7 +18,7 @@ import { import InitialStep from './components/Steps/InitialStep'; import AddOrganizationName from './components/Steps/AddOrganizationName'; import CreateYourAccount from './components/Steps/CreateYourAccount'; -import WhitelistStep from './components/Steps/WhitelistStep'; +import PermittedDomainsStep from './components/Steps/PermittedDomainsStep'; import FinalStep from './components/Steps/FinalStep'; class InstallContainer extends Component { @@ -41,10 +41,7 @@ class InstallContainer extends Component {

Welcome to the Coral Project

{ install.step !== 0 ? : null } - - - - +
diff --git a/client/coral-admin/src/containers/Install/components/Steps/PermittedDomainsStep.js b/client/coral-admin/src/containers/Install/components/Steps/PermittedDomainsStep.js new file mode 100644 index 000000000..c5fae148e --- /dev/null +++ b/client/coral-admin/src/containers/Install/components/Steps/PermittedDomainsStep.js @@ -0,0 +1,31 @@ +import React from 'react'; +import styles from './style.css'; +import {Button, Card} from 'coral-ui'; +import TagsInput from 'react-tagsinput'; + +const lang = new I18n(translations); +import translations from '../../translations.json'; +import I18n from 'coral-framework/modules/i18n/i18n'; + +const PermittedDomainsStep = props => { + const {nextStep, onChangeDomainlist} = props; + const domains = []; + return ( +
+

{lang.t('PERMITTED_DOMAINS.TITLE')}

+ +

{lang.t('PERMITTED_DOMAINS.DESCRIPTION')}

+ data.split(',').map(d => d.trim())} + onChange={tags => onChangeDomainlist(tags)} + /> +
+ +
+ ); +}; + +export default PermittedDomainsStep; diff --git a/client/coral-admin/src/containers/Install/components/Steps/WhitelistStep.js b/client/coral-admin/src/containers/Install/components/Steps/WhitelistStep.js deleted file mode 100644 index e246b457e..000000000 --- a/client/coral-admin/src/containers/Install/components/Steps/WhitelistStep.js +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react'; -import styles from './style.css'; -import {Button} from 'coral-ui'; - -const WhitelistStep = props => { - const {nextStep} = props; - return ( -
-

Domain Whitelist

- -
- ); -}; - -export default WhitelistStep; diff --git a/client/coral-admin/src/containers/Install/translations.json b/client/coral-admin/src/containers/Install/translations.json new file mode 100644 index 000000000..494a020f4 --- /dev/null +++ b/client/coral-admin/src/containers/Install/translations.json @@ -0,0 +1,16 @@ +{ + "en": { + "PERMITTED_DOMAINS": { + "TITLE": "Permitted domains", + "DESCRIPTION": "Add permitted domains", + "SUBMIT": "Finish install" + } + }, + "es": { + "PERMITTED_DOMAINS": { + "TITLE": "Dominios Permitidos", + "DESCRIPTION": "Agrega dominios permitidos", + "SUBMIT": "Finalizar instalación" + } + } +} diff --git a/client/coral-admin/src/reducers/install.js b/client/coral-admin/src/reducers/install.js index 429d5cce0..8d3ea0f76 100644 --- a/client/coral-admin/src/reducers/install.js +++ b/client/coral-admin/src/reducers/install.js @@ -6,10 +6,7 @@ const initialState = Map({ isLoading: false, data: Map({ settings: Map({ - organizationName: '', - domains: Map({ - whitelist: List() - }) + organizationName: '' }), user: Map({ username: '', From ab16e5bfe7a396377e4784873549384f9bffe125 Mon Sep 17 00:00:00 2001 From: David Jay Date: Mon, 27 Feb 2017 14:26:20 -0500 Subject: [PATCH 029/132] Retrieving comment y id from backend --- graph/loaders/comments.js | 17 +++++++++++++++++ graph/resolvers/comment.js | 7 +++++++ graph/resolvers/root_query.js | 4 +++- graph/typeDefs.graphql | 6 ++++++ 4 files changed, 33 insertions(+), 1 deletion(-) diff --git a/graph/loaders/comments.js b/graph/loaders/comments.js index ad78a1e92..b5f493831 100644 --- a/graph/loaders/comments.js +++ b/graph/loaders/comments.js @@ -270,6 +270,22 @@ const genRecentComments = (_, ids) => { .then(util.arrayJoinBy(ids, 'asset_id')); }; +/** + * genComments returns the comments by the id's specified that are considered + * public comments (i.e., accepted or not rejected). + */ +const genComments = (context, ids) => { + return CommentModel.find({ + id: { + $in: ids + }, + status: { + $in: ['NONE', 'ACCEPTED'] + } + }) + .then(util.singleJoinBy(ids, 'id')); +}; + /** * Creates a set of loaders based on a GraphQL context. * @param {Object} context the context of the GraphQL request @@ -277,6 +293,7 @@ const genRecentComments = (_, ids) => { */ module.exports = (context) => ({ Comments: { + get: new DataLoader((ids) => genComments(context, ids)), getByQuery: (query) => getCommentsByQuery(context, query), getCountByQuery: (query) => getCommentCountByQuery(context, query), countByAssetID: new util.SharedCacheDataLoader('Comments.countByAssetID', 3600, (ids) => getCountsByAssetID(context, ids)), diff --git a/graph/resolvers/comment.js b/graph/resolvers/comment.js index ef77ff6b5..43577dca0 100644 --- a/graph/resolvers/comment.js +++ b/graph/resolvers/comment.js @@ -1,4 +1,11 @@ const Comment = { + parent({parent_id}, _, {loaders: {Comments}}) { + if (parent_id == null) { + return null; + } + + return Comments.get.load(parent_id); + }, user({author_id}, _, {loaders: {Users}}) { return Users.getByID.load(author_id); }, diff --git a/graph/resolvers/root_query.js b/graph/resolvers/root_query.js index ced4e65cf..6622fd17f 100644 --- a/graph/resolvers/root_query.js +++ b/graph/resolvers/root_query.js @@ -38,7 +38,9 @@ const RootQuery = { return Comments.getByQuery(query); }, - + comment(_, {id}, {loaders: {Comments}}) { + return Comments.get.load(id); + }, commentCount(_, {query: {action_type, statuses, asset_id, parent_id}}, {user, loaders: {Actions, Comments}}) { if (user == null || !user.hasRoles('ADMIN')) { return null; diff --git a/graph/typeDefs.graphql b/graph/typeDefs.graphql index fbdeb4279..b9ab770ac 100644 --- a/graph/typeDefs.graphql +++ b/graph/typeDefs.graphql @@ -149,6 +149,9 @@ input CommentCountQuery { # Comment is the base representation of user interaction in Talk. type Comment { + # The parent of the comment (if there is one). + parent: Comment + # The ID of the comment. id: ID! @@ -477,6 +480,9 @@ type RootQuery { # Site wide settings and defaults. settings: Settings + # Finds a specific comment based on it's id. + comment(id: ID!): Comment + # All assets. Requires the `ADMIN` role. assets: [Asset] From 013625df274c2e8b40743bd798592bff9299bc01 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Mon, 27 Feb 2017 16:39:52 -0300 Subject: [PATCH 030/132] no validation for domains --- client/coral-admin/src/actions/install.js | 38 ++++++++--------- client/coral-admin/src/constants/install.js | 1 + .../src/containers/Configure/Domainlist.js | 42 ++++++++++--------- .../containers/Install/InstallContainer.js | 23 ++++++---- .../components/Steps/PermittedDomainsStep.js | 10 ++--- .../Install/components/Steps/style.css | 6 +++ client/coral-admin/src/reducers/install.js | 8 +++- 7 files changed, 76 insertions(+), 52 deletions(-) diff --git a/client/coral-admin/src/actions/install.js b/client/coral-admin/src/actions/install.js index 73e7aaa82..970c15141 100644 --- a/client/coral-admin/src/actions/install.js +++ b/client/coral-admin/src/actions/install.js @@ -20,13 +20,17 @@ const validation = (formData, dispatch, next) => { return dispatch(hasError()); } + const validKeys = Object.keys(formData) + .filter(name => name !== 'domains'); + // Required Validation - const empty = Object.keys(formData).filter(name => { + const empty = validKeys + .filter(name => { const cond = !formData[name].length; if (cond) { - // Adding Error + // Adding Error dispatch(addError(name, 'This field is required.')); } else { dispatch(addError(name, '')); @@ -40,18 +44,19 @@ const validation = (formData, dispatch, next) => { } // RegExp Validation - const validation = Object.keys(formData).filter(name => { - const cond = !validate[name](formData[name]); - if (cond) { + const validation = validKeys + .filter(name => { + const cond = !validate[name](formData[name]); + if (cond) { // Adding Error - dispatch(addError(name, errorMsj[name])); - } else { - dispatch(addError(name, '')); - } + dispatch(addError(name, errorMsj[name])); + } else { + dispatch(addError(name, '')); + } - return cond; - }); + return cond; + }); if (validation.length) { return dispatch(hasError()); @@ -75,16 +80,10 @@ export const submitUser = () => (dispatch, getState) => { }); }; -export const submitWhitelistDomains = () => (dispatch) => { - submitForm().then(() => { - dispatch(installSuccess()); - }); -}; - -const submitForm = () => (dispatch, getState) => { +export const finishInstall = () => (dispatch, getState) => { const data = getState().install.toJS().data; dispatch(installRequest()); - return coralApi('/setup', { method: 'POST', body: data }) + return coralApi('/setup', {method: 'POST', body: data}) .then(result => { console.log(result); dispatch(installSuccess()); @@ -98,6 +97,7 @@ const submitForm = () => (dispatch, getState) => { export const updateSettingsFormData = (name, value) => ({type: actions.UPDATE_FORMDATA_SETTINGS, name, value}); export const updateUserFormData = (name, value) => ({type: actions.UPDATE_FORMDATA_USER, name, value}); +export const updatePermittedDomains = (value) => ({type: actions.UPDATE_PERMITTED_DOMAINS_SETTINGS, value}); const checkInstallRequest = () => ({type: actions.CHECK_INSTALL_REQUEST}); const checkInstallSuccess = installed => ({type: actions.CHECK_INSTALL_SUCCESS, installed}); diff --git a/client/coral-admin/src/constants/install.js b/client/coral-admin/src/constants/install.js index b3fd7e0d0..743d68593 100644 --- a/client/coral-admin/src/constants/install.js +++ b/client/coral-admin/src/constants/install.js @@ -10,6 +10,7 @@ export const INSTALL_SUCCESS = 'INSTALL_SUCCESS'; export const INSTALL_FAILURE = 'INSTALL_FAILURE'; export const UPDATE_FORMDATA_USER = 'UPDATE_FORMDATA_USER'; export const UPDATE_FORMDATA_SETTINGS = 'UPDATE_FORMDATA_SETTINGS'; +export const UPDATE_PERMITTED_DOMAINS_SETTINGS = 'UPDATE_PERMITTED_DOMAINS_SETTINGS'; export const CHECK_INSTALL_REQUEST = 'CHECK_INSTALL_REQUEST'; export const CHECK_INSTALL_SUCCESS = 'CHECK_INSTALL_SUCCESS'; diff --git a/client/coral-admin/src/containers/Configure/Domainlist.js b/client/coral-admin/src/containers/Configure/Domainlist.js index f845dfeaa..6918c0471 100644 --- a/client/coral-admin/src/containers/Configure/Domainlist.js +++ b/client/coral-admin/src/containers/Configure/Domainlist.js @@ -1,26 +1,28 @@ import React from 'react'; +import {Card} from 'coral-ui'; +import styles from './Configure.css'; +import TagsInput from 'react-tagsinput'; + import I18n from 'coral-framework/modules/i18n/i18n'; import translations from '../../translations.json'; -import TagsInput from 'react-tagsinput'; -import styles from './Configure.css'; -import {Card} from 'coral-ui'; +const lang = new I18n(translations); -const Domainlist = ({domains, onChangeDomainlist}) => ( -
-

{lang.t('configure.domain-list-title')}

- -

{lang.t('configure.domain-list-text')}

- data.split(',').map(d => d.trim())} - onChange={tags => onChangeDomainlist('whitelist', tags)} - /> -
-
-); +const Domainlist = ({domains, onChangeDomainlist}) => { + return ( +
+

{lang.t('configure.domain-list-title')}

+ +

{lang.t('configure.domain-list-text')}

+ data.split(',').map(d => d.trim())} + onChange={tags => onChangeDomainlist('whitelist', tags)} + /> +
+
+ ); +}; export default Domainlist; - -const lang = new I18n(translations); diff --git a/client/coral-admin/src/containers/Install/InstallContainer.js b/client/coral-admin/src/containers/Install/InstallContainer.js index fe41e12e4..b70d3b8c9 100644 --- a/client/coral-admin/src/containers/Install/InstallContainer.js +++ b/client/coral-admin/src/containers/Install/InstallContainer.js @@ -5,14 +5,16 @@ import {Wizard, WizardNav} from 'coral-ui'; import {Layout} from '../../components/ui/Layout'; import { - nextStep, - previousStep, goToStep, + nextStep, + submitUser, + checkInstall, + previousStep, + finishInstall, + submitSettings, updateUserFormData, updateSettingsFormData, - submitSettings, - submitUser, - checkInstall + updatePermittedDomains } from '../../actions/install'; import InitialStep from './components/Steps/InitialStep'; @@ -41,6 +43,9 @@ class InstallContainer extends Component {

Welcome to the Coral Project

{ install.step !== 0 ? : null } + + + @@ -64,10 +69,14 @@ const mapStateToProps = state => ({ }); const mapDispatchToProps = dispatch => ({ - checkInstall: next => dispatch(checkInstall(next)), nextStep: () => dispatch(nextStep()), - previousStep: () => dispatch(previousStep()), goToStep: step => dispatch(goToStep(step)), + previousStep: () => dispatch(previousStep()), + finishInstall: () => dispatch(finishInstall()), + checkInstall: next => dispatch(checkInstall(next)), + handleDomainsChange: value => { + dispatch(updatePermittedDomains(value)); + }, handleSettingsChange: e => { const {name, value} = e.currentTarget; dispatch(updateSettingsFormData(name, value)); diff --git a/client/coral-admin/src/containers/Install/components/Steps/PermittedDomainsStep.js b/client/coral-admin/src/containers/Install/components/Steps/PermittedDomainsStep.js index c5fae148e..f2c1546f6 100644 --- a/client/coral-admin/src/containers/Install/components/Steps/PermittedDomainsStep.js +++ b/client/coral-admin/src/containers/Install/components/Steps/PermittedDomainsStep.js @@ -8,22 +8,22 @@ import translations from '../../translations.json'; import I18n from 'coral-framework/modules/i18n/i18n'; const PermittedDomainsStep = props => { - const {nextStep, onChangeDomainlist} = props; - const domains = []; + const {finishInstall, install, handleDomainsChange} = props; + const domains = install.data.settings.domains.whitelist; return (

{lang.t('PERMITTED_DOMAINS.TITLE')}

- +

{lang.t('PERMITTED_DOMAINS.DESCRIPTION')}

data.split(',').map(d => d.trim())} - onChange={tags => onChangeDomainlist(tags)} + onChange={tags => handleDomainsChange(tags)} />
- +
); }; diff --git a/client/coral-admin/src/containers/Install/components/Steps/style.css b/client/coral-admin/src/containers/Install/components/Steps/style.css index a5867e960..dea752298 100644 --- a/client/coral-admin/src/containers/Install/components/Steps/style.css +++ b/client/coral-admin/src/containers/Install/components/Steps/style.css @@ -59,6 +59,12 @@ } } } + + .card { + max-width: 500px; + margin: 20px auto; + text-align: left; + } } .finalStep { diff --git a/client/coral-admin/src/reducers/install.js b/client/coral-admin/src/reducers/install.js index 8d3ea0f76..1f0f079ff 100644 --- a/client/coral-admin/src/reducers/install.js +++ b/client/coral-admin/src/reducers/install.js @@ -6,7 +6,10 @@ const initialState = Map({ isLoading: false, data: Map({ settings: Map({ - organizationName: '' + organizationName: '', + domains: Map({ + whitelist: List() + }) }), user: Map({ username: '', @@ -54,6 +57,9 @@ export default function install (state = initialState, action) { case actions.GO_TO_STEP: return state .set('step', action.step); + case actions.UPDATE_PERMITTED_DOMAINS_SETTINGS: + return state + .setIn(['data', 'settings', 'domains', 'whitelist'], action.value); case actions.UPDATE_FORMDATA_SETTINGS: return state .setIn(['data', 'settings', action.name], action.value); From 1e52c579cc318703494d5170c6cb03c8d1b467b3 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Mon, 27 Feb 2017 16:50:04 -0300 Subject: [PATCH 031/132] =?UTF-8?q?=C3=8Dnitial=20translations?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Install/components/Steps/InitialStep.js | 12 ++++++------ .../src/containers/Install/translations.json | 8 ++++++++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/client/coral-admin/src/containers/Install/components/Steps/InitialStep.js b/client/coral-admin/src/containers/Install/components/Steps/InitialStep.js index 9f9770fe9..1838e3178 100644 --- a/client/coral-admin/src/containers/Install/components/Steps/InitialStep.js +++ b/client/coral-admin/src/containers/Install/components/Steps/InitialStep.js @@ -2,16 +2,16 @@ import React from 'react'; import styles from './style.css'; import {Button} from 'coral-ui'; +const lang = new I18n(translations); +import translations from '../../translations.json'; +import I18n from 'coral-framework/modules/i18n/i18n'; + const InitialStep = props => { const {nextStep} = props; return (
-

- The remainder of the Talk installation will take about ten minutes. - Once you complete the following two steps, you will have a free - installation and provision of Mongo and Redis. -

- +

{lang.t('INITIAL.DESCRIPTION')}

+
); }; diff --git a/client/coral-admin/src/containers/Install/translations.json b/client/coral-admin/src/containers/Install/translations.json index 494a020f4..5b3c5f036 100644 --- a/client/coral-admin/src/containers/Install/translations.json +++ b/client/coral-admin/src/containers/Install/translations.json @@ -1,5 +1,9 @@ { "en": { + "INITIAL" : { + "DESCRIPTION": "The remainder of the Talk installation will take about ten minutes. Once you complete the following two steps, you will have a free installation and provision of Mongo and Redis.", + "SUBMIT": "Get Started" + }, "PERMITTED_DOMAINS": { "TITLE": "Permitted domains", "DESCRIPTION": "Add permitted domains", @@ -7,6 +11,10 @@ } }, "es": { + "INITIAL" : { + "DESCRIPTION": "La instalación de Talk tomará aproximadamente diez minutos. Tan pronto como termines los tres pasos, tendrás una gratis instalación y provision de Mongo y Redis", + "SUBMIT": "Empezá!" + }, "PERMITTED_DOMAINS": { "TITLE": "Dominios Permitidos", "DESCRIPTION": "Agrega dominios permitidos", From 7341fdff4eb9b3b5bf1cfd36f7b628555cc18dbf Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Mon, 27 Feb 2017 16:54:03 -0300 Subject: [PATCH 032/132] add Organization translations --- .../Install/components/Steps/AddOrganizationName.js | 13 +++++++------ .../src/containers/Install/translations.json | 10 ++++++++++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/client/coral-admin/src/containers/Install/components/Steps/AddOrganizationName.js b/client/coral-admin/src/containers/Install/components/Steps/AddOrganizationName.js index ae23d0048..127c4afa1 100644 --- a/client/coral-admin/src/containers/Install/components/Steps/AddOrganizationName.js +++ b/client/coral-admin/src/containers/Install/components/Steps/AddOrganizationName.js @@ -2,25 +2,26 @@ import React from 'react'; import styles from './style.css'; import {TextField, Button} from 'coral-ui'; +const lang = new I18n(translations); +import translations from '../../translations.json'; +import I18n from 'coral-framework/modules/i18n/i18n'; + const AddOrganizationName = props => { const {handleSettingsChange, handleSettingsSubmit, install} = props; return (
-

- Please tell us the name of your organization. This will appear in emails when - inviting new team members -

+

{lang.t('ADD_ORGANIZATION.DESCRIPTION')}

- +
diff --git a/client/coral-admin/src/containers/Install/translations.json b/client/coral-admin/src/containers/Install/translations.json index 5b3c5f036..aee01c3cd 100644 --- a/client/coral-admin/src/containers/Install/translations.json +++ b/client/coral-admin/src/containers/Install/translations.json @@ -4,6 +4,11 @@ "DESCRIPTION": "The remainder of the Talk installation will take about ten minutes. Once you complete the following two steps, you will have a free installation and provision of Mongo and Redis.", "SUBMIT": "Get Started" }, + "ADD_ORGANIZATION": { + "DESCRIPTION": "Please tell us the name of your organization. This will appear in emails when inviting new team members", + "LABEL": "Organization Name", + "SAVE": "Save" + }, "PERMITTED_DOMAINS": { "TITLE": "Permitted domains", "DESCRIPTION": "Add permitted domains", @@ -15,6 +20,11 @@ "DESCRIPTION": "La instalación de Talk tomará aproximadamente diez minutos. Tan pronto como termines los tres pasos, tendrás una gratis instalación y provision de Mongo y Redis", "SUBMIT": "Empezá!" }, + "ADD_ORGANIZATION": { + "DESCRIPTION": "Por favor, dinos el nombre de tu organización. Este aparecerá en los emails cuando invites nuevos miembros", + "LABEL": "Nombre de la Organización", + "SAVE": "Guardar" + }, "PERMITTED_DOMAINS": { "TITLE": "Dominios Permitidos", "DESCRIPTION": "Agrega dominios permitidos", From b47fd3543740c55fc61779710196a0c6f7727773 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Mon, 27 Feb 2017 16:58:16 -0300 Subject: [PATCH 033/132] add user translations --- .../Install/components/Steps/CreateYourAccount.js | 10 +++++----- .../src/containers/Install/translations.json | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/client/coral-admin/src/containers/Install/components/Steps/CreateYourAccount.js b/client/coral-admin/src/containers/Install/components/Steps/CreateYourAccount.js index cb0f4635f..ec1e34607 100644 --- a/client/coral-admin/src/containers/Install/components/Steps/CreateYourAccount.js +++ b/client/coral-admin/src/containers/Install/components/Steps/CreateYourAccount.js @@ -12,7 +12,7 @@ const InitialStep = props => { className={styles.textField} id="email" type="email" - label='Email address' + label={lang.t('CREATE.EMAIL')} onChange={handleUserChange} showErrors={install.showErrors} errorMsg={install.errors.email} @@ -23,7 +23,7 @@ const InitialStep = props => { className={styles.textField} id="username" type="text" - label='Username' + label={lang.t('CREATE.USERNAME')} onChange={handleUserChange} showErrors={install.showErrors} errorMsg={install.errors.username} @@ -33,7 +33,7 @@ const InitialStep = props => { className={styles.textField} id="password" type="password" - label='Password' + label={lang.t('CREATE.PASSWORD')} onChange={handleUserChange} showErrors={install.showErrors} errorMsg={install.errors.password} @@ -43,7 +43,7 @@ const InitialStep = props => { className={styles.textField} id="confirmPassword" type="password" - label='Confirm Password' + label={lang.t('CREATE.CONFIRM_PASSWORD')} onChange={handleUserChange} showErrors={install.showErrors} errorMsg={install.errors.confirmPassword} @@ -51,7 +51,7 @@ const InitialStep = props => { { !props.install.isLoading ? - + : } diff --git a/client/coral-admin/src/containers/Install/translations.json b/client/coral-admin/src/containers/Install/translations.json index aee01c3cd..64b18101a 100644 --- a/client/coral-admin/src/containers/Install/translations.json +++ b/client/coral-admin/src/containers/Install/translations.json @@ -9,6 +9,13 @@ "LABEL": "Organization Name", "SAVE": "Save" }, + "CREATE": { + "EMAIL": "Email address", + "USERNAME": "Username", + "PASSWORD": "Password", + "CONFIRM_PASSWORD": "Confirm Password", + "SAVE": "Save" + }, "PERMITTED_DOMAINS": { "TITLE": "Permitted domains", "DESCRIPTION": "Add permitted domains", @@ -25,6 +32,13 @@ "LABEL": "Nombre de la Organización", "SAVE": "Guardar" }, + "CREATE": { + "EMAIL": "Dirección de E-Mail", + "USERNAME": "Usuario", + "PASSWORD": "Contraseña", + "CONFIRM_PASSWORD": "Confirmar contraseña", + "SAVE": "Guardar" + }, "PERMITTED_DOMAINS": { "TITLE": "Dominios Permitidos", "DESCRIPTION": "Agrega dominios permitidos", From 628e8844f3ff6dcdd087e7380f37a8d9e7a5fbd6 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Mon, 27 Feb 2017 17:04:14 -0300 Subject: [PATCH 034/132] final translations --- .../Install/components/Steps/CreateYourAccount.js | 4 ++++ .../Install/components/Steps/FinalStep.js | 14 +++++++------- .../src/containers/Install/translations.json | 10 ++++++++++ 3 files changed, 21 insertions(+), 7 deletions(-) diff --git a/client/coral-admin/src/containers/Install/components/Steps/CreateYourAccount.js b/client/coral-admin/src/containers/Install/components/Steps/CreateYourAccount.js index ec1e34607..416fac195 100644 --- a/client/coral-admin/src/containers/Install/components/Steps/CreateYourAccount.js +++ b/client/coral-admin/src/containers/Install/components/Steps/CreateYourAccount.js @@ -2,6 +2,10 @@ import React from 'react'; import styles from './style.css'; import {TextField, Button, Spinner} from 'coral-ui'; +const lang = new I18n(translations); +import translations from '../../translations.json'; +import I18n from 'coral-framework/modules/i18n/i18n'; + const InitialStep = props => { const {handleUserChange, handleUserSubmit, install} = props; return ( diff --git a/client/coral-admin/src/containers/Install/components/Steps/FinalStep.js b/client/coral-admin/src/containers/Install/components/Steps/FinalStep.js index e549ebe63..0ad918487 100644 --- a/client/coral-admin/src/containers/Install/components/Steps/FinalStep.js +++ b/client/coral-admin/src/containers/Install/components/Steps/FinalStep.js @@ -3,16 +3,16 @@ import styles from './style.css'; import {Button} from 'coral-ui'; import {Link} from 'react-router'; +const lang = new I18n(translations); +import translations from '../../translations.json'; +import I18n from 'coral-framework/modules/i18n/i18n'; + const InitialStep = () => { return (
-

- Thanks for installing Talk! We sent an email to verify your email - address. While you finish setting the account, you can start engaging - with your readers now. -

- - +

{lang.t('FINAL.DESCRIPTION')}

+ +
); }; diff --git a/client/coral-admin/src/containers/Install/translations.json b/client/coral-admin/src/containers/Install/translations.json index 64b18101a..3bae62c3a 100644 --- a/client/coral-admin/src/containers/Install/translations.json +++ b/client/coral-admin/src/containers/Install/translations.json @@ -20,6 +20,11 @@ "TITLE": "Permitted domains", "DESCRIPTION": "Add permitted domains", "SUBMIT": "Finish install" + }, + "FINAL": { + "DESCRIPTION": "Thanks for installing Talk! We sent an email to verify your email address. While you finish setting the account, you can start engaging with your readers now.", + "LAUNCH": "Launch Talk", + "CLOSE": "Close this Installer" } }, "es": { @@ -43,6 +48,11 @@ "TITLE": "Dominios Permitidos", "DESCRIPTION": "Agrega dominios permitidos", "SUBMIT": "Finalizar instalación" + }, + "FINAL": { + "DESCRIPTION": "Gracias por instalar Talk! Te enviamos un email para verificar tu identidad. Mientras se termina de configurar la cuenta, ya puedes empezar a interactuar con tus lectores", + "LAUNCH": "Lanzar Talk", + "CLOSE": "Cerrar este instalador" } } } From b9e9d3e7fa60b5e1e11141d27df9dc339a62b3d9 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Mon, 27 Feb 2017 17:06:22 -0300 Subject: [PATCH 035/132] status --- .../containers/Install/components/Steps/AddOrganizationName.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/coral-admin/src/containers/Install/components/Steps/AddOrganizationName.js b/client/coral-admin/src/containers/Install/components/Steps/AddOrganizationName.js index 127c4afa1..bcac6ef29 100644 --- a/client/coral-admin/src/containers/Install/components/Steps/AddOrganizationName.js +++ b/client/coral-admin/src/containers/Install/components/Steps/AddOrganizationName.js @@ -17,7 +17,7 @@ const AddOrganizationName = props => { className={styles.TextField} id="organizationName" type="text" - label={lang.t('ADD_ORGANIZATION.DESCRIPTION')} + label={lang.t('ADD_ORGANIZATION.LABEL')} onChange={handleSettingsChange} showErrors={install.showErrors} errorMsg={install.errors.organizationName} /> From 1234a99a0d75d634fc94f11babe12635655fb1a4 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Mon, 27 Feb 2017 17:16:19 -0300 Subject: [PATCH 036/132] copy for install permitted domains updated --- client/coral-admin/src/containers/Install/translations.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/coral-admin/src/containers/Install/translations.json b/client/coral-admin/src/containers/Install/translations.json index 3bae62c3a..8f651240c 100644 --- a/client/coral-admin/src/containers/Install/translations.json +++ b/client/coral-admin/src/containers/Install/translations.json @@ -18,7 +18,7 @@ }, "PERMITTED_DOMAINS": { "TITLE": "Permitted domains", - "DESCRIPTION": "Add permitted domains", + "DESCRIPTION": "Enter the domains you would like to permit for Talk, e.g. your local, staging and production environments (ex. localhost:3000, staging.domain.com, domain.com).", "SUBMIT": "Finish install" }, "FINAL": { @@ -46,7 +46,7 @@ }, "PERMITTED_DOMAINS": { "TITLE": "Dominios Permitidos", - "DESCRIPTION": "Agrega dominios permitidos", + "DESCRIPTION": "Agrega dominios permitidos a Talk, e.g. tu localhost, staging y ambientes de production (ex. localhost:3000, staging.domain.com, domain.com).", "SUBMIT": "Finalizar instalación" }, "FINAL": { From 555faa02f5629eb4d97a7e0522af5c890cc8a8a0 Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Mon, 27 Feb 2017 17:18:37 -0300 Subject: [PATCH 037/132] new translations for configure --- client/coral-admin/src/translations.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/coral-admin/src/translations.json b/client/coral-admin/src/translations.json index 7219a22ca..e32d3fb9d 100644 --- a/client/coral-admin/src/translations.json +++ b/client/coral-admin/src/translations.json @@ -86,7 +86,7 @@ "comment-count-text-post": " characters.", "comment-count-error": "Please enter a valid number.", "domain-list-title": "Domain Whitelist", - "domain-list-text": "Some instructions on how to type the urls." + "domain-list-text": "Enter the domains you would like to permit for Talk, e.g. your local, staging and production environments (ex. localhost:3000, staging.domain.com, domain.com)." }, "bandialog": { "ban_user": "Ban User?", @@ -206,7 +206,7 @@ "comment-count-text-post": " caracteres", "comment-count-error": "Por favor escribe un número válido.", "domain-list-title": "Lista de Dominios Permitidos", - "domain-list-text": "Instrucciones de como ingresar las URLs." + "domain-list-text": "Agrega dominios permitidos a Talk, e.g. tu localhost, staging y ambientes de production (ex. localhost:3000, staging.domain.com, domain.com)." }, "embedlink": { "copy": "Copiar" From 6cd3c84853a59b90c08e37a82fbbbfb62fff31bb Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Mon, 27 Feb 2017 14:21:48 -0700 Subject: [PATCH 038/132] Moved route definitions into env wrapped check, webpackified embed --- client/coral-embed/index.js | 193 -------------------------------- client/coral-embed/src/index.js | 119 ++++++++++++++++++++ routes/index.js | 21 ++-- webpack.config.js | 9 +- 4 files changed, 138 insertions(+), 204 deletions(-) delete mode 100644 client/coral-embed/index.js create mode 100644 client/coral-embed/src/index.js diff --git a/client/coral-embed/index.js b/client/coral-embed/index.js deleted file mode 100644 index 4a7e753ca..000000000 --- a/client/coral-embed/index.js +++ /dev/null @@ -1,193 +0,0 @@ -/* eslint-disable no-var, prefer-template */ -/** - * @file Exposes the main 'window.Coral.Talk' API that developers can use to - * render Talk streams in their webpages - * @todo Currently implemented to be included directly via - - - From bb1aea63baf7fa9fc58b4d20b0be43ddedc56b84 Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Tue, 28 Feb 2017 14:33:57 -0700 Subject: [PATCH 073/132] add a couple of routes --- client/coral-admin/src/AppRouter.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/coral-admin/src/AppRouter.js b/client/coral-admin/src/AppRouter.js index d96bacfe0..a1ba32ea7 100644 --- a/client/coral-admin/src/AppRouter.js +++ b/client/coral-admin/src/AppRouter.js @@ -14,6 +14,8 @@ import Dashboard from 'containers/Dashboard/Dashboard'; const routes = (
+ + From b369fb910106f5314128df43f567387f8f1f50ae Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Tue, 28 Feb 2017 14:38:19 -0700 Subject: [PATCH 074/132] re-rename --- .../src/components/{LoginView.js => AdminLogin.js} | 6 +++--- client/coral-admin/src/containers/LayoutContainer.js | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) rename client/coral-admin/src/components/{LoginView.js => AdminLogin.js} (92%) diff --git a/client/coral-admin/src/components/LoginView.js b/client/coral-admin/src/components/AdminLogin.js similarity index 92% rename from client/coral-admin/src/components/LoginView.js rename to client/coral-admin/src/components/AdminLogin.js index e9b740683..b96a84031 100644 --- a/client/coral-admin/src/components/LoginView.js +++ b/client/coral-admin/src/components/AdminLogin.js @@ -3,7 +3,7 @@ import Layout from 'coral-admin/src/components/ui/Layout'; import styles from './NotFound.css'; import {Button, TextField} from 'coral-ui'; -class LoginView extends React.Component { +class AdminLogin extends React.Component { constructor (props) { super(props); @@ -42,8 +42,8 @@ class LoginView extends React.Component { } } -LoginView.propTypes = { +AdminLogin.propTypes = { handleLogin: PropTypes.func.isRequired }; -export default LoginView; +export default AdminLogin; diff --git a/client/coral-admin/src/containers/LayoutContainer.js b/client/coral-admin/src/containers/LayoutContainer.js index ce3c7d1bf..94ce98c55 100644 --- a/client/coral-admin/src/containers/LayoutContainer.js +++ b/client/coral-admin/src/containers/LayoutContainer.js @@ -3,7 +3,7 @@ import {connect} from 'react-redux'; import Layout from '../components/ui/Layout'; import {checkLogin, handleLogin, logout} from '../actions/auth'; import {FullLoading} from '../components/FullLoading'; -import LoginView from '../components/LoginView'; +import AdminLogin from '../components/AdminLogin'; class LayoutContainer extends Component { componentWillMount () { @@ -15,7 +15,7 @@ class LayoutContainer extends Component { const {handleLogout} = this.props; if (loadingUser) { return ; } if (!isAdmin) { - return ; + return ; } if (isAdmin && loggedIn) { return ; } return ; From d8117494d1f968bb6452bcd3a98ab6141959699c Mon Sep 17 00:00:00 2001 From: David Jay Date: Tue, 28 Feb 2017 18:18:17 -0500 Subject: [PATCH 075/132] Cleaning up after merge conflict. --- graph/loaders/comments.js | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/graph/loaders/comments.js b/graph/loaders/comments.js index 6c9d4bcbc..afa79ea5c 100644 --- a/graph/loaders/comments.js +++ b/graph/loaders/comments.js @@ -39,14 +39,7 @@ const getCountsByAssetID = (context, asset_ids) => { /** * Returns the comment count for all comments that are public based on their * parent ids. - * @param {Object} - - - - - - - graph context + * * @param {Array} parent_ids the ids of parents for which there are * comments that we want to get */ @@ -284,7 +277,7 @@ const genRecentComments = (_, ids) => { * @return {Promise} resolves to the comments */ const genComments = ({user}, ids) => { - let comments + let comments; if (user && user.hasRoles('ADMIN')) { comments = CommentModel.find({ id: { @@ -300,11 +293,8 @@ const genComments = ({user}, ids) => { $in: ['NONE', 'ACCEPTED'] } }); + } return comments.then(util.singleJoinBy(ids, 'id')); - - */ -const genCommentsByID = (context, ids) => { - }; /** From 8f23ca678d93144cc86c3c7a46f8d1e66bb64c7a Mon Sep 17 00:00:00 2001 From: riley Date: Tue, 28 Feb 2017 16:30:05 -0700 Subject: [PATCH 076/132] add Alert component to coral-ui --- client/coral-admin/src/actions/auth.js | 4 ++-- client/coral-admin/src/components/AdminLogin.js | 10 ++++++++-- .../src/containers/LayoutContainer.js | 6 ++++-- client/coral-admin/src/reducers/auth.js | 7 ++++++- client/coral-admin/src/translations.json | 8 +++++++- .../components/CreateUsernameDialog.js | 3 +-- .../coral-sign-in/components/SignInContent.js | 3 +-- .../coral-sign-in/components/SignUpContent.js | 3 +-- client/coral-sign-in/components/styles.css | 17 ----------------- client/coral-ui/components/Alert.css | 16 ++++++++++++++++ .../components/Alert.js | 2 +- client/coral-ui/index.js | 1 + 12 files changed, 48 insertions(+), 32 deletions(-) create mode 100644 client/coral-ui/components/Alert.css rename client/{coral-sign-in => coral-ui}/components/Alert.js (87%) diff --git a/client/coral-admin/src/actions/auth.js b/client/coral-admin/src/actions/auth.js index 0eb17f74c..66c063d00 100644 --- a/client/coral-admin/src/actions/auth.js +++ b/client/coral-admin/src/actions/auth.js @@ -1,5 +1,5 @@ import * as actions from '../constants/auth'; -import coralApi from '../../../coral-framework/helpers/response'; +import coralApi from 'coral-framework/helpers/response'; // Log In. export const handleLogin = (email, password) => dispatch => { @@ -10,7 +10,7 @@ export const handleLogin = (email, password) => dispatch => { dispatch(checkLoginSuccess(result.user, isAdmin)); }) .catch(error => { - console.error(error); + dispatch({type: actions.LOGIN_FAILURE, message: error.translation_key}); }); }; diff --git a/client/coral-admin/src/components/AdminLogin.js b/client/coral-admin/src/components/AdminLogin.js index b96a84031..1475ccce7 100644 --- a/client/coral-admin/src/components/AdminLogin.js +++ b/client/coral-admin/src/components/AdminLogin.js @@ -1,7 +1,10 @@ import React, {PropTypes} from 'react'; import Layout from 'coral-admin/src/components/ui/Layout'; import styles from './NotFound.css'; -import {Button, TextField} from 'coral-ui'; +import {Button, TextField, Alert} from 'coral-ui'; +import I18n from 'coral-framework/modules/i18n/i18n'; +import translations from '../translations'; +const lang = new I18n(translations); class AdminLogin extends React.Component { @@ -16,12 +19,14 @@ class AdminLogin extends React.Component { } render () { + const {errorMessage} = this.props; return (

Permission Required

Sign in to interact with your community.

+ {errorMessage && {lang.t(`errors.${errorMessage}`)}} ; } if (!isAdmin) { - return ; + return ; } if (isAdmin && loggedIn) { return ; } return ; diff --git a/client/coral-admin/src/reducers/auth.js b/client/coral-admin/src/reducers/auth.js index 095ef7aac..d2f178773 100644 --- a/client/coral-admin/src/reducers/auth.js +++ b/client/coral-admin/src/reducers/auth.js @@ -4,7 +4,8 @@ import * as actions from '../constants/auth'; const initialState = Map({ loggedIn: false, user: null, - isAdmin: false + isAdmin: false, + loginError: null }); export default function auth (state = initialState, action) { @@ -25,6 +26,10 @@ export default function auth (state = initialState, action) { .set('user', action.user); case actions.LOGOUT_SUCCESS: return initialState; + case actions.LOGIN_REQUEST: + return state.set('loginError', null); + case actions.LOGIN_FAILURE: + return state.set('loginError', action.message); default : return state; } diff --git a/client/coral-admin/src/translations.json b/client/coral-admin/src/translations.json index 7219a22ca..0fbd09011 100644 --- a/client/coral-admin/src/translations.json +++ b/client/coral-admin/src/translations.json @@ -1,5 +1,8 @@ { "en": { + "errors": { + "NOT_AUTHORIZED": "Your username or password is not recognized by our system." + }, "community": { "username_and_email": "Username and Email", "account_creation_date": "Account Creation Date", @@ -132,6 +135,9 @@ } }, "es": { + "errors": { + "NOT_AUTHORIZED": "Acción no autorizada." + }, "community": { "username_and_email": "Usuario y E-mail", "account_creation_date": "Fecha de creación de la cuenta", @@ -213,7 +219,7 @@ }, "bandialog": { "ban_user": "Quieres suspender el Usuario?", - "are_you_sure": "Estas segura que quieres suspender a {props.author.username}?", + "are_you_sure": "Estas segura que quieres suspender a {0}?", "note": "Nota: Suspender este usuario también va a colocar este comentario en la cola de Rechazados.", "cancel": "Cancelar", "yes_ban_user": "Si, Suspendan el usuario" diff --git a/client/coral-sign-in/components/CreateUsernameDialog.js b/client/coral-sign-in/components/CreateUsernameDialog.js index d0e348046..4a7a99b81 100644 --- a/client/coral-sign-in/components/CreateUsernameDialog.js +++ b/client/coral-sign-in/components/CreateUsernameDialog.js @@ -1,8 +1,7 @@ import React from 'react'; import TextField from 'coral-ui/components/TextField'; -import Alert from './Alert'; import Button from 'coral-ui/components/Button'; -import {Dialog} from 'coral-ui'; +import {Dialog, Alert} from 'coral-ui'; import FakeComment from './FakeComment'; import styles from './styles.css'; diff --git a/client/coral-sign-in/components/SignInContent.js b/client/coral-sign-in/components/SignInContent.js index 1f339979b..a0ed5b5b4 100644 --- a/client/coral-sign-in/components/SignInContent.js +++ b/client/coral-sign-in/components/SignInContent.js @@ -1,6 +1,5 @@ import React, {PropTypes} from 'react'; -import Alert from './Alert'; -import {Button, TextField, Spinner, Success} from 'coral-ui'; +import {Button, TextField, Spinner, Success, Alert} from 'coral-ui'; import styles from './styles.css'; import I18n from 'coral-framework/modules/i18n/i18n'; import translations from '../translations'; diff --git a/client/coral-sign-in/components/SignUpContent.js b/client/coral-sign-in/components/SignUpContent.js index 6a781675b..c1e1d36cc 100644 --- a/client/coral-sign-in/components/SignUpContent.js +++ b/client/coral-sign-in/components/SignUpContent.js @@ -1,6 +1,5 @@ import React, {PropTypes} from 'react'; -import Alert from './Alert'; -import {Button, TextField, Spinner, Success} from 'coral-ui'; +import {Button, TextField, Spinner, Success, Alert} from 'coral-ui'; import styles from './styles.css'; import I18n from 'coral-framework/modules/i18n/i18n'; import translations from '../translations'; diff --git a/client/coral-sign-in/components/styles.css b/client/coral-sign-in/components/styles.css index 31d4a4fed..d3cd47b87 100644 --- a/client/coral-sign-in/components/styles.css +++ b/client/coral-sign-in/components/styles.css @@ -65,23 +65,6 @@ input.error{ padding: 3px 0 16px; } -.alert { - padding: 10px; - margin-bottom: 20px; - border-radius: 2px; -} - -.alert--success { - border: solid 1px #1ec00e; - background: #cbf1b8; - color: #006900; -} - -.alert--error { - background: #FFEBEE; - color: #B71C1C; -} - .userBox { padding: 10px 0 20px; letter-spacing: 0.1px; diff --git a/client/coral-ui/components/Alert.css b/client/coral-ui/components/Alert.css new file mode 100644 index 000000000..47b4787a1 --- /dev/null +++ b/client/coral-ui/components/Alert.css @@ -0,0 +1,16 @@ +.alert { + padding: 10px; + margin-bottom: 20px; + border-radius: 2px; +} + +.alert--success { + border: solid 1px #1ec00e; + background: #cbf1b8; + color: #006900; +} + +.alert--error { + background: #FFEBEE; + color: #B71C1C; +} diff --git a/client/coral-sign-in/components/Alert.js b/client/coral-ui/components/Alert.js similarity index 87% rename from client/coral-sign-in/components/Alert.js rename to client/coral-ui/components/Alert.js index 019c3456a..02f0524ff 100644 --- a/client/coral-sign-in/components/Alert.js +++ b/client/coral-ui/components/Alert.js @@ -1,5 +1,5 @@ import React from 'react'; -import styles from './styles.css'; +import styles from './Alert.css'; const Alert = ({cStyle = 'error', children, className, ...props}) => (
Date: Tue, 28 Feb 2017 17:10:51 -0700 Subject: [PATCH 077/132] add reset password link --- client/coral-admin/src/actions/auth.js | 11 ++++ .../coral-admin/src/components/AdminLogin.js | 63 ++++++++++++++----- .../coral-admin/src/components/NotFound.css | 7 +++ client/coral-admin/src/constants/auth.js | 4 ++ .../src/containers/LayoutContainer.js | 13 +++- client/coral-admin/src/reducers/auth.js | 7 ++- 6 files changed, 85 insertions(+), 20 deletions(-) diff --git a/client/coral-admin/src/actions/auth.js b/client/coral-admin/src/actions/auth.js index 66c063d00..4fd4f3c63 100644 --- a/client/coral-admin/src/actions/auth.js +++ b/client/coral-admin/src/actions/auth.js @@ -14,6 +14,17 @@ export const handleLogin = (email, password) => dispatch => { }); }; +const forgotPassowordRequest = () => ({type: actions.FETCH_FORGOT_PASSWORD_REQUEST}); +const forgotPassowordSuccess = () => ({type: actions.FETCH_FORGOT_PASSWORD_SUCCESS}); +const forgotPassowordFailure = () => ({type: actions.FETCH_FORGOT_PASSWORD_FAILURE}); + +export const requestPasswordReset = email => dispatch => { + dispatch(forgotPassowordRequest(email)); + return coralApi('/account/password/reset', {method: 'POST', body: {email}}) + .then(() => dispatch(forgotPassowordSuccess())) + .catch(error => dispatch(forgotPassowordFailure(error))); +}; + // Check Login const checkLoginRequest = () => ({type: actions.CHECK_LOGIN_REQUEST}); diff --git a/client/coral-admin/src/components/AdminLogin.js b/client/coral-admin/src/components/AdminLogin.js index 1475ccce7..cd9bac1d4 100644 --- a/client/coral-admin/src/components/AdminLogin.js +++ b/client/coral-admin/src/components/AdminLogin.js @@ -10,7 +10,7 @@ class AdminLogin extends React.Component { constructor (props) { super(props); - this.state = {email: '', password: ''}; + this.state = {email: '', password: '', requestPassword: false}; } handleSignIn = e => { @@ -18,29 +18,57 @@ class AdminLogin extends React.Component { this.props.handleLogin(this.state.email, this.state.password); } + handleRequestPassword = e => { + e.preventDefault(); + this.props.requestPasswordReset(this.state.email); + } + render () { const {errorMessage} = this.props; + const signInForm = ( + + {errorMessage && {lang.t(`errors.${errorMessage}`)}} + this.setState({email: e.target.value})} /> + this.setState({password: e.target.value})} + type='password' /> + +

+ Forgot your password? { + e.preventDefault(); + this.setState({requestPassword: true}); + }}>Request a new one. +

+ + ); + const requestPasswordForm = ( + this.props.passwordRequestSuccess + ?

{this.props.passwordRequestSuccess}

+ :
+ this.setState({email: e.target.value})} /> + + + ); return (

Permission Required

Sign in to interact with your community.

-
- {errorMessage && {lang.t(`errors.${errorMessage}`)}} - this.setState({email: e.target.value})} /> - this.setState({password: e.target.value})} - type='password' /> - - + { this.state.requestPassword ? requestPasswordForm : signInForm }
); @@ -49,6 +77,7 @@ class AdminLogin extends React.Component { AdminLogin.propTypes = { handleLogin: PropTypes.func.isRequired, + passwordRequestSuccess: PropTypes.string, loginError: PropTypes.string }; diff --git a/client/coral-admin/src/components/NotFound.css b/client/coral-admin/src/components/NotFound.css index e0e04e0fd..c45fbcc02 100644 --- a/client/coral-admin/src/components/NotFound.css +++ b/client/coral-admin/src/components/NotFound.css @@ -6,3 +6,10 @@ .layout h1 { font-size: 40px; } + +.passwordRequestSuccess { + padding: 8px 14px; + background: lightgreen; + border: 1px solid darkgreen; + border-radius: 4px; +} diff --git a/client/coral-admin/src/constants/auth.js b/client/coral-admin/src/constants/auth.js index 88a9c4a3f..3c47bfc45 100644 --- a/client/coral-admin/src/constants/auth.js +++ b/client/coral-admin/src/constants/auth.js @@ -11,3 +11,7 @@ export const LOGOUT_FAILURE = 'LOGOUT_FAILURE'; export const LOGIN_REQUEST = 'LOGIN_REQUEST'; export const LOGIN_SUCCESS = 'LOGIN_SUCCESS'; export const LOGIN_FAILURE = 'LOGIN_FAILURE'; + +export const FETCH_FORGOT_PASSWORD_REQUEST = 'FETCH_FORGOT_PASSWORD_REQUEST'; +export const FETCH_FORGOT_PASSWORD_SUCCESS = 'FETCH_FORGOT_PASSWORD_SUCCESS'; +export const FETCH_FORGOT_PASSWORD_FAILURE = 'FETCH_FORGOT_PASSWORD_FAILURE'; diff --git a/client/coral-admin/src/containers/LayoutContainer.js b/client/coral-admin/src/containers/LayoutContainer.js index ca9ff2e7b..d122cd23a 100644 --- a/client/coral-admin/src/containers/LayoutContainer.js +++ b/client/coral-admin/src/containers/LayoutContainer.js @@ -1,7 +1,7 @@ import React, {Component} from 'react'; import {connect} from 'react-redux'; import Layout from '../components/ui/Layout'; -import {checkLogin, handleLogin, logout} from '../actions/auth'; +import {checkLogin, handleLogin, logout, requestPasswordReset} from '../actions/auth'; import {FullLoading} from '../components/FullLoading'; import AdminLogin from '../components/AdminLogin'; @@ -11,12 +11,20 @@ class LayoutContainer extends Component { checkLogin(); } render () { - const {isAdmin, loggedIn, loadingUser, loginError} = this.props.auth; + const { + isAdmin, + loggedIn, + loadingUser, + loginError, + passwordRequestSuccess + } = this.props.auth; const {handleLogout} = this.props; if (loadingUser) { return ; } if (!isAdmin) { return ; } if (isAdmin && loggedIn) { return ; } @@ -31,6 +39,7 @@ const mapStateToProps = state => ({ const mapDispatchToProps = dispatch => ({ checkLogin: () => dispatch(checkLogin()), handleLogin: (username, password) => dispatch(handleLogin(username, password)), + requestPasswordReset: email => dispatch(requestPasswordReset(email)), handleLogout: () => dispatch(logout()) }); diff --git a/client/coral-admin/src/reducers/auth.js b/client/coral-admin/src/reducers/auth.js index d2f178773..b52efdb85 100644 --- a/client/coral-admin/src/reducers/auth.js +++ b/client/coral-admin/src/reducers/auth.js @@ -5,7 +5,8 @@ const initialState = Map({ loggedIn: false, user: null, isAdmin: false, - loginError: null + loginError: null, + passwordRequestSuccess: null }); export default function auth (state = initialState, action) { @@ -30,6 +31,10 @@ export default function auth (state = initialState, action) { return state.set('loginError', null); case actions.LOGIN_FAILURE: return state.set('loginError', action.message); + case actions.FETCH_FORGOT_PASSWORD_REQUEST: + return state.set('passwordRequestSuccess', null); + case actions.FETCH_FORGOT_PASSWORD_SUCCESS: + return state.set('passwordRequestSuccess', 'If you have a registered account, a password reset link was sent to that email.'); default : return state; } From 42b380b942ac56066f93101fbfb189e767c91abe Mon Sep 17 00:00:00 2001 From: Belen Curcio Date: Tue, 28 Feb 2017 22:35:37 -0300 Subject: [PATCH 078/132] Flag box --- .../ModerationQueue/ModerationQueue.js | 1 + .../ModerationQueue/components/Comment.js | 60 ++++++++++--------- .../components/CommentType.css | 33 ++++++++++ .../ModerationQueue/components/CommentType.js | 30 ++++++++++ .../ModerationQueue/components/FlagBox.css | 35 +++++++++++ .../ModerationQueue/components/FlagBox.js | 20 ++++--- .../ModerationQueue/components/styles.css | 40 +++++++------ 7 files changed, 164 insertions(+), 55 deletions(-) create mode 100644 client/coral-admin/src/containers/ModerationQueue/components/CommentType.css create mode 100644 client/coral-admin/src/containers/ModerationQueue/components/CommentType.js create mode 100644 client/coral-admin/src/containers/ModerationQueue/components/FlagBox.css diff --git a/client/coral-admin/src/containers/ModerationQueue/ModerationQueue.js b/client/coral-admin/src/containers/ModerationQueue/ModerationQueue.js index 0d48acc92..23ed45f2e 100644 --- a/client/coral-admin/src/containers/ModerationQueue/ModerationQueue.js +++ b/client/coral-admin/src/containers/ModerationQueue/ModerationQueue.js @@ -21,6 +21,7 @@ const ModerationQueue = ({activeTab = 'premod', ...props}) => { key={i} index={i} comment={comment} + commentType={activeTab} suspectWords={props.suspectWords} actions={actionsMap[status]} showBanUserDialog={props.showBanUserDialog} diff --git a/client/coral-admin/src/containers/ModerationQueue/components/Comment.js b/client/coral-admin/src/containers/ModerationQueue/components/Comment.js index b39eeb2f8..98e24f92a 100644 --- a/client/coral-admin/src/containers/ModerationQueue/components/Comment.js +++ b/client/coral-admin/src/containers/ModerationQueue/components/Comment.js @@ -8,6 +8,7 @@ import styles from './styles.css'; import {Icon} from 'coral-ui'; import ActionButton from '../../../components/ActionButton'; import FlagBox from './FlagBox'; +import CommentType from './CommentType'; const linkify = new Linkify(); @@ -21,46 +22,48 @@ const Comment = ({actions = [], ...props}) => { return (
  • -
    +
    +
    {props.comment.user.name} - {timeago().format(props.comment.created_at || (Date.now() - props.index * 60 * 1000), lang.getLocale().replace('-', '_'))} - - {props.comment.action_summaries ?

    {lang.t('comment.flagged')}

    : null} + {timeago().format(props.comment.created_at || (Date.now() - props.index * 60 * 1000), lang.getLocale().replace('-', '_'))} + +
    {links ? Contains Link : null} -
    - {actions.map((action, i) => - props.acceptComment({commentId: props.comment.id})} - rejectComment={() => props.rejectComment({commentId: props.comment.id})} - showBanUserDialog={() => props.showBanUserDialog(props.comment.user, props.comment.id)} - /> - )} -
    +
    + {actions.map((action, i) => + props.acceptComment({commentId: props.comment.id})} + rejectComment={() => props.rejectComment({commentId: props.comment.id})} + showBanUserDialog={() => props.showBanUserDialog(props.comment.user, props.comment.id)} + /> + )} +
    {props.comment.user.status === 'banned' ? - + {lang.t('comment.banned_user')} - - : null} + + : null}
    - {!props.currentAsset && ( -
    - Article: {props.comment.asset.title} Moderate Article + {!props.currentAsset && ( +
    + Story: {props.comment.asset.title} Moderate → +
    + )} +
    +

    + + + +

    - )} -
    -

    - - - -

    {actionSummaries && }
  • @@ -72,7 +75,6 @@ Comment.propTypes = { rejectComment: PropTypes.func.isRequired, suspectWords: PropTypes.arrayOf(PropTypes.string).isRequired, currentAsset: PropTypes.object, - isActive: PropTypes.bool.isRequired, comment: PropTypes.shape({ body: PropTypes.string.isRequired, action_summaries: PropTypes.array, diff --git a/client/coral-admin/src/containers/ModerationQueue/components/CommentType.css b/client/coral-admin/src/containers/ModerationQueue/components/CommentType.css new file mode 100644 index 000000000..42c0b75f0 --- /dev/null +++ b/client/coral-admin/src/containers/ModerationQueue/components/CommentType.css @@ -0,0 +1,33 @@ +.commentType { + position: absolute; + right: 5px; + top: 5px; + color: white; + background: grey; + padding: 2px 13px; + font-size: 14px; + height: 32px; + box-sizing: border-box; + line-height: 29px; + padding-left: 26px; + + i { + font-size: 14px; + position: absolute; + left: 6px; + top: 8px; + margin: 0; + } + + &.premod { + background: #063B9A; + } + + &.flagged { + background: #d03235; + } + + &.no-type { + display: none; + } +} diff --git a/client/coral-admin/src/containers/ModerationQueue/components/CommentType.js b/client/coral-admin/src/containers/ModerationQueue/components/CommentType.js new file mode 100644 index 000000000..5ad4138ca --- /dev/null +++ b/client/coral-admin/src/containers/ModerationQueue/components/CommentType.js @@ -0,0 +1,30 @@ +import React, {PropTypes} from 'react'; +import styles from './CommentType.css'; +import {Icon} from 'coral-ui'; + +const CommentType = props => { + const typeData = getTypeData(props.type); + + return ( + + {typeData.text} + + ); +}; + +const getTypeData = type => { + switch (type) { + case 'premod': + return {icon: 'query_builder', text: 'Pre-Mod', className: 'premod'}; + case 'flagged': + return {icon: 'flag', text: 'Flagged', className: 'flagged'}; + default: + return {icon: 'flag', className: 'no-type'}; + } +}; + +CommentType.propTypes = { + type: PropTypes.string.isRequired +}; + +export default CommentType; diff --git a/client/coral-admin/src/containers/ModerationQueue/components/FlagBox.css b/client/coral-admin/src/containers/ModerationQueue/components/FlagBox.css new file mode 100644 index 000000000..0806c30c3 --- /dev/null +++ b/client/coral-admin/src/containers/ModerationQueue/components/FlagBox.css @@ -0,0 +1,35 @@ +.flagBox { + border-top: 1px solid rgba(66, 66, 66, 0.12); + + .container { + padding: 0 14px; + } + + .header { + position: relative; + .moreDetail { + float: right; + } + 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; + } + } + + h3 { + vertical-align: middle; + margin: 0; + font-weight: 500; + display: inline-block; + margin-left: 7px; + font-size: 12px; + } +} diff --git a/client/coral-admin/src/containers/ModerationQueue/components/FlagBox.js b/client/coral-admin/src/containers/ModerationQueue/components/FlagBox.js index 6140abd90..f30d32662 100644 --- a/client/coral-admin/src/containers/ModerationQueue/components/FlagBox.js +++ b/client/coral-admin/src/containers/ModerationQueue/components/FlagBox.js @@ -1,14 +1,20 @@ import React, {PropTypes} from 'react'; -import styles from './styles.css'; +import {Icon} from 'coral-ui'; +import styles from './FlagBox.css'; const FlagBox = props => (
    -

    Flags:

    -
      - {props.actionSummaries.map((action, i) => -
    • {!action.reason ? No reason provided : action.reason} ({action.count})
    • - )} -
    +
    +
    +

    Flags ({props.actionSummaries.length}):

    +
      + {props.actionSummaries.map((action, i) => +
    • {!action.reason ? No reason provided : action.reason} ({action.count})
    • + )} +
    + +
    +
    ); diff --git a/client/coral-admin/src/containers/ModerationQueue/components/styles.css b/client/coral-admin/src/containers/ModerationQueue/components/styles.css index 27d5c2533..fdaf01439 100644 --- a/client/coral-admin/src/containers/ModerationQueue/components/styles.css +++ b/client/coral-admin/src/containers/ModerationQueue/components/styles.css @@ -162,16 +162,20 @@ span { .listItem { border-bottom: 1px solid #e0e0e0; - font-size: 16px; + font-size: 18px; width: 100%; max-width: 660px; min-width: 400px; margin: 0 auto; - padding: 16px 14px; position: relative; transition: box-shadow 200ms; margin-top: 0; + padding: 20px 0 0; + min-height: 187px; + .container { + padding: 0 14px; + } &:hover { box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23); @@ -213,6 +217,8 @@ span { .itemBody { display: flex; justify-content: space-between; + margin-top: 15px; + font-size: 16px; } .avatar { @@ -228,7 +234,7 @@ span { .created { color: #666; font-size: 13px; - margin-left: 40px; + margin-left: 15px; } .actionButton { @@ -310,20 +316,26 @@ span { } .Comment { + .moderateArticle { - font-size: 12px; + font-size: 15px; + margin-top: 14px; + font-weight: 500; a { display: inline-block; - color: #679af3; + color: #063b9a; text-decoration: none; - font-size: 1em; - font-weight: 400; + font-weight: 500; letter-spacing: .5px; - font-size: 12px; margin-left: 10px; + font-size: 13px; + margin-left: 5px; + padding-bottom: 0px; + border-bottom: solid 1px; + line-height: 16px; + &:hover { - text-decoration: underline; opacity: .9; cursor: pointer; } @@ -331,16 +343,6 @@ span { } } -.flagBox { - max-width: 480px; - border-top: 1px solid rgba(66, 66, 66, 0.12); - h3 { - font-size: 14px; - margin: 0; - font-weight: 500; - } -} - .selectField { position: relative; width: 140px; From 378622f7e8bc5835ac42171497ad34830e80949d Mon Sep 17 00:00:00 2001 From: Benjamin Goering Date: Wed, 1 Mar 2017 12:46:35 +0800 Subject: [PATCH 079/132] commentTag mutation tests await SettingsService --- test/graph/mutations/addCommentTag.js | 2 +- test/graph/mutations/removeCommentTag.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/graph/mutations/addCommentTag.js b/test/graph/mutations/addCommentTag.js index fcbb0d0e8..14a746705 100644 --- a/test/graph/mutations/addCommentTag.js +++ b/test/graph/mutations/addCommentTag.js @@ -10,7 +10,7 @@ const CommentsService = require('../../../services/comments'); describe('graph.mutations.addCommentTag', () => { let comment; beforeEach(async () => { - SettingsService.init(); + await SettingsService.init(); comment = await CommentsService.publicCreate({body: `hello there! ${ String(Math.random()).slice(2)}`}); }); diff --git a/test/graph/mutations/removeCommentTag.js b/test/graph/mutations/removeCommentTag.js index c10f70172..99def095d 100644 --- a/test/graph/mutations/removeCommentTag.js +++ b/test/graph/mutations/removeCommentTag.js @@ -10,7 +10,7 @@ const CommentsService = require('../../../services/comments'); describe('graph.mutations.removeCommentTag', () => { let comment; beforeEach(async () => { - SettingsService.init(); + await SettingsService.init(); comment = await CommentsService.publicCreate({body: `hello there! ${ String(Math.random()).slice(2)}`}); }); From 388c3182ea79ca7b4cd98a8bcc44f28775437aff Mon Sep 17 00:00:00 2001 From: Benjamin Goering Date: Wed, 1 Mar 2017 13:08:36 +0800 Subject: [PATCH 080/132] Change add,removeTag in CommentsService to use simpler query then elemMatch --- services/comments.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/services/comments.js b/services/comments.js index 4b11f3622..b0594cf8d 100644 --- a/services/comments.js +++ b/services/comments.js @@ -59,7 +59,7 @@ module.exports = class CommentsService { const filter = { id, - tags: {$not: {$elemMatch: {name}}} + 'tags.name': {$ne: name}, }; const update = { $push: {tags: { @@ -101,7 +101,7 @@ module.exports = class CommentsService { static removeTag(id, name) { const filter = { id, - tags: {$elemMatch: {name}} + 'tags.name': name, }; const update = {$pull: {tags: {name}}}; return CommentModel.update(filter, update) From 405dac292c1da4a0b6e1cfce81eac501de62eef0 Mon Sep 17 00:00:00 2001 From: Benjamin Goering Date: Wed, 1 Mar 2017 13:43:39 +0800 Subject: [PATCH 081/132] Only transform-async-to-generator for client code. Allows async to work with mocha tests (if proper node version) --- .babelrc | 1 - client/.babelrc | 6 ++++++ package.json | 2 +- test/mocha.opts | 1 - 4 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 client/.babelrc diff --git a/.babelrc b/.babelrc index 41d27bf34..6186cefaf 100644 --- a/.babelrc +++ b/.babelrc @@ -5,7 +5,6 @@ ], "plugins": [ "add-module-exports", - "transform-async-to-generator", "transform-class-properties", "transform-decorators-legacy", "transform-object-assign", diff --git a/client/.babelrc b/client/.babelrc new file mode 100644 index 000000000..27289288c --- /dev/null +++ b/client/.babelrc @@ -0,0 +1,6 @@ +{ + "extends": "../.babelrc", + "plugins": [ + "transform-async-to-generator", + ] +} diff --git a/package.json b/package.json index 7e4c6dfa6..140e9d4e5 100644 --- a/package.json +++ b/package.json @@ -165,6 +165,6 @@ "webpack": "^2.2.1" }, "engines": { - "node": ">=7.0.0" + "node": ">=7.6.0" } } diff --git a/test/mocha.opts b/test/mocha.opts index 76ca86399..a159ae7aa 100644 --- a/test/mocha.opts +++ b/test/mocha.opts @@ -2,7 +2,6 @@ test/helpers/*.js test --compilers js:babel-core/register --require ignore-styles ---require babel-polyfill --recursive --colors --sort From 4b2cc72e1aea194e3f0ce498254c08eade311fd0 Mon Sep 17 00:00:00 2001 From: Benjamin Goering Date: Wed, 1 Mar 2017 14:01:12 +0800 Subject: [PATCH 082/132] Remove unnecessary defensive code in CommentsService --- services/comments.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/services/comments.js b/services/comments.js index b0594cf8d..85cc03167 100644 --- a/services/comments.js +++ b/services/comments.js @@ -86,8 +86,8 @@ module.exports = class CommentsService { // tag added return; default: - console.warn('CommentsService#addTag modified multiple comments, but it should only have modified 1. ' - + `You may have bad data. Check for multiple comments with id=${id}`); + + // this should never happen because no multi parameter and unique index on id } }); } @@ -122,8 +122,8 @@ module.exports = class CommentsService { // tag removed return; default: - console.warn('CommentsService#removeTag modified multiple comments, but it should only have modified 1. ' - + `You may have bad data. Check for multiple comments with id=${id}`); + + // this should never happen because no multi parameter and unique index on id } }); } From b0036ef77842247c8bd2f75174547a642c6afcd6 Mon Sep 17 00:00:00 2001 From: Benjamin Goering Date: Wed, 1 Mar 2017 14:09:03 +0800 Subject: [PATCH 083/132] Remove findById in error conditions of CommentsService@addTag,removeTag --- services/comments.js | 20 +++----------------- 1 file changed, 3 insertions(+), 17 deletions(-) diff --git a/services/comments.js b/services/comments.js index 85cc03167..75b53873a 100644 --- a/services/comments.js +++ b/services/comments.js @@ -73,14 +73,8 @@ module.exports = class CommentsService { switch (nModified) { case 0: - // either the tag was already there, or the comment doesn't exist with that id... - return this.findById(id) - .then(result => { - if ( ! result) { - throw new Error(`Can't add tag to comment. There is no comment with id ${id}`); - } - throw new Error(`Can't add tag ${name} to comment. Comment already has that tag.`); - }); + // either the tag was already there, or the comment doesn't exist with that id... + throw new Error('Could not add tag to comment. Either the comment doesn\'t exist or the tag is already present.'); case 1: // tag added @@ -108,15 +102,7 @@ module.exports = class CommentsService { .then(({nModified}) => { switch (nModified) { case 0: - - // either the tag was already there, or the comment doesn't exist with that id... - return this.findById(id) - .then(result => { - if ( ! result) { - throw new Error(`Can't remove tag from comment. There is no comment with id ${id}`); - } - throw new Error(`Can't remove tag ${name} from comment. Comment doesn't have that tag.`); - }); + throw new Error('Could not remove tag from comment. Either the comment doesn\'t exist or the tag is not present'); case 1: // tag removed From 5e0d01a6493ec68c122242cb0c4db518b2c1e4f2 Mon Sep 17 00:00:00 2001 From: Benjamin Goering Date: Wed, 1 Mar 2017 14:15:31 +0800 Subject: [PATCH 084/132] lift findById out of add,removeCommentTag mutators and into root_mutation.js defs --- graph/mutators/comment.js | 6 ++---- graph/resolvers/root_mutation.js | 5 +++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/graph/mutators/comment.js b/graph/mutators/comment.js index c9b3b0ab0..94ffb850c 100644 --- a/graph/mutators/comment.js +++ b/graph/mutators/comment.js @@ -193,8 +193,7 @@ const setCommentStatus = ({loaders: {Comments}}, {id, status}) => { * @param {String} tag name of the tag */ const addCommentTag = ({user, loaders: {Comments}}, {id, tag}) => { - return CommentsService.addTag(id, tag, user.id) - .then(() => CommentsService.findById( id )); + return CommentsService.addTag(id, tag, user.id); }; /** @@ -203,8 +202,7 @@ const addCommentTag = ({user, loaders: {Comments}}, {id, tag}) => { * @param {String} tag name of the tag */ const removeCommentTag = ({user, loaders: {Comments}}, {id, tag}) => { - return CommentsService.removeTag(id, tag) - .then(() => CommentsService.findById( id )); + return CommentsService.removeTag(id, tag); }; module.exports = (context) => { diff --git a/graph/resolvers/root_mutation.js b/graph/resolvers/root_mutation.js index 61c4367c1..dc540b202 100644 --- a/graph/resolvers/root_mutation.js +++ b/graph/resolvers/root_mutation.js @@ -1,5 +1,6 @@ const {Error: {ValidationError}} = require('mongoose'); const errors = require('../../errors'); +const CommentsService = require('../../services/comments'); /** * Wraps up a promise to return an object with the resolution of the promise @@ -50,10 +51,10 @@ const RootMutation = { return wrapResponse(null)(Comment.setCommentStatus({id, status})); }, addCommentTag(_, {id, tag}, {mutators: {Comment}}) { - return wrapResponse('comment')(Comment.addCommentTag({id, tag})); + return wrapResponse('comment')(Comment.addCommentTag({id, tag}).then(() => CommentsService.findById(id))); }, removeCommentTag(_, {id, tag}, {mutators: {Comment}}) { - return wrapResponse('comment')(Comment.removeCommentTag({id, tag})); + return wrapResponse('comment')(Comment.removeCommentTag({id, tag}).then(() => CommentsService.findById(id))); }, }; From 90730e52be09e5eeb1186d78026b286accde2a03 Mon Sep 17 00:00:00 2001 From: Benjamin Goering Date: Wed, 1 Mar 2017 14:56:44 +0800 Subject: [PATCH 085/132] Make all comment action buttons use cursor:pointer and nowrap (sam said ok) --- client/coral-embed-stream/src/Comment.js | 71 +++++++++++++-------- client/coral-embed-stream/style/default.css | 8 ++- client/coral-plugin-best/BestButton.js | 6 +- client/coral-plugin-replies/ReplyButton.js | 2 +- 4 files changed, 50 insertions(+), 37 deletions(-) diff --git a/client/coral-embed-stream/src/Comment.js b/client/coral-embed-stream/src/Comment.js index 3cc13174a..1e4802470 100644 --- a/client/coral-embed-stream/src/Comment.js +++ b/client/coral-embed-stream/src/Comment.js @@ -26,6 +26,11 @@ const getActionSummary = (type, comment) => comment.action_summaries .filter((a) => a.__typename === type)[0]; const isStaff = (tags) => !tags.every((t) => t.name !== 'STAFF') ; +// hold actions links (e.g. Like, Reply) along the comment footer +const ActionButton = ({children}) => { + return { children }; +}; + class Comment extends React.Component { constructor(props) { @@ -135,36 +140,46 @@ class Comment extends React.Component {
    - - setActiveReplyBox(comment.id)} - parentCommentId={parentId || comment.id} - currentUserId={currentUser && currentUser.id} - banned={false} /> - - - + + + + + setActiveReplyBox(comment.id)} + parentCommentId={parentId || comment.id} + currentUserId={currentUser && currentUser.id} + banned={false} /> + + + + + +
    - - + + + + + +
    { activeReplyBox === comment.id diff --git a/client/coral-embed-stream/style/default.css b/client/coral-embed-stream/style/default.css index 6a8c58059..afc690f01 100644 --- a/client/coral-embed-stream/style/default.css +++ b/client/coral-embed-stream/style/default.css @@ -214,15 +214,17 @@ hr { } .comment__action-container .material-icons { - font-size: 12px !important; + font-size: 12px; margin-left: 3px; } -.comment__action-button { +button.comment__action-button, +.comment__action-button button { cursor: pointer; } -.comment__action-button[disabled] { +button.comment__action-button[disabled], +.comment__action-button[disabled] button { cursor: inherit; } diff --git a/client/coral-plugin-best/BestButton.js b/client/coral-plugin-best/BestButton.js index 182bd27c2..ac0e75aaf 100644 --- a/client/coral-plugin-best/BestButton.js +++ b/client/coral-plugin-best/BestButton.js @@ -89,17 +89,13 @@ export class BestButton extends Component { } render() { - - // @TODO(bengo) Consider adding the comment__action--cursor-pointer to all buttons to add cursor:pointer and never wrap the icons const {isBest, addBest, removeBest} = this.props; const {isSaving} = this.state; const disabled = isSaving || ! (isBest ? removeBest : addBest); return ( ); }; diff --git a/client/coral-admin/src/components/BanUserButton.css b/client/coral-admin/src/components/BanUserButton.css index 79b805c30..36243348f 100644 --- a/client/coral-admin/src/components/BanUserButton.css +++ b/client/coral-admin/src/components/BanUserButton.css @@ -1,6 +1,7 @@ .banButton { - width: 114px; - letter-spacing: 1px; + -webkit-transform: scale(.8); + transform: scale(.8); + margin: 0; i { vertical-align: middle; diff --git a/client/coral-admin/src/components/BanUserButton.js b/client/coral-admin/src/components/BanUserButton.js index 191164ca5..a54cdd322 100644 --- a/client/coral-admin/src/components/BanUserButton.js +++ b/client/coral-admin/src/components/BanUserButton.js @@ -8,7 +8,7 @@ const lang = new I18n(translations); const BanUserButton = ({user, ...props}) => (
    -
    {index + 1}.{lang.t('streams.article')} {lang.t('modqueue.flagged')}{lang.t('modqueue.likes')} {lang.t('dashboard.comment_count')}
    {index + 1}. {flagSummary ? flagSummary.actionCount : 0}{likeSummary ? likeSummary.actionCount : 0} {asset.commentCount}
    {lang.t('streams.article')}{lang.t('modqueue.flagged')} {lang.t('modqueue.likes')} {lang.t('dashboard.comment_count')}
    {flagSummary ? flagSummary.actionCount : 0} {likeSummary ? likeSummary.actionCount : 0} {asset.commentCount}
    {lang.t('streams.article')} {lang.t('modqueue.flagged')}{lang.t('dashboard.comment_count')}
    {flagSummary ? flagSummary.actionCount : 0}{asset.commentCount}
    {lang.t('streams.article')} {lang.t('modqueue.likes')}{lang.t('dashboard.comment_count')}
    {likeSummary ? likeSummary.actionCount : 0}{asset.commentCount}
    - {/* empty on purpose */} - + { assets.length - ? assets.map((asset, index) => { + ? assets.map(asset => { const flagSummary = asset.action_summaries.find(s => s.type === 'FlagAssetActionSummary'); return ( - - + + - ); }) - : + : }
    {lang.t('streams.article')}{lang.t('modqueue.flagged')}{lang.t('dashboard.flags')}
    {index + 1}.
    - {asset.title} -

    {asset.author} - Published: {new Date(asset.created_at).toLocaleDateString()}

    + +

    {asset.title}

    +

    {asset.author} — Published: {new Date(asset.created_at).toLocaleDateString()}

    + +
    + +

    {flagSummary ? flagSummary.actionCount : 0}

    +
    {flagSummary ? flagSummary.actionCount : 0}
    {lang.t('dashboard.no_flags')}
    {lang.t('dashboard.no_flags')}
    diff --git a/client/coral-admin/src/containers/Dashboard/LikeWidget.js b/client/coral-admin/src/containers/Dashboard/LikeWidget.js index ed6a0c0ae..d628c2e11 100644 --- a/client/coral-admin/src/containers/Dashboard/LikeWidget.js +++ b/client/coral-admin/src/containers/Dashboard/LikeWidget.js @@ -16,7 +16,6 @@ const LikeWidget = (props) => { - {/* empty on purpose */} @@ -24,20 +23,25 @@ const LikeWidget = (props) => { { assets.length - ? assets.map((asset, index) => { + ? assets.map(asset => { const likeSummary = asset.action_summaries.find(s => s.type === 'LikeAssetActionSummary'); return ( - + - ); }) - : + : }
    {lang.t('streams.article')} {lang.t('modqueue.likes')}
    {index + 1}. - {asset.title} -

    {asset.author} - Published: {new Date(asset.created_at).toLocaleDateString()}

    + +

    {asset.title}

    +

    {asset.author} — Published: {new Date(asset.created_at).toLocaleDateString()}

    + +
    + +

    {likeSummary ? likeSummary.actionCount : 0}

    +
    {likeSummary ? likeSummary.actionCount : 0}
    {lang.t('dashboard.no_likes')}
    {lang.t('dashboard.no_likes')}
    diff --git a/client/coral-admin/src/containers/Dashboard/Widget.css b/client/coral-admin/src/containers/Dashboard/Widget.css index 624b72519..a99c2febd 100644 --- a/client/coral-admin/src/containers/Dashboard/Widget.css +++ b/client/coral-admin/src/containers/Dashboard/Widget.css @@ -4,10 +4,12 @@ box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.2); padding: 15px; flex: 1; + background-color: white; } .heading { margin: 0; + padding-left: 10px; font-size: 1.5rem; font-weight: bold; } @@ -15,28 +17,62 @@ .widgetTable { width: 100%; border-collapse: collapse; - box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.2); + user-select: none; } .widgetTable thead th { - border-bottom: 1px solid #f47e6b; + color: rgb(35, 102, 223); padding: 10px; text-align: left; + text-transform: capitalize; } -.widgetTable tbody tr { +.widgetTable thead th:last-child { + width: 10%; +} + +.rowLinkify { + cursor: pointer; border-bottom: 1px solid lightgrey; + color: #555; } -.widgetTable tbody tr:last-child { +.rowLinkify:last-child { border-bottom: none; } +.rowLinkify:hover { + background-color: #f8f8f8; +} + .widgetTable tbody td { padding: 10px; } +.linkToAsset { + display: block; + text-decoration: none; +} + .lede { font-size: 0.9em; - color: grey; + color: #aaa; +} + +.assetTitle { + color: #555; + text-decoration: none; + font-size: 1.2em; + font-weight: normal; + margin: 0; +} + +.assetTitle:hover { + text-decoration: underline; +} + +.widgetCount { + color: #555; + font-size: 1.3em; + font-weight: 400; } diff --git a/client/coral-admin/src/reducers/settings.js b/client/coral-admin/src/reducers/settings.js index f74eb659f..4f7d90d59 100644 --- a/client/coral-admin/src/reducers/settings.js +++ b/client/coral-admin/src/reducers/settings.js @@ -6,7 +6,7 @@ import * as actions from '../actions/settings'; // cleaner updates are planned in the future. // TODO: if there are more than two fields for the dashboard being created here, // please create a new reducer specifically for the Dashboard. -const DASHBOARD_WINDOW_MINUTES = 5; +const DASHBOARD_WINDOW_MINUTES = 105; let then = new Date(); then.setMinutes(then.getMinutes() - DASHBOARD_WINDOW_MINUTES); diff --git a/client/coral-admin/src/translations.json b/client/coral-admin/src/translations.json index dbb3e650e..92e0cbbff 100644 --- a/client/coral-admin/src/translations.json +++ b/client/coral-admin/src/translations.json @@ -112,6 +112,7 @@ "dashboard": { "no_flags": "There have been no flags in the last 5 minutes! Hooray!", "no_likes": "There have been no likes in the last 5 minutes. All quiet.", + "flags": "Flags", "comment_count": "comments" }, "streams": { @@ -222,6 +223,7 @@ "dashbord": { "no_flags": "¡Nadie ha marcado nada en los últimos 5 minutos! ¡Bravo!", "no_likes": "A nadie le ha gustado algún comentario en los últimos 5 minutos. Todo tranquilo.", + "flags": "Marcados", "comment_count": "comentarios" }, "streams": { From 04ab00d053e441d5c5010b3cdf2d58f72ddf629d Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Wed, 1 Mar 2017 10:40:40 -0700 Subject: [PATCH 091/132] ignore this --- client/coral-admin/src/AppRouter.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/client/coral-admin/src/AppRouter.js b/client/coral-admin/src/AppRouter.js index aacc3d6c7..38d06dcb1 100644 --- a/client/coral-admin/src/AppRouter.js +++ b/client/coral-admin/src/AppRouter.js @@ -14,8 +14,6 @@ import Dashboard from 'containers/Dashboard/Dashboard'; const routes = (
    - - From 045fa3e2a945988910aa1e066d410c44695ccc2a Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Wed, 1 Mar 2017 10:42:01 -0700 Subject: [PATCH 092/132] also ignore this --- client/coral-admin/src/components/AdminLogin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/coral-admin/src/components/AdminLogin.js b/client/coral-admin/src/components/AdminLogin.js index cd9bac1d4..3d374bcda 100644 --- a/client/coral-admin/src/components/AdminLogin.js +++ b/client/coral-admin/src/components/AdminLogin.js @@ -66,7 +66,7 @@ class AdminLogin extends React.Component { return (
    -

    Permission Required

    +

    Team Sign In

    Sign in to interact with your community.

    { this.state.requestPassword ? requestPasswordForm : signInForm }
    From bbf70aedabb0afddb18f40c336a69fd214440a7c Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Wed, 1 Mar 2017 10:47:31 -0700 Subject: [PATCH 093/132] put it back to 5 minutes --- client/coral-admin/src/reducers/settings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/coral-admin/src/reducers/settings.js b/client/coral-admin/src/reducers/settings.js index 4f7d90d59..f74eb659f 100644 --- a/client/coral-admin/src/reducers/settings.js +++ b/client/coral-admin/src/reducers/settings.js @@ -6,7 +6,7 @@ import * as actions from '../actions/settings'; // cleaner updates are planned in the future. // TODO: if there are more than two fields for the dashboard being created here, // please create a new reducer specifically for the Dashboard. -const DASHBOARD_WINDOW_MINUTES = 105; +const DASHBOARD_WINDOW_MINUTES = 5; let then = new Date(); then.setMinutes(then.getMinutes() - DASHBOARD_WINDOW_MINUTES); From 45b14d026dec4927addbb33d5918e227d8da68ed Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 1 Mar 2017 10:49:47 -0700 Subject: [PATCH 094/132] Added more conditional checks to exclusion --- graph/loaders/metrics.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graph/loaders/metrics.js b/graph/loaders/metrics.js index 2627d82d9..a6fe5afe4 100644 --- a/graph/loaders/metrics.js +++ b/graph/loaders/metrics.js @@ -54,7 +54,7 @@ const getAssetMetrics = ({loaders: {Metrics, Assets, Comments}}, {from, to, sort .filter((asset) => { let contextActionSummary = asset.action_summaries.find((({action_type}) => action_type === sort)); - if (contextActionSummary === null) { + if (contextActionSummary === null || contextActionSummary.actionCount === 0) { return false; } From 00b2bf37eee9cdd2ff5280a507d03683ee798d6e Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Wed, 1 Mar 2017 11:14:13 -0700 Subject: [PATCH 095/132] fix height of the table --- client/coral-admin/src/containers/Dashboard/FlagWidget.js | 6 +++++- client/coral-admin/src/containers/Dashboard/LikeWidget.js | 8 ++++++-- client/coral-admin/src/containers/Dashboard/Widget.css | 6 ++++++ 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/client/coral-admin/src/containers/Dashboard/FlagWidget.js b/client/coral-admin/src/containers/Dashboard/FlagWidget.js index 5d891b3bb..da71ac04a 100644 --- a/client/coral-admin/src/containers/Dashboard/FlagWidget.js +++ b/client/coral-admin/src/containers/Dashboard/FlagWidget.js @@ -40,7 +40,11 @@ const FlagWidget = (props) => { ); }) - : {lang.t('dashboard.no_flags')} + : {lang.t('dashboard.no_flags')} + } + { /* rows in a table with a fixed height will expand and ignore height. + this extra row will expand to fill the extra space. */ + assets.length < 10 ? : null } diff --git a/client/coral-admin/src/containers/Dashboard/LikeWidget.js b/client/coral-admin/src/containers/Dashboard/LikeWidget.js index d628c2e11..25e851966 100644 --- a/client/coral-admin/src/containers/Dashboard/LikeWidget.js +++ b/client/coral-admin/src/containers/Dashboard/LikeWidget.js @@ -26,7 +26,7 @@ const LikeWidget = (props) => { ? assets.map(asset => { const likeSummary = asset.action_summaries.find(s => s.type === 'LikeAssetActionSummary'); return ( - +

    {asset.title}

    @@ -41,7 +41,11 @@ const LikeWidget = (props) => { ); }) - : {lang.t('dashboard.no_likes')} + : {lang.t('dashboard.no_likes')} + } + { /* rows in a table with a fixed height will expand and ignore height. + this extra row will expand to fill the extra space. */ + assets.length < 10 ? : null } diff --git a/client/coral-admin/src/containers/Dashboard/Widget.css b/client/coral-admin/src/containers/Dashboard/Widget.css index a99c2febd..cb764d9cc 100644 --- a/client/coral-admin/src/containers/Dashboard/Widget.css +++ b/client/coral-admin/src/containers/Dashboard/Widget.css @@ -1,3 +1,7 @@ +:root { + --row-height: 80px; +} + .widget { box-sizing: border-box; margin: 10px 5px 5px 5px; @@ -18,6 +22,7 @@ width: 100%; border-collapse: collapse; user-select: none; + height: calc(var(--row-height) * 10); } .widgetTable thead th { @@ -35,6 +40,7 @@ cursor: pointer; border-bottom: 1px solid lightgrey; color: #555; + height: var(--row-height); } .rowLinkify:last-child { From af8c9262968afbc30e6d805ae075be5ace14119d Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 1 Mar 2017 11:37:29 -0700 Subject: [PATCH 096/132] Pinning to 7.6 until upstream issues resolved, see #357 --- Dockerfile | 2 +- circle.yml | 2 +- package.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 14d606c0a..dc7e64e31 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:7 +FROM node:7.6 # Install yarn RUN npm install -g yarn diff --git a/circle.yml b/circle.yml index b29dfcc4c..2357ecf4c 100644 --- a/circle.yml +++ b/circle.yml @@ -1,6 +1,6 @@ machine: node: - version: 7 + version: 7.6 services: - docker - redis diff --git a/package.json b/package.json index cbf3a1267..740063dd1 100644 --- a/package.json +++ b/package.json @@ -165,6 +165,6 @@ "webpack": "^2.2.1" }, "engines": { - "node": ">=7.0.0" + "node": "~7.6.0" } } From 4e5bcbc27f61185bbc32e7301af21bb8974683f1 Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Wed, 1 Mar 2017 11:42:03 -0700 Subject: [PATCH 097/132] even more design updates --- .../coral-admin/src/components/AdminLogin.js | 30 ++++++++++------- .../coral-admin/src/components/NotFound.css | 32 ++++++++++++++++--- 2 files changed, 46 insertions(+), 16 deletions(-) diff --git a/client/coral-admin/src/components/AdminLogin.js b/client/coral-admin/src/components/AdminLogin.js index 3d374bcda..7c7d4b00f 100644 --- a/client/coral-admin/src/components/AdminLogin.js +++ b/client/coral-admin/src/components/AdminLogin.js @@ -1,7 +1,7 @@ import React, {PropTypes} from 'react'; import Layout from 'coral-admin/src/components/ui/Layout'; import styles from './NotFound.css'; -import {Button, TextField, Alert} from 'coral-ui'; +import {Button, TextField, Alert, Success} from 'coral-ui'; import I18n from 'coral-framework/modules/i18n/i18n'; import translations from '../translations'; const lang = new I18n(translations); @@ -29,20 +29,22 @@ class AdminLogin extends React.Component {
    {errorMessage && {lang.t(`errors.${errorMessage}`)}} this.setState({email: e.target.value})} /> this.setState({password: e.target.value})} type='password' /> +
    -

    - Forgot your password? { + full + onClick={this.handleSignIn}>Sign In +

    + Forgot your password? { e.preventDefault(); this.setState({requestPassword: true}); }}>Request a new one. @@ -51,23 +53,29 @@ class AdminLogin extends React.Component { ); const requestPasswordForm = ( this.props.passwordRequestSuccess - ?

    {this.props.passwordRequestSuccess}

    + ?

    { + location.href = location.href; + }}> + {this.props.passwordRequestSuccess} Sign in + +

    : this.setState({email: e.target.value})} /> ); return ( -
    -

    Team Sign In

    -

    Sign in to interact with your community.

    +
    +

    Team sign in

    +

    Sign in to interact with your community.

    { this.state.requestPassword ? requestPasswordForm : signInForm }
    diff --git a/client/coral-admin/src/components/NotFound.css b/client/coral-admin/src/components/NotFound.css index c45fbcc02..9977f858a 100644 --- a/client/coral-admin/src/components/NotFound.css +++ b/client/coral-admin/src/components/NotFound.css @@ -1,15 +1,37 @@ .layout { + max-width: 800px; + margin: 0 auto; +} + +.loginLayout { max-width: 400px; margin: 0 auto; } +.loginHeader, .loginCTA, .forgotPasswordCTA, .passwordRequestSuccess { + text-align: center; + font-size: 16px; +} + +.forgotPasswordLink, .signInLink { + color: blue; + font-weight: normal; + text-decoration: none; +} + +.forgotPasswordLink:hover, .signInLink:hover { + text-decoration: underline; +} + .layout h1 { font-size: 40px; } -.passwordRequestSuccess { - padding: 8px 14px; - background: lightgreen; - border: 1px solid darkgreen; - border-radius: 4px; +.loginHeader { + font-size: 30px; +} + +.passwordRequestSuccess { + cursor: pointer; + padding: 8px 14px; } From 2f05cec380a01986b8d5cdb12f0b78c2109bc6c2 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 1 Mar 2017 11:50:32 -0700 Subject: [PATCH 098/132] Removed yarn install (already has yarn!) --- Dockerfile | 3 --- 1 file changed, 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index dc7e64e31..fc0b3aca2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,5 @@ FROM node:7.6 -# Install yarn -RUN npm install -g yarn - # Create app directory RUN mkdir -p /usr/src/app WORKDIR /usr/src/app From 0085d2bb0473e4c2fd708e832cccc48ae11c65f6 Mon Sep 17 00:00:00 2001 From: David Jay Date: Wed, 1 Mar 2017 14:21:03 -0500 Subject: [PATCH 099/132] Preventing premod comments from being posted optimistically. --- client/coral-framework/graphql/mutations/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/coral-framework/graphql/mutations/index.js b/client/coral-framework/graphql/mutations/index.js index 67af2df4a..4c2920e54 100644 --- a/client/coral-framework/graphql/mutations/index.js +++ b/client/coral-framework/graphql/mutations/index.js @@ -40,7 +40,7 @@ export const postComment = graphql(POST_COMMENT, { updateQueries: { AssetQuery: (oldData, {mutationResult:{data:{createComment:{comment}}}}) => { - if (oldData.asset.moderation === 'PRE') { + if (oldData.asset.settings.moderation === 'PRE') { return oldData; } From 9cb835b08bc493ed072c00398f26cdb15ac13d74 Mon Sep 17 00:00:00 2001 From: David Jay Date: Wed, 1 Mar 2017 14:49:42 -0500 Subject: [PATCH 100/132] Setting action user_id to null on suspect words. --- graph/mutators/action.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/graph/mutators/action.js b/graph/mutators/action.js index a572a641c..3bc20cba4 100644 --- a/graph/mutators/action.js +++ b/graph/mutators/action.js @@ -16,7 +16,7 @@ const createAction = ({user = {}}, {item_id, item_type, action_type, group_id, m return ActionsService.insertUserAction({ item_id, item_type, - user_id: user.id, + user_id: group_id === 'Matched suspect word filter' ? null : user.id, group_id, action_type, metadata From 49477ead6a3ae3b80bf4689a1dbc69c24ba7b6f9 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 1 Mar 2017 13:47:08 -0700 Subject: [PATCH 101/132] Fixed temp issue --- Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Dockerfile b/Dockerfile index fc0b3aca2..7cd06e673 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,8 @@ FROM node:7.6 +# Add node-gyp for bcrypt build support +RUN yarn global add node-gyp + # Create app directory RUN mkdir -p /usr/src/app WORKDIR /usr/src/app From fb96d432ee4f1fcf237f56a9efda881db8b34bf0 Mon Sep 17 00:00:00 2001 From: Wyatt Johnson Date: Wed, 1 Mar 2017 13:51:32 -0700 Subject: [PATCH 102/132] Moved action creation upstream --- graph/mutators/action.js | 2 +- graph/mutators/comment.js | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/graph/mutators/action.js b/graph/mutators/action.js index 3bc20cba4..a572a641c 100644 --- a/graph/mutators/action.js +++ b/graph/mutators/action.js @@ -16,7 +16,7 @@ const createAction = ({user = {}}, {item_id, item_type, action_type, group_id, m return ActionsService.insertUserAction({ item_id, item_type, - user_id: group_id === 'Matched suspect word filter' ? null : user.id, + user_id: user.id, group_id, action_type, metadata diff --git a/graph/mutators/comment.js b/graph/mutators/comment.js index 5112ba829..d608eee57 100644 --- a/graph/mutators/comment.js +++ b/graph/mutators/comment.js @@ -1,6 +1,7 @@ const errors = require('../../errors'); const AssetsService = require('../../services/assets'); +const ActionsService = require('../../services/actions'); const CommentsService = require('../../services/comments'); const Wordlist = require('../../services/wordlist'); @@ -146,10 +147,11 @@ const createPublicComment = (context, commentInput) => { // TODO: this is kind of fragile, we should refactor this to resolve // all these const's that we're using like 'COMMENTS', 'FLAG' to be // defined in a checkable schema. - return context.mutators.Action.create({ + return ActionsService.insertUserAction({ item_id: comment.id, item_type: 'COMMENTS', action_type: 'FLAG', + user_id: null, group_id: 'Matched suspect word filter', metadata: {} }) From 62793f59472cb8a64fafa9c6b4492038c64649dc Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Wed, 1 Mar 2017 14:40:10 -0700 Subject: [PATCH 103/132] keepin' it DRY --- .../src/containers/Configure/Configure.css | 2 +- .../src/containers/Configure/Configure.js | 85 ++++++++++--------- .../src/containers/Configure/Domainlist.js | 24 +++--- .../src/containers/Configure/EmbedLink.js | 21 ++--- .../Configure/ModerationSettings.js | 56 ++++++++++++ .../{CommentSettings.js => StreamSettings.js} | 47 +--------- .../src/containers/Configure/TechSettings.js | 48 +++++++++++ client/coral-admin/src/reducers/settings.js | 4 +- 8 files changed, 177 insertions(+), 110 deletions(-) create mode 100644 client/coral-admin/src/containers/Configure/ModerationSettings.js rename client/coral-admin/src/containers/Configure/{CommentSettings.js => StreamSettings.js} (80%) create mode 100644 client/coral-admin/src/containers/Configure/TechSettings.js diff --git a/client/coral-admin/src/containers/Configure/Configure.css b/client/coral-admin/src/containers/Configure/Configure.css index 1f23af30b..5f4a07c81 100644 --- a/client/coral-admin/src/containers/Configure/Configure.css +++ b/client/coral-admin/src/containers/Configure/Configure.css @@ -150,7 +150,7 @@ margin-top: 38px; } -.commentSettingsSection { +.settingsSection { padding-bottom: 200px; .action { display: inline-block; diff --git a/client/coral-admin/src/containers/Configure/Configure.js b/client/coral-admin/src/containers/Configure/Configure.js index 1ec78dcd2..2fbe9daf2 100644 --- a/client/coral-admin/src/containers/Configure/Configure.js +++ b/client/coral-admin/src/containers/Configure/Configure.js @@ -8,22 +8,20 @@ import { updateDomainlist } from '../../actions/settings'; -import {Button, List, Item} from 'coral-ui'; +import {Button, List, Item, Card, Spinner} from 'coral-ui'; import styles from './Configure.css'; import I18n from 'coral-framework/modules/i18n/i18n'; -import translations from '../../translations.json'; -import EmbedLink from './EmbedLink'; -import CommentSettings from './CommentSettings'; -import Wordlist from './Wordlist'; -import Domainlist from './Domainlist'; -import has from 'lodash/has'; +import translations from 'coral-admin/src/translations.json'; +import StreamSettings from './StreamSettings'; +import ModerationSettings from './ModerationSettings'; +import TechSettings from './TechSettings'; class Configure extends Component { constructor (props) { super(props); this.state = { - activeSection: 'comments', + activeSection: 'stream', changed: false, errors: {} }; @@ -70,40 +68,51 @@ class Configure extends Component { getSection (section) { const pageTitle = this.getPageTitle(section); + let sectionComponent; switch(section){ - case 'comments': - return ; - case 'embed': - return has(this, 'props.settings.domains.whitelist') - ?
    - - -
    - : ; - case 'wordlist': - return has(this, 'props.settings.wordlist') - ? - :

    loading wordlists

    ; + break; + case 'moderation': + sectionComponent = ; + break; + case 'tech': + sectionComponent = ; } + + if (this.props.settings.fetchingSettings) { + return Loading settings...; + } + + return ( +
    +

    {pageTitle}

    + {sectionComponent} +
    + ); } getPageTitle (section) { switch(section) { - case 'comments': - return lang.t('configure.comment-settings'); - case 'embed': - return lang.t('configure.embed-comment-stream'); + case 'stream': + return lang.t('configure.stream-settings'); + case 'moderation': + return lang.t('configure.moderation-settings'); + case 'tech': + return lang.t('configure.tech-settings'); default: return ''; } @@ -120,14 +129,14 @@ class Configure extends Component {
    - - {lang.t('configure.comment-settings')} + + {lang.t('configure.stream-settings')} - - {lang.t('configure.embed-comment-stream')} + + {lang.t('configure.moderation-settings')} - - {lang.t('configure.wordlist')} + + {lang.t('configure.tech-settings')}
    diff --git a/client/coral-admin/src/containers/Configure/Domainlist.js b/client/coral-admin/src/containers/Configure/Domainlist.js index 6918c0471..bda3ca139 100644 --- a/client/coral-admin/src/containers/Configure/Domainlist.js +++ b/client/coral-admin/src/containers/Configure/Domainlist.js @@ -9,19 +9,17 @@ const lang = new I18n(translations); const Domainlist = ({domains, onChangeDomainlist}) => { return ( -
    -

    {lang.t('configure.domain-list-title')}

    - -

    {lang.t('configure.domain-list-text')}

    - data.split(',').map(d => d.trim())} - onChange={tags => onChangeDomainlist('whitelist', tags)} - /> -
    -
    + +

    {lang.t('configure.domain-list-title')}

    +

    {lang.t('configure.domain-list-text')}

    + data.split(',').map(d => d.trim())} + onChange={tags => onChangeDomainlist('whitelist', tags)} + /> +
    ); }; diff --git a/client/coral-admin/src/containers/Configure/EmbedLink.js b/client/coral-admin/src/containers/Configure/EmbedLink.js index 413f421d7..cdbb66c3a 100644 --- a/client/coral-admin/src/containers/Configure/EmbedLink.js +++ b/client/coral-admin/src/containers/Configure/EmbedLink.js @@ -44,19 +44,14 @@ class EmbedLink extends Component { "> `.trim(); return ( -
    -

    {this.props.title}

    -
    - -

    {lang.t('configure.copy-and-paste')}

    -