From d4e68de34959883d8ba10cd68e1a2a735be1d27d Mon Sep 17 00:00:00 2001 From: Riley Davis Date: Fri, 10 Feb 2017 15:32:30 -0700 Subject: [PATCH] setting up dashboard :) --- client/coral-admin/src/AppRouter.js | 2 + .../coral-admin/src/components/ui/Header.js | 40 +++++++++++++------ .../src/containers/Dashboard/Dashboard.js | 15 +++++++ .../coral-admin/src/graphql/queries/index.js | 4 ++ .../src/graphql/queries/mostFlags.graphql | 3 ++ client/coral-admin/src/translations.json | 2 + graph/loaders/assets.js | 10 +++++ graph/resolvers/root_query.js | 10 ++++- graph/typeDefs.graphql | 40 +++++++++++++++++++ 9 files changed, 112 insertions(+), 14 deletions(-) create mode 100644 client/coral-admin/src/containers/Dashboard/Dashboard.js create mode 100644 client/coral-admin/src/graphql/queries/index.js create mode 100644 client/coral-admin/src/graphql/queries/mostFlags.graphql diff --git a/client/coral-admin/src/AppRouter.js b/client/coral-admin/src/AppRouter.js index 9721123fa..e76690417 100644 --- a/client/coral-admin/src/AppRouter.js +++ b/client/coral-admin/src/AppRouter.js @@ -8,6 +8,7 @@ import CommentStream from 'containers/CommentStream/CommentStream'; import InstallContainer from 'containers/Install/InstallContainer'; import CommunityContainer from 'containers/Community/CommunityContainer'; import ModerationContainer from 'containers/ModerationQueue/ModerationContainer'; +import Dashboard from 'containers/Dashboard/Dashboard'; const routes = (
@@ -18,6 +19,7 @@ const routes = ( +
); diff --git a/client/coral-admin/src/components/ui/Header.js b/client/coral-admin/src/components/ui/Header.js index 3e6598d6e..7263c7ca4 100644 --- a/client/coral-admin/src/components/ui/Header.js +++ b/client/coral-admin/src/components/ui/Header.js @@ -13,21 +13,35 @@ export default ({handleLogout, restricted = false}) => ( !restricted ?
- - {lang.t('configure.moderate')} - - - {lang.t('configure.community')} + + {lang.t('configure.moderate')} + + + {lang.t('configure.community')} - - {lang.t('configure.configure')} + + {lang.t('configure.configure')} - - {lang.t('configure.streams')} + + {lang.t('configure.streams')} + + + {lang.t('configure.dashboard')}
diff --git a/client/coral-admin/src/containers/Dashboard/Dashboard.js b/client/coral-admin/src/containers/Dashboard/Dashboard.js new file mode 100644 index 000000000..c287d5f2c --- /dev/null +++ b/client/coral-admin/src/containers/Dashboard/Dashboard.js @@ -0,0 +1,15 @@ +import React from 'react'; +import {compose} from 'react-apollo'; +import {mostFlags} from 'coral-admin/src/graphql/queries'; + +class Dashboard extends React.Component { + render () { + return ( +
Dashboard
+ ); + } +} + +export default compose( + mostFlags +)(Dashboard); diff --git a/client/coral-admin/src/graphql/queries/index.js b/client/coral-admin/src/graphql/queries/index.js new file mode 100644 index 000000000..30550e48a --- /dev/null +++ b/client/coral-admin/src/graphql/queries/index.js @@ -0,0 +1,4 @@ +import {graphql} from 'react-apollo'; +import MOST_FLAGS from './mostFlags.graphql'; + +export const mostFlags = graphql(MOST_FLAGS, {}); diff --git a/client/coral-admin/src/graphql/queries/mostFlags.graphql b/client/coral-admin/src/graphql/queries/mostFlags.graphql new file mode 100644 index 000000000..b84e21d08 --- /dev/null +++ b/client/coral-admin/src/graphql/queries/mostFlags.graphql @@ -0,0 +1,3 @@ +query mostFlags { + metric +} diff --git a/client/coral-admin/src/translations.json b/client/coral-admin/src/translations.json index 0eb1ab98d..68658d4a0 100644 --- a/client/coral-admin/src/translations.json +++ b/client/coral-admin/src/translations.json @@ -48,6 +48,7 @@ "copy": "Copy to Clipboard" }, "configure": { + "dashboard": "Dashboard", "enable-pre-moderation": "Enable pre-moderation", "enable-pre-moderation-text": "Moderators must approve any comment before it is published.", "require-email-verification": "Require Email Verification", @@ -157,6 +158,7 @@ "username_flags": "" }, "configure": { + "dashboard": "Panel", "enable-pre-moderation": "Habilitar pre-moderación", "enable-pre-moderation-text": "Los moderadores deben aprobar cada comentario antes de que sea publicado.", "require-email-verification": "Necesita confirmación de correo", diff --git a/graph/loaders/assets.js b/graph/loaders/assets.js index a07a18a3f..ba8fb3751 100644 --- a/graph/loaders/assets.js +++ b/graph/loaders/assets.js @@ -46,6 +46,15 @@ const findOrCreateAssetByURL = (context, asset_url) => { }); }; +const getAssetsForMetrics = ({loaders: {Actions, Comments}}) => { + return Actions.getByTypes({action_type: 'FLAG', item_type: 'COMMENT'}) + .then((actions) => { // ALL ACTIONS :O + const ids = actions.map(({item_id}) => item_id); + + return Comments.getByQuery({ids}); + }); +}; + /** * Creates a set of loaders based on a GraphQL context. * @param {Object} context the context of the GraphQL request @@ -59,6 +68,7 @@ module.exports = (context) => ({ getByURL: (url) => findOrCreateAssetByURL(context, url), getByID: new DataLoader((ids) => genAssetsByID(context, ids)), + getForMetrics: () => getAssetsForMetrics(context), getAll: new util.SingletonResolver(() => AssetModel.find({})) } }); diff --git a/graph/resolvers/root_query.js b/graph/resolvers/root_query.js index 8aa14d5c6..72d57ed14 100644 --- a/graph/resolvers/root_query.js +++ b/graph/resolvers/root_query.js @@ -34,7 +34,7 @@ const RootQuery = { // Map the actions from the items referenced byt this query. The actions // returned by this query are explicitly going to be distinct by their // `item_id`'s. - let ids = actions.map((action) => action.item_id); + let ids = actions.map(({item_id}) => item_id); // Perform the query using the available resolver. return Comments.getByQuery({ids, statuses, asset_id, parent_id, limit, cursor, sort}); @@ -44,6 +44,14 @@ const RootQuery = { return Comments.getByQuery(query); }, + metric(_, args, {user, loaders: {Assets}}) { + if (user == null || !user.hasRoles('ADMIN')) { + return null; + } + + return Assets.getForMetrics(); + }, + // This returns the current user, ensure that if we aren't logged in, we // return null. me(_, args, {user}) { diff --git a/graph/typeDefs.graphql b/graph/typeDefs.graphql index e231bc0c3..7cbb6bd47 100644 --- a/graph/typeDefs.graphql +++ b/graph/typeDefs.graphql @@ -167,6 +167,36 @@ interface ActionSummary { current_user: Action } +# A summary of actions for a specific action type on an Asset. +interface AssetActionSummary { + + # Number of actions associated with actionable types on this this Asset. + actionCount: Int + + # Number of unique actionable types that are referenced by the actions. + actionableItemCount: Int +} + +# A summary of counts related to all the Likes on an Asset. +type LikeAssetActionSummary implements AssetActionSummary { + + # Number of actions associated with actionable types on this this Asset. + actionCount: Int + + # Number of unique actionable types that are referenced by the actions. + actionableItemCount: Int +} + +# A summary of counts related to all the Flags on an Asset. +type FlagAssetActionSummary implements AssetActionSummary { + + # Number of actions associated with actionable types on this this Asset. + actionCount: Int + + # Number of unique actionable types that are referenced by the actions. + actionableItemCount: Int +} + # LikeAction is used by users who "like" a specific entity. type LikeAction implements Action { @@ -294,6 +324,13 @@ type Asset { # The date that the asset was created. created_at: Date + + # Summary of all Actions against all entities associated with the Asset. + # (likes, flags, etc.) + action_summaries: [AssetActionSummary] + + # Unique users that have commented on this Asset. + authorCount: Int } ################################################################################ @@ -358,6 +395,9 @@ type RootQuery { # The currently logged in user based on the request. me: User + + # metrics + metric: [Asset] } ################################################################################