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
Этот коммит содержится в:
коммит произвёл
Corey Hulen
родитель
9a9729f22f
Коммит
689cac535e
@@ -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();
|
||||
|
||||
Ссылка в новой задаче
Block a user