Skip to content
This repository has been archived by the owner on Mar 13, 2024. It is now read-only.

Commit

Permalink
Count inactive users towards total count in system console user list (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
jwilander committed May 30, 2018
1 parent b6d0311 commit ec3e625
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 63 deletions.
10 changes: 10 additions & 0 deletions actions/views/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,13 @@ export function setModalSearchTerm(term) {
return {data: true};
};
}

export function setSystemUsersSearch(term, team = '') {
return async (dispatch) => {
dispatch({
type: SearchTypes.SET_SYSTEM_USERS_SEARCH,
data: {term, team},
});
return {data: true};
};
}
27 changes: 27 additions & 0 deletions components/admin_console/system_users/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ import {getTeams, getTeamStats} from 'mattermost-redux/actions/teams';
import {getUser, getUserAccessToken} from 'mattermost-redux/actions/users';
import {getTeamsList} from 'mattermost-redux/selectors/entities/teams';
import {getConfig, getLicense} from 'mattermost-redux/selectors/entities/general';
import {Stats} from 'mattermost-redux/constants';

import {setSystemUsersSearch} from 'actions/views/search';
import {SearchUserTeamFilter} from 'utils/constants.jsx';

import SystemUsers from './system_users.jsx';

Expand All @@ -20,10 +24,32 @@ function mapStateToProps(state) {
const enableUserAccessTokens = config.EnableUserAccessTokens === 'true';
const experimentalEnableAuthenticationTransfer = config.ExperimentalEnableAuthenticationTransfer === 'true';

const search = state.views.search.systemUsersSearch;
let totalUsers = 0;
let searchTerm = '';
let teamId = '';
if (search) {
searchTerm = search.term || '';
teamId = search.team || '';

if (!teamId || teamId === SearchUserTeamFilter.ALL_USERS) {
const stats = state.entities.admin.analytics || {[Stats.TOTAL_USERS]: 0, [Stats.TOTAL_INACTIVE_USERS]: 0};
totalUsers = stats[Stats.TOTAL_USERS] + stats[Stats.TOTAL_INACTIVE_USERS];
} else if (teamId === SearchUserTeamFilter.NO_TEAM) {
totalUsers = 0;
} else {
const stats = state.entities.teams.stats[teamId] || {total_member_count: 0};
totalUsers = stats.total_member_count;
}
}

return {
teams: getTeamsList(state),
siteName,
mfaEnabled,
totalUsers,
searchTerm,
teamId,
enableUserAccessTokens,
experimentalEnableAuthenticationTransfer,
};
Expand All @@ -36,6 +62,7 @@ function mapDispatchToProps(dispatch) {
getTeamStats,
getUser,
getUserAccessToken,
setSystemUsersSearch,
}, dispatch),
};
}
Expand Down
89 changes: 26 additions & 63 deletions components/admin_console/system_users/system_users.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,12 @@ import {FormattedMessage} from 'react-intl';
import {getStandardAnalytics} from 'actions/admin_actions.jsx';
import {reloadIfServerVersionChanged} from 'actions/global_actions.jsx';
import {loadProfiles, loadProfilesAndTeamMembers, loadProfilesWithoutTeam, searchUsers} from 'actions/user_actions.jsx';
import AnalyticsStore from 'stores/analytics_store.jsx';
import TeamStore from 'stores/team_store.jsx';
import UserStore from 'stores/user_store.jsx';
import {Constants, StatTypes, UserSearchOptions} from 'utils/constants.jsx';
import {Constants, UserSearchOptions, SearchUserTeamFilter} from 'utils/constants.jsx';
import * as Utils from 'utils/utils.jsx';

import SystemUsersList from './list';

const ALL_USERS = '';
const NO_TEAM = 'no_team';

const USER_ID_LENGTH = 26;
const USERS_PER_PAGE = 50;

Expand Down Expand Up @@ -49,6 +44,9 @@ export default class SystemUsers extends React.Component {
* Whether or not the experimental authentication transfer is enabled.
*/
experimentalEnableAuthenticationTransfer: PropTypes.bool.isRequired,
totalUsers: PropTypes.number.isRequired,
searchTerm: PropTypes.string.isRequired,
teamId: PropTypes.string.isRequired,

actions: PropTypes.shape({

Expand All @@ -71,14 +69,13 @@ export default class SystemUsers extends React.Component {
* Function to get a user access token
*/
getUserAccessToken: PropTypes.func.isRequired,
setSystemUsersSearch: PropTypes.func.isRequired,
}).isRequired,
}

constructor(props) {
super(props);

this.updateTotalUsersFromStore = this.updateTotalUsersFromStore.bind(this);

this.loadDataForTeam = this.loadDataForTeam.bind(this);
this.loadComplete = this.loadComplete.bind(this);

Expand All @@ -93,64 +90,30 @@ export default class SystemUsers extends React.Component {
this.renderFilterRow = this.renderFilterRow.bind(this);

this.state = {
totalUsers: AnalyticsStore.getAllSystem()[StatTypes.TOTAL_USERS],

teamId: ALL_USERS,
term: '',
loading: true,
searching: false,
};
}

componentDidMount() {
AnalyticsStore.addChangeListener(this.updateTotalUsersFromStore);
TeamStore.addStatsChangeListener(this.updateTotalUsersFromStore);

this.loadDataForTeam(this.state.teamId);
this.loadDataForTeam(this.props.teamId);
this.props.actions.getTeams(0, 1000).then(reloadIfServerVersionChanged);
}

UNSAFE_componentWillUpdate(nextProps, nextState) { // eslint-disable-line camelcase
const nextTeamId = nextState.teamId;

if (this.state.teamId !== nextTeamId) {
this.updateTotalUsersFromStore(nextTeamId);

this.loadDataForTeam(nextTeamId);
}
}

componentWillUnmount() {
AnalyticsStore.removeChangeListener(this.updateTotalUsersFromStore);
TeamStore.removeStatsChangeListener(this.updateTotalUsersFromStore);
}

updateTotalUsersFromStore(teamId = this.state.teamId) {
if (teamId === ALL_USERS) {
this.setState({
totalUsers: AnalyticsStore.getAllSystem()[StatTypes.TOTAL_USERS],
});
} else if (teamId === NO_TEAM) {
this.setState({
totalUsers: 0,
});
} else {
this.setState({
totalUsers: TeamStore.getStats(teamId).total_member_count,
});
}
this.props.actions.setSystemUsersSearch('', '');
}

loadDataForTeam(teamId) {
if (this.state.term) {
this.search(this.state.term, teamId);
if (this.props.searchTerm) {
this.search(this.props.searchTerm, teamId);
return;
}

if (teamId === ALL_USERS) {
if (teamId === SearchUserTeamFilter.ALL_USERS) {
loadProfiles(0, Constants.PROFILE_CHUNK_SIZE, this.loadComplete);
getStandardAnalytics();
} else if (teamId === NO_TEAM) {
} else if (teamId === SearchUserTeamFilter.NO_TEAM) {
loadProfilesWithoutTeam(0, Constants.PROFILE_CHUNK_SIZE, this.loadComplete);
} else {
loadProfilesAndTeamMembers(0, Constants.PROFILE_CHUNK_SIZE, teamId, this.loadComplete);
Expand All @@ -163,26 +126,28 @@ export default class SystemUsers extends React.Component {
}

handleTeamChange(e) {
this.setState({teamId: e.target.value});
const teamId = e.target.value;
this.loadDataForTeam(teamId);
this.props.actions.setSystemUsersSearch(this.props.searchTerm, teamId);
}

handleTermChange(term) {
this.setState({term});
this.props.actions.setSystemUsersSearch(term, this.props.teamId);
}

nextPage(page) {
// Paging isn't supported while searching

if (this.state.teamId === ALL_USERS) {
if (this.props.teamId === SearchUserTeamFilter.ALL_USERS) {
loadProfiles(page + 1, USERS_PER_PAGE, this.loadComplete);
} else if (this.state.teamId === NO_TEAM) {
} else if (this.props.teamId === SearchUserTeamFilter.NO_TEAM) {
loadProfilesWithoutTeam(page + 1, USERS_PER_PAGE, this.loadComplete);
} else {
loadProfilesAndTeamMembers(page + 1, USERS_PER_PAGE, this.state.teamId, this.loadComplete);
loadProfilesAndTeamMembers(page + 1, USERS_PER_PAGE, this.props.teamId, this.loadComplete);
}
}

search(term, teamId = this.state.teamId) {
search(term, teamId = this.props.teamId) {
if (term === '') {
this.setState({
loading: false,
Expand All @@ -197,14 +162,13 @@ export default class SystemUsers extends React.Component {

doSearch(teamId, term, now = false) {
clearTimeout(this.searchTimeoutId);
this.term = term;

this.setState({loading: true});

const options = {
[UserSearchOptions.ALLOW_INACTIVE]: true,
};
if (teamId === NO_TEAM) {
if (teamId === SearchUserTeamFilter.NO_TEAM) {
options[UserSearchOptions.WITHOUT_TEAM] = true;
}

Expand Down Expand Up @@ -251,7 +215,6 @@ export default class SystemUsers extends React.Component {
const {data} = await this.props.actions.getUserAccessToken(id);

if (data) {
this.term = data.user_id;
this.setState({term: data.user_id});
this.getUserById(data.user_id);
return;
Expand Down Expand Up @@ -294,10 +257,10 @@ export default class SystemUsers extends React.Component {
<select
className='form-control system-users__team-filter'
onChange={this.handleTeamChange}
value={this.state.teamId}
value={this.props.teamId}
>
<option value={ALL_USERS}>{Utils.localizeMessage('admin.system_users.allUsers', 'All Users')}</option>
<option value={NO_TEAM}>{Utils.localizeMessage('admin.system_users.noTeams', 'No Teams')}</option>
<option value={SearchUserTeamFilter.ALL_USERS}>{Utils.localizeMessage('admin.system_users.allUsers', 'All Users')}</option>
<option value={SearchUserTeamFilter.NO_TEAM}>{Utils.localizeMessage('admin.system_users.noTeams', 'No Teams')}</option>
{teams}
</select>
</label>
Expand All @@ -324,10 +287,10 @@ export default class SystemUsers extends React.Component {
search={this.search}
nextPage={this.nextPage}
usersPerPage={USERS_PER_PAGE}
total={this.state.totalUsers}
total={this.props.totalUsers}
teams={this.props.teams}
teamId={this.state.teamId}
term={this.state.term}
teamId={this.props.teamId}
term={this.props.searchTerm}
onTermChange={this.handleTermChange}
mfaEnabled={this.props.mfaEnabled}
enableUserAccessTokens={this.props.enableUserAccessTokens}
Expand Down
11 changes: 11 additions & 0 deletions reducers/views/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,17 @@ function modalSearch(state = '', action) {
}
}

function systemUsersSearch(state = {}, action) {
switch (action.type) {
case SearchTypes.SET_SYSTEM_USERS_SEARCH: {
return action.data;
}
default:
return state;
}
}

export default combineReducers({
modalSearch,
systemUsersSearch,
});
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ exports[`components/admin_console/system_users should match default snapshot 1`]
teamId=""
teams={Array []}
term=""
total={0}
usersPerPage={50}
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,15 @@ describe('components/admin_console/system_users', () => {
mfaEnabled: false,
enableUserAccessTokens: false,
experimentalEnableAuthenticationTransfer: false,
searchTerm: '',
teamId: '',
totalUsers: 0,
actions: {
getTeams: jest.fn().mockImplementation(() => Promise.resolve()),
getTeamStats: jest.fn().mockImplementation(() => Promise.resolve()),
getUser: jest.fn().mockImplementation(() => Promise.resolve()),
getUserAccessToken: jest.fn().mockImplementation(() => Promise.resolve()),
setSystemUsersSearch: jest.fn().mockImplementation(() => Promise.resolve()),
},
};

Expand Down
6 changes: 6 additions & 0 deletions utils/constants.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -404,8 +404,14 @@ export const StatTypes = keyMirror({
MONTHLY_ACTIVE_USERS: null,
});

export const SearchUserTeamFilter = {
ALL_USERS: '',
NO_TEAM: 'no_team',
};

export const SearchTypes = keyMirror({
SET_MODAL_SEARCH: null,
SET_SYSTEM_USERS_SEARCH: null,
});

export const StorageTypes = keyMirror({
Expand Down

0 comments on commit ec3e625

Please sign in to comment.