PLT-2713/PLT-6028 Added System Users list to System Console (#5882)

* PLT-2713 Added ability for admins to list users not in any team

* Updated style of unit test

* Split SearchableUserList to give better control over its properties

* Added users without any teams to the user store

* Added ManageUsers page

* Renamed ManageUsers to SystemUsers

* Added ability to search by user id in SystemUsers page

* Added SystemUsersDropdown

* Removed unnecessary injectIntl

* Created TeamUtils

* Reduced scope of system console heading CSS

* Added team filter to TeamAnalytics page

* Updated admin console sidebar

* Removed unnecessary TODO

* Removed unused reference to deleted modal

* Fixed system console sidebar not scrolling on first load

* Fixed TeamAnalytics page not rendering on first load

* Fixed chart.js throwing an error when switching between teams

* Changed TeamAnalytics header to show the team's display name

* Fixed appearance of TeamAnalytics and SystemUsers on small screen widths

* Fixed placement of 'No users found' message

* Fixed teams not appearing in SystemUsers on first load

* Updated user count text for SystemUsers

* Changed search by id fallback to trigger less often

* Fixed SystemUsers list items not updating when searching

* Fixed localization strings for SystemUsers page
Этот коммит содержится в:
Harrison Healey
2017-03-30 12:46:47 -04:00
коммит произвёл Corey Hulen
родитель 9a9729f22f
Коммит 689cac535e
74 изменённых файлов: 1445 добавлений и 1298 удалений

Просмотреть файл

@@ -4,8 +4,6 @@
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
import EventEmitter from 'events';
import BrowserStore from 'stores/browser_store.jsx';
import Constants from 'utils/constants.jsx';
const ActionTypes = Constants.ActionTypes;
@@ -138,18 +136,6 @@ class AdminStoreClass extends EventEmitter {
getTeam(id) {
return this.teams[id];
}
getSelectedTeams() {
const result = BrowserStore.getItem('selected_teams');
if (!result) {
return {};
}
return result;
}
saveSelectedTeams(teams) {
BrowserStore.setItem('selected_teams', teams);
}
}
var AdminStore = new AdminStoreClass();

Просмотреть файл

@@ -16,6 +16,7 @@ const UserStatuses = Constants.UserStatuses;
const CHANGE_EVENT_NOT_IN_CHANNEL = 'change_not_in_channel';
const CHANGE_EVENT_IN_CHANNEL = 'change_in_channel';
const CHANGE_EVENT_IN_TEAM = 'change_in_team';
const CHANGE_EVENT_WITHOUT_TEAM = 'change_without_team';
const CHANGE_EVENT = 'change';
const CHANGE_EVENT_SESSIONS = 'change_sessions';
const CHANGE_EVENT_AUDITS = 'change_audits';
@@ -50,6 +51,9 @@ class UserStoreClass extends EventEmitter {
this.not_in_channel_offset = {};
this.not_in_channel_count = {};
// Lists of sorted IDs for users without a team
this.profiles_without_team = {};
this.statuses = {};
this.sessions = {};
this.audits = [];
@@ -105,6 +109,18 @@ class UserStoreClass extends EventEmitter {
this.removeListener(CHANGE_EVENT_NOT_IN_CHANNEL, callback);
}
emitWithoutTeamChange() {
this.emit(CHANGE_EVENT_WITHOUT_TEAM);
}
addWithoutTeamChangeListener(callback) {
this.on(CHANGE_EVENT_WITHOUT_TEAM, callback);
}
removeWithoutTeamChangeListener(callback) {
this.removeListener(CHANGE_EVENT_WITHOUT_TEAM, callback);
}
emitSessionsChange() {
this.emit(CHANGE_EVENT_SESSIONS);
}
@@ -189,8 +205,33 @@ class UserStoreClass extends EventEmitter {
return null;
}
getProfileListForIds(userIds, skipCurrent = false, skipInactive = false) {
const profiles = [];
const currentId = this.getCurrentId();
for (let i = 0; i < userIds.length; i++) {
const profile = this.getProfile(userIds[i]);
if (!profile) {
continue;
}
if (skipCurrent && profile.id === currentId) {
continue;
}
if (skipInactive && profile.delete_at > 0) {
continue;
}
profiles.push(profile);
}
return profiles;
}
hasProfile(userId) {
return this.getProfile(userId) != null;
return this.getProfiles().hasOwnProperty(userId);
}
getProfileByUsername(username) {
@@ -248,7 +289,7 @@ class UserStoreClass extends EventEmitter {
return profiles;
}
getProfileList(skipCurrent) {
getProfileList(skipCurrent = false, allowInactive = false) {
const profiles = [];
const currentId = this.getCurrentId();
@@ -260,7 +301,7 @@ class UserStoreClass extends EventEmitter {
continue;
}
if (profile.delete_at === 0) {
if (allowInactive || profile.delete_at === 0) {
profiles.push(profile);
}
}
@@ -314,28 +355,8 @@ class UserStoreClass extends EventEmitter {
getProfileListInTeam(teamId = TeamStore.getCurrentId(), skipCurrent = false, skipInactive = false) {
const userIds = this.profiles_in_team[teamId] || [];
const profiles = [];
const currentId = this.getCurrentId();
for (let i = 0; i < userIds.length; i++) {
const profile = this.getProfile(userIds[i]);
if (!profile) {
continue;
}
if (skipCurrent && profile.id === currentId) {
continue;
}
if (skipInactive && profile.delete_at > 0) {
continue;
}
profiles.push(profile);
}
return profiles;
return this.getProfileListForIds(userIds, skipCurrent, skipInactive);
}
removeProfileFromTeam(teamId, userId) {
@@ -416,21 +437,8 @@ class UserStoreClass extends EventEmitter {
getProfileListInChannel(channelId = ChannelStore.getCurrentId(), skipCurrent = false) {
const userIds = this.profiles_in_channel[channelId] || [];
const currentId = this.getCurrentId();
const profiles = [];
for (let i = 0; i < userIds.length; i++) {
const profile = this.getProfile(userIds[i]);
if (profile) {
if (skipCurrent && profile.id === currentId) {
continue;
}
profiles.push(profile);
}
}
return profiles;
return this.getProfileListForIds(userIds, skipCurrent, false);
}
saveProfilesNotInChannel(channelId = ChannelStore.getCurrentId(), profiles) {
@@ -482,23 +490,43 @@ class UserStoreClass extends EventEmitter {
getProfileListNotInChannel(channelId = ChannelStore.getCurrentId(), skipInactive = false) {
const userIds = this.profiles_not_in_channel[channelId] || [];
const profiles = [];
for (let i = 0; i < userIds.length; i++) {
const profile = this.getProfile(userIds[i]);
return this.getProfileListForIds(userIds, false, skipInactive);
}
if (!profile) {
continue;
}
// Profiles without any teams
if (skipInactive && profile.delete_at > 0) {
continue;
}
profiles.push(profile);
saveProfilesWithoutTeam(profiles) {
const oldProfileList = this.profiles_without_team;
const oldProfileMap = {};
for (let i = 0; i < oldProfileList.length; i++) {
oldProfileMap[oldProfileList[i]] = this.getProfile(oldProfileList[i]);
}
return profiles;
const newProfileMap = Object.assign({}, oldProfileMap, profiles);
const newProfileList = Object.keys(newProfileMap);
newProfileList.sort((a, b) => {
const aProfile = newProfileMap[a];
const bProfile = newProfileMap[b];
if (aProfile.username < bProfile.username) {
return -1;
}
if (aProfile.username > bProfile.username) {
return 1;
}
return 0;
});
this.profiles_without_team = newProfileList;
this.saveProfiles(profiles);
}
getProfileListWithoutTeam(skipCurrent = false, skipInactive = false) {
const userIds = this.profiles_without_team || [];
return this.getProfileListForIds(userIds, skipCurrent, skipInactive);
}
// Other
@@ -680,6 +708,10 @@ UserStore.dispatchToken = AppDispatcher.register((payload) => {
}
UserStore.emitNotInChannelChange();
break;
case ActionTypes.RECEIVED_PROFILES_WITHOUT_TEAM:
UserStore.saveProfilesWithoutTeam(action.profiles);
UserStore.emitWithoutTeamChange();
break;
case ActionTypes.RECEIVED_PROFILE:
UserStore.saveProfile(action.profile);
UserStore.emitChange();