From ae5d1898037be4f59bf6517ad76b13cc16f595ce Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Thu, 22 Oct 2015 18:04:06 -0700 Subject: Adding analytics tab --- .../components/admin_console/admin_controller.jsx | 5 + .../components/admin_console/admin_sidebar.jsx | 11 +- .../components/admin_console/team_analytics.jsx | 144 +++++++++++++++++++++ web/react/utils/client.jsx | 14 ++ 4 files changed, 173 insertions(+), 1 deletion(-) create mode 100644 web/react/components/admin_console/team_analytics.jsx (limited to 'web/react') diff --git a/web/react/components/admin_console/admin_controller.jsx b/web/react/components/admin_console/admin_controller.jsx index f770d166c..d309ced2e 100644 --- a/web/react/components/admin_console/admin_controller.jsx +++ b/web/react/components/admin_console/admin_controller.jsx @@ -18,6 +18,7 @@ var SqlSettingsTab = require('./sql_settings.jsx'); var TeamSettingsTab = require('./team_settings.jsx'); var ServiceSettingsTab = require('./service_settings.jsx'); var TeamUsersTab = require('./team_users.jsx'); +var TeamAnalyticsTab = require('./team_analytics.jsx'); export default class AdminController extends React.Component { constructor(props) { @@ -149,6 +150,10 @@ export default class AdminController extends React.Component { if (this.state.teams) { tab = ; } + } else if (this.state.selected === 'team_analytics') { + if (this.state.teams) { + tab = ; + } } } diff --git a/web/react/components/admin_console/admin_sidebar.jsx b/web/react/components/admin_console/admin_sidebar.jsx index b0e01ff17..c950b4629 100644 --- a/web/react/components/admin_console/admin_sidebar.jsx +++ b/web/react/components/admin_console/admin_sidebar.jsx @@ -24,7 +24,7 @@ export default class AdminSidebar extends React.Component { handleClick(name, teamId, e) { e.preventDefault(); this.props.selectTab(name, teamId); - history.pushState({name: name, teamId: teamId}, null, `/admin_console/${name}/${teamId || ''}`); + history.pushState({name, teamId}, null, `/admin_console/${name}/${teamId || ''}`); } isSelected(name, teamId) { @@ -121,6 +121,15 @@ export default class AdminSidebar extends React.Component { {'- Users'} +
  • + + {'- Analytics'} + +
  • diff --git a/web/react/components/admin_console/team_analytics.jsx b/web/react/components/admin_console/team_analytics.jsx new file mode 100644 index 000000000..03123a3f0 --- /dev/null +++ b/web/react/components/admin_console/team_analytics.jsx @@ -0,0 +1,144 @@ +// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +var Client = require('../../utils/client.jsx'); +var LoadingScreen = require('../loading_screen.jsx'); + +export default class UserList extends React.Component { + constructor(props) { + super(props); + + this.getData = this.getData.bind(this); + + this.state = { + users: null, + serverError: null, + channel_open_count: null, + channel_private_count: null, + post_count: null + }; + } + + componentDidMount() { + this.getData(this.props.team.id); + } + + getData(teamId) { + Client.getAnalytics( + teamId, + 'standard', + (data) => { + for (var index in data) { + if (data[index].name === 'channel_open_count') { + this.setState({channel_open_count: data[index].value}); + } + + if (data[index].name === 'channel_private_count') { + this.setState({channel_private_count: data[index].value}); + } + + if (data[index].name === 'post_count') { + this.setState({post_count: data[index].value}); + } + } + }, + (err) => { + this.setState({serverError: err.message}); + } + ); + + Client.getProfilesForTeam( + teamId, + (users) => { + this.setState({users}); + + // var memberList = []; + // for (var id in users) { + // if (users.hasOwnProperty(id)) { + // memberList.push(users[id]); + // } + // } + + // memberList.sort((a, b) => { + // if (a.username < b.username) { + // return -1; + // } + + // if (a.username > b.username) { + // return 1; + // } + + // return 0; + // }); + }, + (err) => { + this.setState({serverError: err.message}); + } + ); + } + + componentWillReceiveProps(newProps) { + this.setState({ + users: null, + serverError: null, + channel_open_count: null, + channel_private_count: null, + post_count: null + }); + + this.getData(newProps.team.id); + } + + componentWillUnmount() { + } + + render() { + var serverError = ''; + if (this.state.serverError) { + serverError =
    ; + } + + var totalCount = ( +
    +
    {'Total Users'}
    +
    {this.state.users == null ? 'Loading...' : Object.keys(this.state.users).length}
    +
    + ); + + var openChannelCount = ( +
    +
    {'Public Groups'}
    +
    {this.state.channel_open_count == null ? 'Loading...' : this.state.channel_open_count}
    +
    + ); + + var openPrivateCount = ( +
    +
    {'Private Groups'}
    +
    {this.state.channel_private_count == null ? 'Loading...' : this.state.channel_private_count}
    +
    + ); + + var postCount = ( +
    +
    {'Total Posts'}
    +
    {this.state.post_count == null ? 'Loading...' : this.state.post_count}
    +
    + ); + + return ( +
    +

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

    + {serverError} + {totalCount} + {postCount} + {openChannelCount} + {openPrivateCount} +
    + ); + } +} + +UserList.propTypes = { + team: React.PropTypes.object +}; diff --git a/web/react/utils/client.jsx b/web/react/utils/client.jsx index f92633439..eca4f4b3e 100644 --- a/web/react/utils/client.jsx +++ b/web/react/utils/client.jsx @@ -327,6 +327,20 @@ export function getConfig(success, error) { }); } +export function getAnalytics(teamId, name, success, error) { + $.ajax({ + url: '/api/v1/admin/analytics/' + teamId + '/' + name, + dataType: 'json', + contentType: 'application/json', + type: 'GET', + success, + error: function onError(xhr, status, err) { + var e = handleError('getAnalytics', xhr, status, err); + error(e); + } + }); +} + export function saveConfig(config, success, error) { $.ajax({ url: '/api/v1/admin/save_config', -- cgit v1.2.3-1-g7c22 From 009982cd4514c6f0950138b15367df559c8f4dd2 Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Thu, 22 Oct 2015 20:48:57 -0700 Subject: Adding post counts by days --- .../components/admin_console/team_analytics.jsx | 40 ++++++++++++++++++++-- 1 file changed, 37 insertions(+), 3 deletions(-) (limited to 'web/react') diff --git a/web/react/components/admin_console/team_analytics.jsx b/web/react/components/admin_console/team_analytics.jsx index 03123a3f0..9d452f95e 100644 --- a/web/react/components/admin_console/team_analytics.jsx +++ b/web/react/components/admin_console/team_analytics.jsx @@ -2,7 +2,6 @@ // See License.txt for license information. var Client = require('../../utils/client.jsx'); -var LoadingScreen = require('../loading_screen.jsx'); export default class UserList extends React.Component { constructor(props) { @@ -15,7 +14,8 @@ export default class UserList extends React.Component { serverError: null, channel_open_count: null, channel_private_count: null, - post_count: null + post_count: null, + post_counts_day: null }; } @@ -47,6 +47,18 @@ export default class UserList extends React.Component { } ); + Client.getAnalytics( + teamId, + 'post_counts_day', + (data) => { + console.log(data); + this.setState({post_counts_day: data}); + }, + (err) => { + this.setState({serverError: err.message}); + } + ); + Client.getProfilesForTeam( teamId, (users) => { @@ -83,7 +95,8 @@ export default class UserList extends React.Component { serverError: null, channel_open_count: null, channel_private_count: null, - post_count: null + post_count: null, + post_counts_day: null }); this.getData(newProps.team.id); @@ -126,6 +139,26 @@ export default class UserList extends React.Component { ); + var postCountsByDay = ( +
    +
    {'Total Posts'}
    +
    {'Loading...'}
    +
    + ); + + if (this.state.post_counts_day != null) { + postCountsByDay = ( +
    +
    {'Total Posts By Day'}
    + +
    + ); + } + return (

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

    @@ -134,6 +167,7 @@ export default class UserList extends React.Component { {postCount} {openChannelCount} {openPrivateCount} + {postCountsByDay}
    ); } -- cgit v1.2.3-1-g7c22 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 From fc3141156459c0dcd57fed9c6d9756212340ec91 Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Mon, 26 Oct 2015 09:55:24 -0700 Subject: PLT-25 adding stats to admin console --- .../components/admin_console/admin_sidebar.jsx | 2 +- .../components/admin_console/team_analytics.jsx | 143 +++++++++++---------- 2 files changed, 77 insertions(+), 68 deletions(-) (limited to 'web/react') diff --git a/web/react/components/admin_console/admin_sidebar.jsx b/web/react/components/admin_console/admin_sidebar.jsx index c950b4629..f2fb1c96d 100644 --- a/web/react/components/admin_console/admin_sidebar.jsx +++ b/web/react/components/admin_console/admin_sidebar.jsx @@ -127,7 +127,7 @@ export default class AdminSidebar extends React.Component { className={this.isSelected('team_analytics', team.id)} onClick={this.handleClick.bind(this, 'team_analytics', team.id)} > - {'- Analytics'} + {'- Statistics'} diff --git a/web/react/components/admin_console/team_analytics.jsx b/web/react/components/admin_console/team_analytics.jsx index 8a6723806..dd8812ad0 100644 --- a/web/react/components/admin_console/team_analytics.jsx +++ b/web/react/components/admin_console/team_analytics.jsx @@ -2,6 +2,7 @@ // See License.txt for license information. var Client = require('../../utils/client.jsx'); +var Utils = require('../../utils/utils.jsx'); var LineChart = require('./line_chart.jsx'); export default class TeamAnalytics extends React.Component { @@ -18,7 +19,8 @@ export default class TeamAnalytics extends React.Component { post_count: null, post_counts_day: null, user_counts_with_posts_day: null, - recent_active_users: null + recent_active_users: null, + newly_created_users: null }; } @@ -34,17 +36,14 @@ export default class TeamAnalytics 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}); } } }, @@ -57,15 +56,6 @@ export default class TeamAnalytics extends React.Component { teamId, '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: [{ @@ -99,15 +89,6 @@ export default class TeamAnalytics extends React.Component { 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: [{ @@ -142,31 +123,56 @@ export default class TeamAnalytics extends React.Component { (users) => { this.setState({users}); + var usersList = []; + for (var id in users) { + if (users.hasOwnProperty(id)) { + usersList.push(users[id]); + } + } + + usersList.sort((a, b) => { + if (a.last_activity_at < b.last_activity_at) { + return 1; + } + + if (a.last_activity_at > b.last_activity_at) { + return -1; + } + + return 0; + }); + 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'}); + for (let i = 0; i < usersList.length; i++) { + recentActive.push(usersList[i]); + if (i > 19) { + break; + } + } + this.setState({recent_active_users: recentActive}); - // var memberList = []; - // for (var id in users) { - // if (users.hasOwnProperty(id)) { - // memberList.push(users[id]); - // } - // } + usersList.sort((a, b) => { + if (a.create_at < b.create_at) { + return 1; + } - // memberList.sort((a, b) => { - // if (a.username < b.username) { - // return -1; - // } + if (a.create_at > b.create_at) { + return -1; + } - // if (a.username > b.username) { - // return 1; - // } + return 0; + }); - // return 0; - // }); + var newlyCreated = []; + for (let i = 0; i < usersList.length; i++) { + newlyCreated.push(usersList[i]); + if (i > 19) { + break; + } + } + + this.setState({newly_created_users: newlyCreated}); }, (err) => { this.setState({serverError: err.message}); @@ -183,7 +189,8 @@ export default class TeamAnalytics extends React.Component { post_count: null, post_counts_day: null, user_counts_with_posts_day: null, - recent_active_users: null + recent_active_users: null, + newly_created_users: null }); this.getData(newProps.team.id); @@ -201,7 +208,7 @@ export default class TeamAnalytics extends React.Component { var totalCount = (
    {'Total Users'}
    -
    {this.state.users == null ? 'Loading...' : Object.keys(this.state.users).length + 23}
    +
    {this.state.users == null ? 'Loading...' : Object.keys(this.state.users).length}
    ); @@ -278,18 +285,18 @@ export default class TeamAnalytics extends React.Component {
    {'Recent Active Users'}
    - - - - - - - - - - - - + + { + this.state.recent_active_users.map((user) => { + return ( + + + + + ); + }) + } +
    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
    {user.email}{Utils.displayDateTime(user.last_activity_at)}
    ); @@ -302,21 +309,23 @@ export default class TeamAnalytics extends React.Component {
    ); - if (this.state.recent_active_users != null) { + if (this.state.newly_created_users != null) { newUsers = (
    {'Newly Created Users'}
    - - - - - - - - - - + + { + this.state.newly_created_users.map((user) => { + return ( + + + + + ); + }) + } +
    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
    {user.email}{Utils.displayDateTime(user.create_at)}
    ); @@ -324,7 +333,7 @@ export default class TeamAnalytics extends React.Component { return (
    -

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

    +

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

    {serverError} {totalCount} {postCount} -- cgit v1.2.3-1-g7c22 From bf555fae14db647d0f1711326126bf94194a0151 Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Mon, 26 Oct 2015 15:16:14 -0400 Subject: Refactoring post_store into post_store and search_store --- web/react/components/channel_header.jsx | 8 +- web/react/components/mention_list.jsx | 6 +- web/react/components/search_bar.jsx | 16 +-- web/react/components/search_results.jsx | 10 +- web/react/components/search_results_item.jsx | 4 +- web/react/components/sidebar_right.jsx | 7 +- web/react/components/textbox.jsx | 6 +- web/react/stores/post_store.jsx | 126 +++------------------- web/react/stores/search_store.jsx | 153 +++++++++++++++++++++++++++ 9 files changed, 197 insertions(+), 139 deletions(-) create mode 100644 web/react/stores/search_store.jsx (limited to 'web/react') diff --git a/web/react/components/channel_header.jsx b/web/react/components/channel_header.jsx index 1b709336f..d66777cc6 100644 --- a/web/react/components/channel_header.jsx +++ b/web/react/components/channel_header.jsx @@ -3,7 +3,7 @@ const ChannelStore = require('../stores/channel_store.jsx'); const UserStore = require('../stores/user_store.jsx'); -const PostStore = require('../stores/post_store.jsx'); +const SearchStore = require('../stores/search_store.jsx'); const NavbarSearchBox = require('./search_bar.jsx'); const AsyncClient = require('../utils/async_client.jsx'); const Client = require('../utils/client.jsx'); @@ -35,19 +35,19 @@ export default class ChannelHeader extends React.Component { memberChannel: ChannelStore.getCurrentMember(), memberTeam: UserStore.getCurrentUser(), users: ChannelStore.getCurrentExtraInfo().members, - searchVisible: PostStore.getSearchResults() !== null + searchVisible: SearchStore.getSearchResults() !== null }; } componentDidMount() { ChannelStore.addChangeListener(this.onListenerChange); ChannelStore.addExtraInfoChangeListener(this.onListenerChange); - PostStore.addSearchChangeListener(this.onListenerChange); + SearchStore.addSearchChangeListener(this.onListenerChange); UserStore.addChangeListener(this.onListenerChange); } componentWillUnmount() { ChannelStore.removeChangeListener(this.onListenerChange); ChannelStore.removeExtraInfoChangeListener(this.onListenerChange); - PostStore.removeSearchChangeListener(this.onListenerChange); + SearchStore.removeSearchChangeListener(this.onListenerChange); UserStore.addChangeListener(this.onListenerChange); } onListenerChange() { diff --git a/web/react/components/mention_list.jsx b/web/react/components/mention_list.jsx index 8c1da942d..cb7f71f15 100644 --- a/web/react/components/mention_list.jsx +++ b/web/react/components/mention_list.jsx @@ -2,7 +2,7 @@ // See License.txt for license information. var UserStore = require('../stores/user_store.jsx'); -var PostStore = require('../stores/post_store.jsx'); +var SearchStore = require('../stores/search_store.jsx'); var AppDispatcher = require('../dispatcher/app_dispatcher.jsx'); var Mention = require('./mention.jsx'); @@ -66,7 +66,7 @@ export default class MentionList extends React.Component { } } componentDidMount() { - PostStore.addMentionDataChangeListener(this.onListenerChange); + SearchStore.addMentionDataChangeListener(this.onListenerChange); $('.post-right__scroll').scroll(this.onScroll); @@ -74,7 +74,7 @@ export default class MentionList extends React.Component { $(document).click(this.onClick); } componentWillUnmount() { - PostStore.removeMentionDataChangeListener(this.onListenerChange); + SearchStore.removeMentionDataChangeListener(this.onListenerChange); $('body').off('keydown.mentionlist', '#' + this.props.id); } diff --git a/web/react/components/search_bar.jsx b/web/react/components/search_bar.jsx index 0da43e8cd..83c10494a 100644 --- a/web/react/components/search_bar.jsx +++ b/web/react/components/search_bar.jsx @@ -3,7 +3,7 @@ var client = require('../utils/client.jsx'); var AsyncClient = require('../utils/async_client.jsx'); -var PostStore = require('../stores/post_store.jsx'); +var SearchStore = require('../stores/search_store.jsx'); var AppDispatcher = require('../dispatcher/app_dispatcher.jsx'); var utils = require('../utils/utils.jsx'); var Constants = require('../utils/constants.jsx'); @@ -30,17 +30,17 @@ export default class SearchBar extends React.Component { this.state = state; } getSearchTermStateFromStores() { - var term = PostStore.getSearchTerm() || ''; + var term = SearchStore.getSearchTerm() || ''; return { searchTerm: term }; } componentDidMount() { - PostStore.addSearchTermChangeListener(this.onListenerChange); + SearchStore.addSearchTermChangeListener(this.onListenerChange); this.mounted = true; } componentWillUnmount() { - PostStore.removeSearchTermChangeListener(this.onListenerChange); + SearchStore.removeSearchTermChangeListener(this.onListenerChange); this.mounted = false; } onListenerChange(doSearch, isMentionSearch) { @@ -84,8 +84,8 @@ export default class SearchBar extends React.Component { } handleUserInput(e) { var term = e.target.value; - PostStore.storeSearchTerm(term); - PostStore.emitSearchTermChange(false); + SearchStore.storeSearchTerm(term); + SearchStore.emitSearchTermChange(false); this.setState({searchTerm: term}); this.refs.autocomplete.handleInputChange(e.target, term); @@ -150,8 +150,8 @@ export default class SearchBar extends React.Component { textbox.value = text; utils.setCaretPosition(textbox, preText.length + word.length); - PostStore.storeSearchTerm(text); - PostStore.emitSearchTermChange(false); + SearchStore.storeSearchTerm(text); + SearchStore.emitSearchTermChange(false); this.setState({searchTerm: text}); } diff --git a/web/react/components/search_results.jsx b/web/react/components/search_results.jsx index 30e15d0ad..ce19c48f0 100644 --- a/web/react/components/search_results.jsx +++ b/web/react/components/search_results.jsx @@ -1,7 +1,7 @@ // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -var PostStore = require('../stores/post_store.jsx'); +var SearchStore = require('../stores/search_store.jsx'); var UserStore = require('../stores/user_store.jsx'); var SearchBox = require('./search_bar.jsx'); var Utils = require('../utils/utils.jsx'); @@ -9,7 +9,7 @@ var SearchResultsHeader = require('./search_results_header.jsx'); var SearchResultsItem = require('./search_results_item.jsx'); function getStateFromStores() { - return {results: PostStore.getSearchResults()}; + return {results: SearchStore.getSearchResults()}; } export default class SearchResults extends React.Component { @@ -30,7 +30,7 @@ export default class SearchResults extends React.Component { componentDidMount() { this.mounted = true; - PostStore.addSearchChangeListener(this.onChange); + SearchStore.addSearchChangeListener(this.onChange); this.resize(); window.addEventListener('resize', this.handleResize); } @@ -40,7 +40,7 @@ export default class SearchResults extends React.Component { } componentWillUnmount() { - PostStore.removeSearchChangeListener(this.onChange); + SearchStore.removeSearchChangeListener(this.onChange); this.mounted = false; window.removeEventListener('resize', this.handleResize); } @@ -78,7 +78,7 @@ export default class SearchResults extends React.Component { searchForm = ; } var noResults = (!results || !results.order || !results.order.length); - var searchTerm = PostStore.getSearchTerm(); + var searchTerm = SearchStore.getSearchTerm(); var ctls = null; diff --git a/web/react/components/search_results_item.jsx b/web/react/components/search_results_item.jsx index d212e47a3..a8bd4db2c 100644 --- a/web/react/components/search_results_item.jsx +++ b/web/react/components/search_results_item.jsx @@ -1,7 +1,7 @@ // Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. // See License.txt for license information. -var PostStore = require('../stores/post_store.jsx'); +var SearchStore = require('../stores/search_store.jsx'); var ChannelStore = require('../stores/channel_store.jsx'); var UserStore = require('../stores/user_store.jsx'); var UserProfile = require('./user_profile.jsx'); @@ -32,7 +32,7 @@ export default class SearchResultsItem extends React.Component { AppDispatcher.handleServerAction({ type: ActionTypes.RECIEVED_POST_SELECTED, post_list: data, - from_search: PostStore.getSearchTerm() + from_search: SearchStore.getSearchTerm() }); AppDispatcher.handleServerAction({ diff --git a/web/react/components/sidebar_right.jsx b/web/react/components/sidebar_right.jsx index 4e6985a86..51225cbbe 100644 --- a/web/react/components/sidebar_right.jsx +++ b/web/react/components/sidebar_right.jsx @@ -3,11 +3,12 @@ var SearchResults = require('./search_results.jsx'); var RhsThread = require('./rhs_thread.jsx'); +var SearchStore = require('../stores/search_store.jsx'); var PostStore = require('../stores/post_store.jsx'); var Utils = require('../utils/utils.jsx'); function getStateFromStores() { - return {search_visible: PostStore.getSearchResults() != null, post_right_visible: PostStore.getSelectedPost() != null, is_mention_search: PostStore.getIsMentionSearch()}; + return {search_visible: SearchStore.getSearchResults() != null, post_right_visible: PostStore.getSelectedPost() != null, is_mention_search: SearchStore.getIsMentionSearch()}; } export default class SidebarRight extends React.Component { @@ -22,11 +23,11 @@ export default class SidebarRight extends React.Component { this.state = getStateFromStores(); } componentDidMount() { - PostStore.addSearchChangeListener(this.onSearchChange); + SearchStore.addSearchChangeListener(this.onSearchChange); PostStore.addSelectedPostChangeListener(this.onSelectedChange); } componentWillUnmount() { - PostStore.removeSearchChangeListener(this.onSearchChange); + SearchStore.removeSearchChangeListener(this.onSearchChange); PostStore.removeSelectedPostChangeListener(this.onSelectedChange); } componentDidUpdate() { diff --git a/web/react/components/textbox.jsx b/web/react/components/textbox.jsx index 86bb42f62..707033d8f 100644 --- a/web/react/components/textbox.jsx +++ b/web/react/components/textbox.jsx @@ -2,7 +2,7 @@ // See License.txt for license information. const AppDispatcher = require('../dispatcher/app_dispatcher.jsx'); -const PostStore = require('../stores/post_store.jsx'); +const SearchStore = require('../stores/search_store.jsx'); const CommandList = require('./command_list.jsx'); const ErrorStore = require('../stores/error_store.jsx'); @@ -54,7 +54,7 @@ export default class Textbox extends React.Component { } componentDidMount() { - PostStore.addAddMentionListener(this.onListenerChange); + SearchStore.addAddMentionListener(this.onListenerChange); ErrorStore.addChangeListener(this.onRecievedError); this.resize(); @@ -62,7 +62,7 @@ export default class Textbox extends React.Component { } componentWillUnmount() { - PostStore.removeAddMentionListener(this.onListenerChange); + SearchStore.removeAddMentionListener(this.onListenerChange); ErrorStore.removeChangeListener(this.onRecievedError); } diff --git a/web/react/stores/post_store.jsx b/web/react/stores/post_store.jsx index 4a9314b31..a58fdde3a 100644 --- a/web/react/stores/post_store.jsx +++ b/web/react/stores/post_store.jsx @@ -12,11 +12,7 @@ var Constants = require('../utils/constants.jsx'); var ActionTypes = Constants.ActionTypes; var CHANGE_EVENT = 'change'; -var SEARCH_CHANGE_EVENT = 'search_change'; -var SEARCH_TERM_CHANGE_EVENT = 'search_term_change'; var SELECTED_POST_CHANGE_EVENT = 'selected_post_change'; -var MENTION_DATA_CHANGE_EVENT = 'mention_data_change'; -var ADD_MENTION_EVENT = 'add_mention'; var EDIT_POST_EVENT = 'edit_post'; class PostStoreClass extends EventEmitter { @@ -26,21 +22,15 @@ class PostStoreClass extends EventEmitter { this.emitChange = this.emitChange.bind(this); this.addChangeListener = this.addChangeListener.bind(this); this.removeChangeListener = this.removeChangeListener.bind(this); - this.emitSearchChange = this.emitSearchChange.bind(this); - this.addSearchChangeListener = this.addSearchChangeListener.bind(this); - this.removeSearchChangeListener = this.removeSearchChangeListener.bind(this); - this.emitSearchTermChange = this.emitSearchTermChange.bind(this); - this.addSearchTermChangeListener = this.addSearchTermChangeListener.bind(this); - this.removeSearchTermChangeListener = this.removeSearchTermChangeListener.bind(this); + this.emitSelectedPostChange = this.emitSelectedPostChange.bind(this); this.addSelectedPostChangeListener = this.addSelectedPostChangeListener.bind(this); this.removeSelectedPostChangeListener = this.removeSelectedPostChangeListener.bind(this); - this.emitMentionDataChange = this.emitMentionDataChange.bind(this); - this.addMentionDataChangeListener = this.addMentionDataChangeListener.bind(this); - this.removeMentionDataChangeListener = this.removeMentionDataChangeListener.bind(this); - this.emitAddMention = this.emitAddMention.bind(this); - this.addAddMentionListener = this.addAddMentionListener.bind(this); - this.removeAddMentionListener = this.removeAddMentionListener.bind(this); + + this.emitEditPost = this.emitEditPost.bind(this); + this.addEditPostListener = this.addEditPostListener.bind(this); + this.removeEditPostListener = this.removeEditPostListener.bind(this); + this.getCurrentPosts = this.getCurrentPosts.bind(this); this.storePosts = this.storePosts.bind(this); this.pStorePosts = this.pStorePosts.bind(this); @@ -59,13 +49,8 @@ class PostStoreClass extends EventEmitter { this.pRemovePendingPost = this.pRemovePendingPost.bind(this); this.clearPendingPosts = this.clearPendingPosts.bind(this); this.updatePendingPost = this.updatePendingPost.bind(this); - this.storeSearchResults = this.storeSearchResults.bind(this); - this.getSearchResults = this.getSearchResults.bind(this); - this.getIsMentionSearch = this.getIsMentionSearch.bind(this); this.storeSelectedPost = this.storeSelectedPost.bind(this); this.getSelectedPost = this.getSelectedPost.bind(this); - this.storeSearchTerm = this.storeSearchTerm.bind(this); - this.getSearchTerm = this.getSearchTerm.bind(this); this.getEmptyDraft = this.getEmptyDraft.bind(this); this.storeCurrentDraft = this.storeCurrentDraft.bind(this); this.getCurrentDraft = this.getCurrentDraft.bind(this); @@ -77,9 +62,6 @@ class PostStoreClass extends EventEmitter { this.clearCommentDraftUploads = this.clearCommentDraftUploads.bind(this); this.storeLatestUpdate = this.storeLatestUpdate.bind(this); this.getLatestUpdate = this.getLatestUpdate.bind(this); - this.emitEditPost = this.emitEditPost.bind(this); - this.addEditPostListener = this.addEditPostListener.bind(this); - this.removeEditPostListener = this.removeEditPostListener.bind(this); this.getCurrentUsersLatestPost = this.getCurrentUsersLatestPost.bind(this); } emitChange() { @@ -94,30 +76,6 @@ class PostStoreClass extends EventEmitter { this.removeListener(CHANGE_EVENT, callback); } - emitSearchChange() { - this.emit(SEARCH_CHANGE_EVENT); - } - - addSearchChangeListener(callback) { - this.on(SEARCH_CHANGE_EVENT, callback); - } - - removeSearchChangeListener(callback) { - this.removeListener(SEARCH_CHANGE_EVENT, callback); - } - - emitSearchTermChange(doSearch, isMentionSearch) { - this.emit(SEARCH_TERM_CHANGE_EVENT, doSearch, isMentionSearch); - } - - addSearchTermChangeListener(callback) { - this.on(SEARCH_TERM_CHANGE_EVENT, callback); - } - - removeSearchTermChangeListener(callback) { - this.removeListener(SEARCH_TERM_CHANGE_EVENT, callback); - } - emitSelectedPostChange(fromSearch) { this.emit(SELECTED_POST_CHANGE_EVENT, fromSearch); } @@ -130,30 +88,6 @@ class PostStoreClass extends EventEmitter { this.removeListener(SELECTED_POST_CHANGE_EVENT, callback); } - emitMentionDataChange(id, mentionText) { - this.emit(MENTION_DATA_CHANGE_EVENT, id, mentionText); - } - - addMentionDataChangeListener(callback) { - this.on(MENTION_DATA_CHANGE_EVENT, callback); - } - - removeMentionDataChangeListener(callback) { - this.removeListener(MENTION_DATA_CHANGE_EVENT, callback); - } - - emitAddMention(id, username) { - this.emit(ADD_MENTION_EVENT, id, username); - } - - addAddMentionListener(callback) { - this.on(ADD_MENTION_EVENT, callback); - } - - removeAddMentionListener(callback) { - this.removeListener(ADD_MENTION_EVENT, callback); - } - emitEditPost(post) { this.emit(EDIT_POST_EVENT, post); } @@ -181,9 +115,9 @@ class PostStoreClass extends EventEmitter { var postList = makePostListNonNull(this.getPosts(channelId)); - for (let pid in newPostList.posts) { + for (const pid in newPostList.posts) { if (newPostList.posts.hasOwnProperty(pid)) { - var np = newPostList.posts[pid]; + const np = newPostList.posts[pid]; if (np.delete_at === 0) { postList.posts[pid] = np; if (postList.order.indexOf(pid) === -1) { @@ -194,7 +128,7 @@ class PostStoreClass extends EventEmitter { delete postList.posts[pid]; } - var index = postList.order.indexOf(pid); + const index = postList.order.indexOf(pid); if (index !== -1) { postList.order.splice(index, 1); } @@ -202,7 +136,7 @@ class PostStoreClass extends EventEmitter { } } - postList.order.sort(function postSort(a, b) { + postList.order.sort((a, b) => { if (postList.posts[a].create_at > postList.posts[b].create_at) { return -1; } @@ -306,7 +240,7 @@ class PostStoreClass extends EventEmitter { var posts = postList.posts; // sort failed posts to the bottom - postList.order.sort(function postSort(a, b) { + postList.order.sort((a, b) => { if (posts[a].state === Constants.POST_LOADING && posts[b].state === Constants.POST_FAILED) { return 1; } @@ -371,7 +305,7 @@ class PostStoreClass extends EventEmitter { this.pStorePendingPosts(channelId, postList); } clearPendingPosts() { - BrowserStore.actionOnGlobalItemsWithPrefix('pending_posts_', function clearPending(key) { + BrowserStore.actionOnGlobalItemsWithPrefix('pending_posts_', (key) => { BrowserStore.removeItem(key); }); } @@ -387,28 +321,12 @@ class PostStoreClass extends EventEmitter { this.pStorePendingPosts(post.channel_id, postList); this.emitChange(); } - storeSearchResults(results, isMentionSearch) { - BrowserStore.setItem('search_results', results); - BrowserStore.setItem('is_mention_search', Boolean(isMentionSearch)); - } - getSearchResults() { - return BrowserStore.getItem('search_results'); - } - getIsMentionSearch() { - return BrowserStore.getItem('is_mention_search'); - } storeSelectedPost(postList) { BrowserStore.setItem('select_post', postList); } getSelectedPost() { return BrowserStore.getItem('select_post'); } - storeSearchTerm(term) { - BrowserStore.setItem('search_term', term); - } - getSearchTerm() { - return BrowserStore.getItem('search_term'); - } getEmptyDraft() { return {message: '', uploadsInProgress: [], previews: []}; } @@ -433,7 +351,7 @@ class PostStoreClass extends EventEmitter { return BrowserStore.getGlobalItem('comment_draft_' + parentPostId, this.getEmptyDraft()); } clearDraftUploads() { - BrowserStore.actionOnGlobalItemsWithPrefix('draft_', function clearUploads(key, value) { + BrowserStore.actionOnGlobalItemsWithPrefix('draft_', (key, value) => { if (value) { value.uploadsInProgress = []; BrowserStore.setItem(key, value); @@ -441,7 +359,7 @@ class PostStoreClass extends EventEmitter { }); } clearCommentDraftUploads() { - BrowserStore.actionOnGlobalItemsWithPrefix('comment_draft_', function clearUploads(key, value) { + BrowserStore.actionOnGlobalItemsWithPrefix('comment_draft_', (key, value) => { if (value) { value.uploadsInProgress = []; BrowserStore.setItem(key, value); @@ -458,7 +376,7 @@ class PostStoreClass extends EventEmitter { var PostStore = new PostStoreClass(); -PostStore.dispatchToken = AppDispatcher.register(function registry(payload) { +PostStore.dispatchToken = AppDispatcher.register((payload) => { var action = payload.action; switch (action.type) { @@ -469,24 +387,10 @@ PostStore.dispatchToken = AppDispatcher.register(function registry(payload) { PostStore.pStorePost(action.post); PostStore.emitChange(); break; - case ActionTypes.RECIEVED_SEARCH: - PostStore.storeSearchResults(action.results, action.is_mention_search); - PostStore.emitSearchChange(); - break; - case ActionTypes.RECIEVED_SEARCH_TERM: - PostStore.storeSearchTerm(action.term); - PostStore.emitSearchTermChange(action.do_search, action.is_mention_search); - break; case ActionTypes.RECIEVED_POST_SELECTED: PostStore.storeSelectedPost(action.post_list); PostStore.emitSelectedPostChange(action.from_search); break; - case ActionTypes.RECIEVED_MENTION_DATA: - PostStore.emitMentionDataChange(action.id, action.mention_text); - break; - case ActionTypes.RECIEVED_ADD_MENTION: - PostStore.emitAddMention(action.id, action.username); - break; case ActionTypes.RECIEVED_EDIT_POST: PostStore.emitEditPost(action); break; diff --git a/web/react/stores/search_store.jsx b/web/react/stores/search_store.jsx new file mode 100644 index 000000000..95f0ea845 --- /dev/null +++ b/web/react/stores/search_store.jsx @@ -0,0 +1,153 @@ +// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved. +// See License.txt for license information. + +var AppDispatcher = require('../dispatcher/app_dispatcher.jsx'); +var EventEmitter = require('events').EventEmitter; + +var BrowserStore = require('../stores/browser_store.jsx'); + +var Constants = require('../utils/constants.jsx'); +var ActionTypes = Constants.ActionTypes; + +var CHANGE_EVENT = 'change'; +var SEARCH_CHANGE_EVENT = 'search_change'; +var SEARCH_TERM_CHANGE_EVENT = 'search_term_change'; +var MENTION_DATA_CHANGE_EVENT = 'mention_data_change'; +var ADD_MENTION_EVENT = 'add_mention'; + +class SearchStoreClass extends EventEmitter { + constructor() { + super(); + + this.emitChange = this.emitChange.bind(this); + this.addChangeListener = this.addChangeListener.bind(this); + this.removeChangeListener = this.removeChangeListener.bind(this); + + this.emitSearchChange = this.emitSearchChange.bind(this); + this.addSearchChangeListener = this.addSearchChangeListener.bind(this); + this.removeSearchChangeListener = this.removeSearchChangeListener.bind(this); + + this.emitSearchTermChange = this.emitSearchTermChange.bind(this); + this.addSearchTermChangeListener = this.addSearchTermChangeListener.bind(this); + this.removeSearchTermChangeListener = this.removeSearchTermChangeListener.bind(this); + + this.emitMentionDataChange = this.emitMentionDataChange.bind(this); + this.addMentionDataChangeListener = this.addMentionDataChangeListener.bind(this); + this.removeMentionDataChangeListener = this.removeMentionDataChangeListener.bind(this); + + this.getSearchResults = this.getSearchResults.bind(this); + this.getIsMentionSearch = this.getIsMentionSearch.bind(this); + + this.storeSearchTerm = this.storeSearchTerm.bind(this); + this.getSearchTerm = this.getSearchTerm.bind(this); + + this.storeSearchResults = this.storeSearchResults.bind(this); + } + + emitChange() { + this.emit(CHANGE_EVENT); + } + + addChangeListener(callback) { + this.on(CHANGE_EVENT, callback); + } + + removeChangeListener(callback) { + this.removeListener(CHANGE_EVENT, callback); + } + + emitSearchChange() { + this.emit(SEARCH_CHANGE_EVENT); + } + + addSearchChangeListener(callback) { + this.on(SEARCH_CHANGE_EVENT, callback); + } + + removeSearchChangeListener(callback) { + this.removeListener(SEARCH_CHANGE_EVENT, callback); + } + + emitSearchTermChange(doSearch, isMentionSearch) { + this.emit(SEARCH_TERM_CHANGE_EVENT, doSearch, isMentionSearch); + } + + addSearchTermChangeListener(callback) { + this.on(SEARCH_TERM_CHANGE_EVENT, callback); + } + + removeSearchTermChangeListener(callback) { + this.removeListener(SEARCH_TERM_CHANGE_EVENT, callback); + } + + getSearchResults() { + return BrowserStore.getItem('search_results'); + } + + getIsMentionSearch() { + return BrowserStore.getItem('is_mention_search'); + } + + storeSearchTerm(term) { + BrowserStore.setItem('search_term', term); + } + + getSearchTerm() { + return BrowserStore.getItem('search_term'); + } + + emitMentionDataChange(id, mentionText) { + this.emit(MENTION_DATA_CHANGE_EVENT, id, mentionText); + } + + addMentionDataChangeListener(callback) { + this.on(MENTION_DATA_CHANGE_EVENT, callback); + } + + removeMentionDataChangeListener(callback) { + this.removeListener(MENTION_DATA_CHANGE_EVENT, callback); + } + + emitAddMention(id, username) { + this.emit(ADD_MENTION_EVENT, id, username); + } + + addAddMentionListener(callback) { + this.on(ADD_MENTION_EVENT, callback); + } + + removeAddMentionListener(callback) { + this.removeListener(ADD_MENTION_EVENT, callback); + } + + storeSearchResults(results, isMentionSearch) { + BrowserStore.setItem('search_results', results); + BrowserStore.setItem('is_mention_search', Boolean(isMentionSearch)); + } +} + +var SearchStore = new SearchStoreClass(); + +SearchStore.dispatchToken = AppDispatcher.register((payload) => { + var action = payload.action; + + switch (action.type) { + case ActionTypes.RECIEVED_SEARCH: + SearchStore.storeSearchResults(action.results, action.is_mention_search); + SearchStore.emitSearchChange(); + break; + case ActionTypes.RECIEVED_SEARCH_TERM: + SearchStore.storeSearchTerm(action.term); + SearchStore.emitSearchTermChange(action.do_search, action.is_mention_search); + break; + case ActionTypes.RECIEVED_MENTION_DATA: + SearchStore.emitMentionDataChange(action.id, action.mention_text); + break; + case ActionTypes.RECIEVED_ADD_MENTION: + SearchStore.emitAddMention(action.id, action.username); + break; + default: + } +}); + +export default SearchStore; -- cgit v1.2.3-1-g7c22 From 834e1a8b58496e721f086f04612658c4a22c8d7d Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Mon, 26 Oct 2015 22:13:40 -0700 Subject: adding arrow notation --- web/react/utils/client.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'web/react') diff --git a/web/react/utils/client.jsx b/web/react/utils/client.jsx index fe5797769..bf117b3b3 100644 --- a/web/react/utils/client.jsx +++ b/web/react/utils/client.jsx @@ -335,7 +335,7 @@ export function getAnalytics(teamId, name, success, error) { contentType: 'application/json', type: 'GET', success, - error: function onError(xhr, status, err) { + error: (xhr, status, err) => { var e = handleError('getAnalytics', xhr, status, err); error(e); } -- cgit v1.2.3-1-g7c22 From c91f4f8ab12c07db0ddac1de5dfda12961cf95ba Mon Sep 17 00:00:00 2001 From: Florian Orben Date: Wed, 28 Oct 2015 01:19:15 +0100 Subject: Dont display '1 minute ago' timestamps for post posted < than 1 minute ago --- web/react/utils/utils.jsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'web/react') diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx index fadab27a7..3140a5d77 100644 --- a/web/react/utils/utils.jsx +++ b/web/react/utils/utils.jsx @@ -211,11 +211,15 @@ export function displayDateTime(ticks) { } interval = Math.floor(seconds / 60); - if (interval > 1) { + if (interval >= 2) { return interval + ' minutes ago'; } - return '1 minute ago'; + if (interval >= 1) { + return '1 minute ago'; + } + + return 'just now'; } export function displayCommentDateTime(ticks) { -- cgit v1.2.3-1-g7c22 From 36308f949d434675eca31b8eb1cd04c863273c93 Mon Sep 17 00:00:00 2001 From: =Corey Hulen Date: Tue, 27 Oct 2015 22:55:10 -0700 Subject: PLT-25 fixing issues with stats page --- web/react/components/admin_console/team_analytics.jsx | 4 ++++ web/react/components/admin_console/team_users.jsx | 10 ---------- 2 files changed, 4 insertions(+), 10 deletions(-) (limited to 'web/react') diff --git a/web/react/components/admin_console/team_analytics.jsx b/web/react/components/admin_console/team_analytics.jsx index dd8812ad0..a945a551c 100644 --- a/web/react/components/admin_console/team_analytics.jsx +++ b/web/react/components/admin_console/team_analytics.jsx @@ -56,6 +56,8 @@ export default class TeamAnalytics extends React.Component { teamId, 'post_counts_day', (data) => { + data.reverse(); + var chartData = { labels: [], datasets: [{ @@ -89,6 +91,8 @@ export default class TeamAnalytics extends React.Component { teamId, 'user_counts_with_posts_day', (data) => { + data.reverse(); + var chartData = { labels: [], datasets: [{ diff --git a/web/react/components/admin_console/team_users.jsx b/web/react/components/admin_console/team_users.jsx index ffb412159..b44aba56e 100644 --- a/web/react/components/admin_console/team_users.jsx +++ b/web/react/components/admin_console/team_users.jsx @@ -33,14 +33,6 @@ export default class UserList extends React.Component { this.getTeamProfiles(this.props.team.id); } - // this.setState({ - // teamId: this.state.teamId, - // users: this.state.users, - // serverError: this.state.serverError, - // showPasswordModal: this.state.showPasswordModal, - // user: this.state.user - // }); - getTeamProfiles(teamId) { Client.getProfilesForTeam( teamId, @@ -95,8 +87,6 @@ export default class UserList extends React.Component { } doPasswordResetDismiss() { - this.state.showPasswordModal = false; - this.state.user = null; this.setState({ teamId: this.state.teamId, users: this.state.users, -- cgit v1.2.3-1-g7c22