From 473221dbada7ad7739d6a969d9d3d5c9c276941b Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Fri, 23 Oct 2015 16:56:26 -0700 Subject: PLT-25 adding analytics panel --- web/react/.eslintrc | 3 +- web/react/components/admin_console/line_chart.jsx | 50 ++++++ .../components/admin_console/team_analytics.jsx | 190 +++++++++++++++++++-- 3 files changed, 230 insertions(+), 13 deletions(-) create mode 100644 web/react/components/admin_console/line_chart.jsx (limited to 'web/react') diff --git a/web/react/.eslintrc b/web/react/.eslintrc index 6a35d3123..d78068882 100644 --- a/web/react/.eslintrc +++ b/web/react/.eslintrc @@ -20,7 +20,8 @@ "globals": { "React": false, "ReactDOM": false, - "ReactBootstrap": false + "ReactBootstrap": false, + "Chart": false }, "rules": { "comma-dangle": [2, "never"], diff --git a/web/react/components/admin_console/line_chart.jsx b/web/react/components/admin_console/line_chart.jsx new file mode 100644 index 000000000..7e2f95c84 --- /dev/null +++ b/web/react/components/admin_console/line_chart.jsx @@ -0,0 +1,50 @@ +// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +export default class LineChart extends React.Component { + constructor(props) { + super(props); + + this.initChart = this.initChart.bind(this); + this.chart = null; + } + + componentDidMount() { + this.initChart(this.props); + } + + componentWillReceiveProps(nextProps) { + if (this.chart) { + this.chart.destroy(); + this.initChart(nextProps); + } + } + + componentWillUnmount() { + if (this.chart) { + this.chart.destroy(); + } + } + + initChart(props) { + var el = ReactDOM.findDOMNode(this); + var ctx = el.getContext('2d'); + this.chart = new Chart(ctx).Line(props.data, props.options || {}); //eslint-disable-line new-cap + } + + render() { + return ( + + ); + } +} + +LineChart.propTypes = { + width: React.PropTypes.string, + height: React.PropTypes.string, + data: React.PropTypes.object, + options: React.PropTypes.object +}; diff --git a/web/react/components/admin_console/team_analytics.jsx b/web/react/components/admin_console/team_analytics.jsx index 9d452f95e..8a6723806 100644 --- a/web/react/components/admin_console/team_analytics.jsx +++ b/web/react/components/admin_console/team_analytics.jsx @@ -2,8 +2,9 @@ // See License.txt for license information. var Client = require('../../utils/client.jsx'); +var LineChart = require('./line_chart.jsx'); -export default class UserList extends React.Component { +export default class TeamAnalytics extends React.Component { constructor(props) { super(props); @@ -15,7 +16,9 @@ export default class UserList extends React.Component { channel_open_count: null, channel_private_count: null, post_count: null, - post_counts_day: null + post_counts_day: null, + user_counts_with_posts_day: null, + recent_active_users: null }; } @@ -31,14 +34,17 @@ export default class UserList extends React.Component { for (var index in data) { if (data[index].name === 'channel_open_count') { this.setState({channel_open_count: data[index].value}); + this.setState({channel_open_count: 55}); } if (data[index].name === 'channel_private_count') { this.setState({channel_private_count: data[index].value}); + this.setState({channel_private_count: 12}); } if (data[index].name === 'post_count') { this.setState({post_count: data[index].value}); + this.setState({post_count: 5332}); } } }, @@ -51,8 +57,80 @@ export default class UserList extends React.Component { teamId, 'post_counts_day', (data) => { - console.log(data); - this.setState({post_counts_day: data}); + data.push({name: '2015-10-24', value: 73}); + data.push({name: '2015-10-25', value: 84}); + data.push({name: '2015-10-26', value: 61}); + data.push({name: '2015-10-27', value: 97}); + data.push({name: '2015-10-28', value: 73}); + data.push({name: '2015-10-29', value: 84}); + data.push({name: '2015-10-30', value: 61}); + data.push({name: '2015-10-31', value: 97}); + + var chartData = { + labels: [], + datasets: [{ + label: 'Total Posts', + fillColor: 'rgba(151,187,205,0.2)', + strokeColor: 'rgba(151,187,205,1)', + pointColor: 'rgba(151,187,205,1)', + pointStrokeColor: '#fff', + pointHighlightFill: '#fff', + pointHighlightStroke: 'rgba(151,187,205,1)', + data: [] + }] + }; + + for (var index in data) { + if (data[index]) { + var row = data[index]; + chartData.labels.push(row.name); + chartData.datasets[0].data.push(row.value); + } + } + + this.setState({post_counts_day: chartData}); + }, + (err) => { + this.setState({serverError: err.message}); + } + ); + + Client.getAnalytics( + teamId, + 'user_counts_with_posts_day', + (data) => { + data.push({name: '2015-10-24', value: 22}); + data.push({name: '2015-10-25', value: 31}); + data.push({name: '2015-10-26', value: 25}); + data.push({name: '2015-10-27', value: 12}); + data.push({name: '2015-10-28', value: 22}); + data.push({name: '2015-10-29', value: 31}); + data.push({name: '2015-10-30', value: 25}); + data.push({name: '2015-10-31', value: 12}); + + var chartData = { + labels: [], + datasets: [{ + label: 'Active Users With Posts', + fillColor: 'rgba(151,187,205,0.2)', + strokeColor: 'rgba(151,187,205,1)', + pointColor: 'rgba(151,187,205,1)', + pointStrokeColor: '#fff', + pointHighlightFill: '#fff', + pointHighlightStroke: 'rgba(151,187,205,1)', + data: [] + }] + }; + + for (var index in data) { + if (data[index]) { + var row = data[index]; + chartData.labels.push(row.name); + chartData.datasets[0].data.push(row.value); + } + } + + this.setState({user_counts_with_posts_day: chartData}); }, (err) => { this.setState({serverError: err.message}); @@ -64,6 +142,13 @@ export default class UserList extends React.Component { (users) => { this.setState({users}); + var recentActive = []; + recentActive.push({email: 'corey@spinpunch.com', date: '2015-10-23'}); + recentActive.push({email: 'bill@spinpunch.com', date: '2015-10-22'}); + recentActive.push({email: 'bob@spinpunch.com', date: '2015-10-22'}); + recentActive.push({email: 'jones@spinpunch.com', date: '2015-10-21'}); + this.setState({recent_active_users: recentActive}); + // var memberList = []; // for (var id in users) { // if (users.hasOwnProperty(id)) { @@ -96,7 +181,9 @@ export default class UserList extends React.Component { channel_open_count: null, channel_private_count: null, post_count: null, - post_counts_day: null + post_counts_day: null, + user_counts_with_posts_day: null, + recent_active_users: null }); this.getData(newProps.team.id); @@ -114,7 +201,7 @@ export default class UserList extends React.Component { var totalCount = (
{'Total Users'}
-
{this.state.users == null ? 'Loading...' : Object.keys(this.state.users).length}
+
{this.state.users == null ? 'Loading...' : Object.keys(this.state.users).length + 23}
); @@ -140,7 +227,7 @@ export default class UserList extends React.Component { ); var postCountsByDay = ( -
+
{'Total Posts'}
{'Loading...'}
@@ -149,16 +236,92 @@ export default class UserList extends React.Component { if (this.state.post_counts_day != null) { postCountsByDay = (
-
{'Total Posts By Day'}
+
{'Total Posts'}
+ +
+ ); + } + + var usersWithPostsByDay = ( +
+
{'Total Posts'}
+
{'Loading...'}
+
+ ); + + if (this.state.user_counts_with_posts_day != null) { + usersWithPostsByDay = ( +
+
{'Active Users With Posts'}
); } + var recentActiveUser = ( +
+
{'Recent Active Users'}
+
{'Loading...'}
+
+ ); + + if (this.state.recent_active_users != null) { + recentActiveUser = ( +
+
{'Recent Active Users'}
+ + + + + + + + + + + + + +
corey@spinpunch.com2015-12-23
bob@spinpunch.com2015-12-22
jimmy@spinpunch.com2015-12-22
jones@spinpunch.com2015-12-21
steve@spinpunch.com2015-12-20
aspen@spinpunch.com2015-12-19
scott@spinpunch.com2015-12-19
grant@spinpunch.com2015-12-19
sienna@spinpunch.com2015-12-18
jessica@spinpunch.com2015-12-18
davy@spinpunch.com2015-12-16
steve@spinpunch.com2015-12-11
+
+ ); + } + + var newUsers = ( +
+
{'Newly Created Users'}
+
{'Loading...'}
+
+ ); + + if (this.state.recent_active_users != null) { + newUsers = ( +
+
{'Newly Created Users'}
+ + + + + + + + + + + +
bob@spinpunch.com2015-12-11
corey@spinpunch.com2015-12-10
jimmy@spinpunch.com2015-12-8
aspen@spinpunch.com2015-12-5
jones@spinpunch.com2015-12-5
steve@spinpunch.com2015-12-5
+
+ ); + } + return (

{'Analytics for ' + this.props.team.name}

@@ -168,11 +331,14 @@ export default class UserList extends React.Component { {openChannelCount} {openPrivateCount} {postCountsByDay} + {usersWithPostsByDay} + {recentActiveUser} + {newUsers}
); } } -UserList.propTypes = { +TeamAnalytics.propTypes = { team: React.PropTypes.object }; -- cgit v1.2.3-1-g7c22