Merging performance branch into master (#4268)
* improve performance on sendNotifications * Fix SQL queries * Remove get direct profiles, not needed anymore * Add raw data to error details if AppError fails to decode * men * Fix decode (#4052) * Fixing json decode * Adding unit test * Initial work for client scaling (#4051) * Begin adding paging to profiles API * Added more paging functionality * Finish hooking up admin console user lists * Add API for searching users and add searching to all user lists * Add lazy loading of profiles * Revert config.json * Fix unit tests and some style issues * Add GetProfilesFromList to Go driver and fix web unit test * Update etag for GetProfiles * Updating ui for filters and pagination (#4044) * Updating UI for pagination * Adjusting margins for filter row * Adjusting margin for specific modals * Adding relative padding to system console * Adjusting responsive view * Update client user tests * Minor fixes for direct messages modal (#4056) * Remove some unneeded initial load calls (#4057) * UX updates to user lists, added smart counts and bug fixes (#4059) * Improved getExplicitMentions and unit tests (#4064) * Refactor getting posts to lazy load profiles correctly (#4062) * Comment out SetActiveChannel test (#4066) * Profiler cpu, block, and memory profiler. (#4081) * Fix TestSetActiveChannel unit test (#4071) * Fixing build failure caused by dependancies updating (#4076) * Adding profiler * Fix admin_team_member_dropdown eslint errors * Bumping session cache size (#4077) * Bumping session cache size * Bumping status cache * Refactor how the client handles channel members to be large team friendly (#4106) * Refactor how the client handles channel members to be large team friendly * Change Id to ChannelId in ChannelStats model * Updated getChannelMember and getProfilesByIds routes to match proposal * Performance improvements (#4100) * Performance improvements * Fixing re-connect issue * Fixing error message * Some other minor perf tweaks * Some other minor perf tweaks * Fixing config file * Fixing buffer size * Fixing web socket send message * adding some error logging * fix getMe to be user required * Fix websocket event for new user * Fixing shutting down * Reverting web socket changes * Fixing logging lvl * Adding caching to GetMember * Adding some logging * Fixing caching * Fixing caching invalidate * Fixing direct message caching * Fixing caching * Fixing caching * Remove GetDirectProfiles from initial load * Adding logging and fixing websocket client * Adding back caching from bad merge. * Explicitly close go driver requests (#4162) * Refactored how the client handles team members to be more large team friendly (#4159) * Refactor getProfilesForDirectMessageList API into getAllProfiles API * Refactored how the client handles team members to be more large team friendly * Fix js error when receiving a notification * Fix JS error caused by current user being overwritten with sanitized version (#4165) * Adding error message to status failure (#4167) * Fix a few bugs caused by client scaling refactoring (#4170) * When there is no read replica, don't open a second set of connections to the master database (#4173) * Adding connection tacking to stats (#4174) * Reduce DB writes for statuses and other status related changes (#4175) * Fix bug preventing opening of DM channels from more modal (#4181) * Fixing socket timing error (#4183) * Fixing ping/pong handler * Fixing socket timing error * Commenting out status broadcasting * Removing user status changes * Removing user status changes * Removing user status changes * Removing user status changes * Adding DoPreComputeJson() * Performance improvements (#4194) * * Fix System Console Analytics queries * Add db.SetConnMaxLifetime to 15 minutes * Add "net/http/pprof" for profiling * Add FreeOSMemory() to manually release memory on reload config * Add flag to enable http profiler * Fix memory leak (#4197) * Fix memory leak * removed unneeded nil assignment * Fixing go routine leak (#4208) * Merge fixes * Merge fix * Refactored statuses to be queried by the client rather than broadcast by the server (#4212) * Refactored server code to reduce status broadcasts and to allow getting statuses by IDs * Refactor client code to periodically fetch statuses * Add store unit test for getting statuses by ids * Fix status unit test * Add getStatusesByIds REST API and move the client over to use that instead of the WebSocket * Adding multiple threads to websocket hub (#4230) * Adding multiple threads to websocket hub * Fixing unit tests * Fixing so websocket connections from the same user end up in the same… (#4240) * Fixing so websocket connections from the same user end up in the same list * Removing old comment * Refactor user autocomplete to query the server (#4239) * Add API for autocompleting users * Converted at mention autocomplete to query server * Converted user search autocomplete to query server * Switch autocomplete API naming to use term instead of username * Split autocomplete API into two, one for channels and for teams * Fix copy/paste error * Some final client scaling fixes (#4246) * Add lazy loading of profiles to integration pages * Add lazy loading of profiles to emoji page * Fix JS error when receiving post in select team menu and also clean up channel store
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
0512bd26ee
Коммит
365b8b465e
@@ -12,7 +12,7 @@ const NotificationPrefs = Constants.NotificationPrefs;
|
||||
const CHANGE_EVENT = 'change';
|
||||
const LEAVE_EVENT = 'leave';
|
||||
const MORE_CHANGE_EVENT = 'change';
|
||||
const EXTRA_INFO_EVENT = 'extra_info';
|
||||
const STATS_EVENT = 'stats';
|
||||
const LAST_VIEVED_EVENT = 'last_viewed';
|
||||
|
||||
class ChannelStoreClass extends EventEmitter {
|
||||
@@ -21,41 +21,13 @@ class ChannelStoreClass extends EventEmitter {
|
||||
|
||||
this.setMaxListeners(15);
|
||||
|
||||
this.emitChange = this.emitChange.bind(this);
|
||||
this.addChangeListener = this.addChangeListener.bind(this);
|
||||
this.removeChangeListener = this.removeChangeListener.bind(this);
|
||||
this.emitMoreChange = this.emitMoreChange.bind(this);
|
||||
this.addMoreChangeListener = this.addMoreChangeListener.bind(this);
|
||||
this.removeMoreChangeListener = this.removeMoreChangeListener.bind(this);
|
||||
this.emitExtraInfoChange = this.emitExtraInfoChange.bind(this);
|
||||
this.addExtraInfoChangeListener = this.addExtraInfoChangeListener.bind(this);
|
||||
this.removeExtraInfoChangeListener = this.removeExtraInfoChangeListener.bind(this);
|
||||
this.emitLeave = this.emitLeave.bind(this);
|
||||
this.addLeaveListener = this.addLeaveListener.bind(this);
|
||||
this.removeLeaveListener = this.removeLeaveListener.bind(this);
|
||||
this.emitLastViewed = this.emitLastViewed.bind(this);
|
||||
this.addLastViewedListener = this.addLastViewedListener.bind(this);
|
||||
this.removeLastViewedListener = this.removeLastViewedListener.bind(this);
|
||||
this.findFirstBy = this.findFirstBy.bind(this);
|
||||
this.get = this.get.bind(this);
|
||||
this.getMember = this.getMember.bind(this);
|
||||
this.getByName = this.getByName.bind(this);
|
||||
this.getByDisplayName = this.getByDisplayName.bind(this);
|
||||
this.setPostMode = this.setPostMode.bind(this);
|
||||
this.getPostMode = this.getPostMode.bind(this);
|
||||
this.setUnreadCount = this.setUnreadCount.bind(this);
|
||||
this.setUnreadCounts = this.setUnreadCounts.bind(this);
|
||||
this.getUnreadCount = this.getUnreadCount.bind(this);
|
||||
this.getUnreadCounts = this.getUnreadCounts.bind(this);
|
||||
this.getChannelNamesMap = this.getChannelNamesMap.bind(this);
|
||||
|
||||
this.currentId = null;
|
||||
this.postMode = this.POST_MODE_CHANNEL;
|
||||
this.channels = [];
|
||||
this.channelMembers = {};
|
||||
this.myChannelMembers = {};
|
||||
this.moreChannels = {};
|
||||
this.moreChannels.loading = true;
|
||||
this.extraInfos = {};
|
||||
this.stats = {};
|
||||
this.unreadCounts = {};
|
||||
}
|
||||
|
||||
@@ -91,16 +63,16 @@ class ChannelStoreClass extends EventEmitter {
|
||||
this.removeListener(MORE_CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
emitExtraInfoChange() {
|
||||
this.emit(EXTRA_INFO_EVENT);
|
||||
emitStatsChange() {
|
||||
this.emit(STATS_EVENT);
|
||||
}
|
||||
|
||||
addExtraInfoChangeListener(callback) {
|
||||
this.on(EXTRA_INFO_EVENT, callback);
|
||||
addStatsChangeListener(callback) {
|
||||
this.on(STATS_EVENT, callback);
|
||||
}
|
||||
|
||||
removeExtraInfoChangeListener(callback) {
|
||||
this.removeListener(EXTRA_INFO_EVENT, callback);
|
||||
removeStatsChangeListener(callback) {
|
||||
this.removeListener(STATS_EVENT, callback);
|
||||
}
|
||||
emitLeave(id) {
|
||||
this.emit(LEAVE_EVENT, id);
|
||||
@@ -148,8 +120,8 @@ class ChannelStoreClass extends EventEmitter {
|
||||
return this.findFirstBy('id', id);
|
||||
}
|
||||
|
||||
getMember(id) {
|
||||
return this.getAllMembers()[id];
|
||||
getMyMember(id) {
|
||||
return this.getMyMembers()[id];
|
||||
}
|
||||
|
||||
getByName(name) {
|
||||
@@ -168,10 +140,6 @@ class ChannelStoreClass extends EventEmitter {
|
||||
return this.getChannels();
|
||||
}
|
||||
|
||||
getAllMembers() {
|
||||
return this.getChannelMembers();
|
||||
}
|
||||
|
||||
getMoreAll() {
|
||||
return this.getMoreChannels();
|
||||
}
|
||||
@@ -181,7 +149,7 @@ class ChannelStoreClass extends EventEmitter {
|
||||
}
|
||||
|
||||
resetCounts(id) {
|
||||
const cm = this.channelMembers;
|
||||
const cm = this.myChannelMembers;
|
||||
for (var cmid in cm) {
|
||||
if (cm[cmid].channel_id === id) {
|
||||
var c = this.get(id);
|
||||
@@ -213,41 +181,34 @@ class ChannelStoreClass extends EventEmitter {
|
||||
var currentId = this.getCurrentId();
|
||||
|
||||
if (currentId) {
|
||||
return this.getAllMembers()[currentId];
|
||||
return this.getMyMembers()[currentId];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
setChannelMember(member) {
|
||||
var members = this.getChannelMembers();
|
||||
members[member.channel_id] = member;
|
||||
this.storeChannelMembers(members);
|
||||
this.emitChange();
|
||||
getCurrentStats() {
|
||||
return this.getStats(this.getCurrentId());
|
||||
}
|
||||
|
||||
getCurrentExtraInfo() {
|
||||
return this.getExtraInfo(this.getCurrentId());
|
||||
}
|
||||
|
||||
getExtraInfo(channelId) {
|
||||
var extra = null;
|
||||
getStats(channelId) {
|
||||
let stats;
|
||||
|
||||
if (channelId) {
|
||||
extra = this.getExtraInfos()[channelId];
|
||||
stats = this.stats[channelId];
|
||||
}
|
||||
|
||||
if (extra) {
|
||||
if (stats) {
|
||||
// create a defensive copy
|
||||
extra = JSON.parse(JSON.stringify(extra));
|
||||
stats = Object.assign({}, stats);
|
||||
} else {
|
||||
extra = {members: []};
|
||||
stats = {member_count: 0};
|
||||
}
|
||||
|
||||
return extra;
|
||||
return stats;
|
||||
}
|
||||
|
||||
pStoreChannel(channel) {
|
||||
storeChannel(channel) {
|
||||
var channels = this.getChannels();
|
||||
var found;
|
||||
|
||||
@@ -279,18 +240,18 @@ class ChannelStoreClass extends EventEmitter {
|
||||
return this.channels;
|
||||
}
|
||||
|
||||
pStoreChannelMember(channelMember) {
|
||||
var members = this.getChannelMembers();
|
||||
storeMyChannelMember(channelMember) {
|
||||
const members = Object.assign({}, this.getMyMembers());
|
||||
members[channelMember.channel_id] = channelMember;
|
||||
this.storeChannelMembers(members);
|
||||
this.storeMyChannelMembers(members);
|
||||
}
|
||||
|
||||
storeChannelMembers(channelMembers) {
|
||||
this.channelMembers = channelMembers;
|
||||
storeMyChannelMembers(channelMembers) {
|
||||
this.myChannelMembers = channelMembers;
|
||||
}
|
||||
|
||||
getChannelMembers() {
|
||||
return this.channelMembers;
|
||||
getMyMembers() {
|
||||
return this.myChannelMembers;
|
||||
}
|
||||
|
||||
storeMoreChannels(channels) {
|
||||
@@ -301,12 +262,8 @@ class ChannelStoreClass extends EventEmitter {
|
||||
return this.moreChannels;
|
||||
}
|
||||
|
||||
storeExtraInfos(extraInfos) {
|
||||
this.extraInfos = extraInfos;
|
||||
}
|
||||
|
||||
getExtraInfos() {
|
||||
return this.extraInfos;
|
||||
storeStats(stats) {
|
||||
this.stats = stats;
|
||||
}
|
||||
|
||||
isDefault(channel) {
|
||||
@@ -323,7 +280,7 @@ class ChannelStoreClass extends EventEmitter {
|
||||
|
||||
setUnreadCount(id) {
|
||||
const ch = this.get(id);
|
||||
const chMember = this.getMember(id);
|
||||
const chMember = this.getMyMember(id);
|
||||
|
||||
const chMentionCount = chMember.mention_count;
|
||||
let chUnreadCount = ch.total_msg_count - chMember.msg_count;
|
||||
@@ -351,7 +308,7 @@ class ChannelStoreClass extends EventEmitter {
|
||||
}
|
||||
|
||||
leaveChannel(id) {
|
||||
Reflect.deleteProperty(this.channelMembers, id);
|
||||
Reflect.deleteProperty(this.myChannelMembers, id);
|
||||
const element = this.channels.indexOf(id);
|
||||
if (element > -1) {
|
||||
this.channels.splice(element, 1);
|
||||
@@ -405,7 +362,7 @@ ChannelStore.dispatchToken = AppDispatcher.register((payload) => {
|
||||
|
||||
case ActionTypes.RECEIVED_CHANNELS:
|
||||
ChannelStore.storeChannels(action.channels);
|
||||
ChannelStore.storeChannelMembers(action.members);
|
||||
ChannelStore.storeMyChannelMembers(action.members);
|
||||
currentId = ChannelStore.getCurrentId();
|
||||
if (currentId && window.isActive) {
|
||||
ChannelStore.resetCounts(currentId);
|
||||
@@ -415,9 +372,9 @@ ChannelStore.dispatchToken = AppDispatcher.register((payload) => {
|
||||
break;
|
||||
|
||||
case ActionTypes.RECEIVED_CHANNEL:
|
||||
ChannelStore.pStoreChannel(action.channel);
|
||||
ChannelStore.storeChannel(action.channel);
|
||||
if (action.member) {
|
||||
ChannelStore.pStoreChannelMember(action.member);
|
||||
ChannelStore.storeMyChannelMember(action.member);
|
||||
}
|
||||
currentId = ChannelStore.getCurrentId();
|
||||
if (currentId && window.isActive) {
|
||||
@@ -432,11 +389,11 @@ ChannelStore.dispatchToken = AppDispatcher.register((payload) => {
|
||||
ChannelStore.emitMoreChange();
|
||||
break;
|
||||
|
||||
case ActionTypes.RECEIVED_CHANNEL_EXTRA_INFO:
|
||||
var extraInfos = ChannelStore.getExtraInfos();
|
||||
extraInfos[action.extra_info.id] = action.extra_info;
|
||||
ChannelStore.storeExtraInfos(extraInfos);
|
||||
ChannelStore.emitExtraInfoChange();
|
||||
case ActionTypes.RECEIVED_CHANNEL_STATS:
|
||||
var stats = Object.assign({}, ChannelStore.getStats());
|
||||
stats[action.stats.channel_id] = action.stats;
|
||||
ChannelStore.storeStats(stats);
|
||||
ChannelStore.emitStatsChange();
|
||||
break;
|
||||
|
||||
case ActionTypes.LEAVE_CHANNEL:
|
||||
|
||||
@@ -44,7 +44,7 @@ class NotificationStoreClass extends EventEmitter {
|
||||
|
||||
const channel = ChannelStore.get(post.channel_id);
|
||||
const user = UserStore.getCurrentUser();
|
||||
const member = ChannelStore.getMember(post.channel_id);
|
||||
const member = ChannelStore.getMyMember(post.channel_id);
|
||||
|
||||
let notifyLevel = member && member.notify_props ? member.notify_props.desktop : 'default';
|
||||
if (notifyLevel === 'default') {
|
||||
|
||||
@@ -178,15 +178,15 @@ class PostStoreClass extends EventEmitter {
|
||||
}
|
||||
|
||||
// Returns true if posts need to be fetched
|
||||
requestVisibilityIncrease(id, ammount) {
|
||||
requestVisibilityIncrease(id, amount) {
|
||||
const endVisible = this.postsInfo[id].endVisible;
|
||||
const postList = this.postsInfo[id].postList;
|
||||
if (this.getVisibilityAtTop(id)) {
|
||||
return false;
|
||||
}
|
||||
this.postsInfo[id].endVisible += ammount;
|
||||
this.postsInfo[id].endVisible += amount;
|
||||
this.emitChange();
|
||||
return endVisible + ammount > postList.order.length;
|
||||
return endVisible + amount > postList.order.length;
|
||||
}
|
||||
|
||||
getFocusedPostId() {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2015 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
|
||||
import AppDispatcher from 'dispatcher/app_dispatcher.jsx';
|
||||
import Constants from 'utils/constants.jsx';
|
||||
import EventEmitter from 'events';
|
||||
|
||||
@@ -222,7 +222,9 @@ class SuggestionStore extends EventEmitter {
|
||||
|
||||
switch (type) {
|
||||
case ActionTypes.SUGGESTION_PRETEXT_CHANGED:
|
||||
this.clearSuggestions(id);
|
||||
if (other.pretext === '') {
|
||||
this.clearSuggestions(id);
|
||||
}
|
||||
|
||||
this.setPretext(id, other.pretext);
|
||||
this.emitPretextChanged(id, other.pretext);
|
||||
@@ -231,6 +233,8 @@ class SuggestionStore extends EventEmitter {
|
||||
this.emitSuggestionsChanged(id);
|
||||
break;
|
||||
case ActionTypes.SUGGESTION_RECEIVED_SUGGESTIONS:
|
||||
this.clearSuggestions(id);
|
||||
|
||||
// ensure the matched pretext hasn't changed so that we don't receive suggestions for outdated pretext
|
||||
this.addSuggestions(id, other.terms, other.items, other.component, other.matchedPretext);
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import Constants from 'utils/constants.jsx';
|
||||
const ActionTypes = Constants.ActionTypes;
|
||||
|
||||
const CHANGE_EVENT = 'change';
|
||||
const STATS_EVENT = 'stats';
|
||||
|
||||
var Utils;
|
||||
|
||||
@@ -20,8 +21,10 @@ class TeamStoreClass extends EventEmitter {
|
||||
|
||||
clear() {
|
||||
this.teams = {};
|
||||
this.team_members = [];
|
||||
this.members_for_team = [];
|
||||
this.my_team_members = [];
|
||||
this.members_in_team = {};
|
||||
this.members_not_in_team = {};
|
||||
this.stats = {};
|
||||
this.teamListings = {};
|
||||
this.currentTeamId = '';
|
||||
}
|
||||
@@ -38,6 +41,18 @@ class TeamStoreClass extends EventEmitter {
|
||||
this.removeListener(CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
emitStatsChange() {
|
||||
this.emit(STATS_EVENT);
|
||||
}
|
||||
|
||||
addStatsChangeListener(callback) {
|
||||
this.on(STATS_EVENT, callback);
|
||||
}
|
||||
|
||||
removeStatsChangeListener(callback) {
|
||||
this.removeListener(STATS_EVENT, callback);
|
||||
}
|
||||
|
||||
get(id) {
|
||||
var c = this.getAll();
|
||||
return c[id];
|
||||
@@ -114,6 +129,27 @@ class TeamStoreClass extends EventEmitter {
|
||||
return origin + '/' + team.name;
|
||||
}
|
||||
|
||||
getCurrentStats() {
|
||||
return this.getStats(this.getCurrentId());
|
||||
}
|
||||
|
||||
getStats(teamId) {
|
||||
let stats;
|
||||
|
||||
if (teamId) {
|
||||
stats = this.stats[teamId];
|
||||
}
|
||||
|
||||
if (stats) {
|
||||
// create a defensive copy
|
||||
stats = Object.assign({}, stats);
|
||||
} else {
|
||||
stats = {member_count: 0};
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
saveTeam(team) {
|
||||
this.teams[team.id] = team;
|
||||
}
|
||||
@@ -127,44 +163,62 @@ class TeamStoreClass extends EventEmitter {
|
||||
this.currentTeamId = team.id;
|
||||
}
|
||||
|
||||
saveTeamMembers(members) {
|
||||
this.team_members = members;
|
||||
saveStats(teamId, stats) {
|
||||
this.stats[teamId] = stats;
|
||||
}
|
||||
|
||||
appendTeamMember(member) {
|
||||
this.team_members.push(member);
|
||||
saveMyTeamMembers(members) {
|
||||
this.my_team_members = members;
|
||||
}
|
||||
|
||||
removeTeamMember(teamId) {
|
||||
for (var index in this.team_members) {
|
||||
if (this.team_members.hasOwnProperty(index)) {
|
||||
if (this.team_members[index].team_id === teamId) {
|
||||
this.team_members.splice(index, 1);
|
||||
appendMyTeamMember(member) {
|
||||
this.my_team_members.push(member);
|
||||
}
|
||||
|
||||
removeMyTeamMember(teamId) {
|
||||
for (var index in this.my_team_members) {
|
||||
if (this.my_team_members.hasOwnProperty(index)) {
|
||||
if (this.my_team_members[index].team_id === teamId) {
|
||||
Reflect.deleteProperty(this.my_team_members, index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getTeamMembers() {
|
||||
return this.team_members;
|
||||
getMyTeamMembers() {
|
||||
return this.my_team_members;
|
||||
}
|
||||
|
||||
saveMembersForTeam(members) {
|
||||
this.members_for_team = members;
|
||||
saveMembersInTeam(teamId = this.getCurrentId(), members) {
|
||||
const oldMembers = this.members_in_team[teamId] || {};
|
||||
this.members_in_team[teamId] = Object.assign({}, oldMembers, members);
|
||||
}
|
||||
|
||||
getMembersForTeam() {
|
||||
return this.members_for_team;
|
||||
saveMembersNotInTeam(teamId = this.getCurrentId(), nonmembers) {
|
||||
this.members_not_in_team[teamId] = nonmembers;
|
||||
}
|
||||
|
||||
hasActiveMemberForTeam(userId) {
|
||||
for (var index in this.members_for_team) {
|
||||
if (this.members_for_team.hasOwnProperty(index)) {
|
||||
if (this.members_for_team[index].user_id === userId &&
|
||||
this.members_for_team[index].team_id === this.currentTeamId) {
|
||||
return this.members_for_team[index].delete_at === 0;
|
||||
}
|
||||
}
|
||||
removeMemberInTeam(teamId = this.getCurrentId(), userId) {
|
||||
if (this.members_in_team[teamId]) {
|
||||
Reflect.deleteProperty(this.members_in_team[teamId], userId);
|
||||
}
|
||||
}
|
||||
|
||||
getMembersInTeam(teamId = this.getCurrentId()) {
|
||||
return this.members_in_team[teamId] || {};
|
||||
}
|
||||
|
||||
hasActiveMemberInTeam(teamId = this.getCurrentId(), userId) {
|
||||
if (this.members_in_team[teamId] && this.members_in_team[teamId][userId]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
hasMemberNotInTeam(teamId = this.getCurrentId(), userId) {
|
||||
if (this.members_not_in_team[teamId] && this.members_not_in_team[teamId][userId]) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -187,7 +241,7 @@ class TeamStoreClass extends EventEmitter {
|
||||
Utils = require('utils/utils.jsx'); //eslint-disable-line global-require
|
||||
}
|
||||
|
||||
var teamMembers = this.getTeamMembers();
|
||||
var teamMembers = this.getMyTeamMembers();
|
||||
const teamMember = teamMembers.find((m) => m.user_id === userId && m.team_id === teamId);
|
||||
|
||||
if (teamMember) {
|
||||
@@ -210,25 +264,32 @@ TeamStore.dispatchToken = AppDispatcher.register((payload) => {
|
||||
break;
|
||||
case ActionTypes.CREATED_TEAM:
|
||||
TeamStore.saveTeam(action.team);
|
||||
TeamStore.appendTeamMember(action.member);
|
||||
TeamStore.appendMyTeamMember(action.member);
|
||||
TeamStore.emitChange();
|
||||
break;
|
||||
case ActionTypes.RECEIVED_ALL_TEAMS:
|
||||
TeamStore.saveTeams(action.teams);
|
||||
TeamStore.emitChange();
|
||||
break;
|
||||
case ActionTypes.RECEIVED_TEAM_MEMBERS:
|
||||
TeamStore.saveTeamMembers(action.team_members);
|
||||
case ActionTypes.RECEIVED_MY_TEAM_MEMBERS:
|
||||
TeamStore.saveMyTeamMembers(action.team_members);
|
||||
TeamStore.emitChange();
|
||||
break;
|
||||
case ActionTypes.RECEIVED_ALL_TEAM_LISTINGS:
|
||||
TeamStore.saveTeamListings(action.teams);
|
||||
TeamStore.emitChange();
|
||||
break;
|
||||
case ActionTypes.RECEIVED_MEMBERS_FOR_TEAM:
|
||||
TeamStore.saveMembersForTeam(action.team_members);
|
||||
case ActionTypes.RECEIVED_MEMBERS_IN_TEAM:
|
||||
TeamStore.saveMembersInTeam(action.team_id, action.team_members);
|
||||
if (action.non_team_members) {
|
||||
TeamStore.saveMembersNotInTeam(action.team_id, action.non_team_members);
|
||||
}
|
||||
TeamStore.emitChange();
|
||||
break;
|
||||
case ActionTypes.RECEIVED_TEAM_STATS:
|
||||
TeamStore.saveStats(action.team_id, action.stats);
|
||||
TeamStore.emitStatsChange();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
});
|
||||
|
||||
@@ -6,12 +6,16 @@ import EventEmitter from 'events';
|
||||
|
||||
import * as GlobalActions from 'actions/global_actions.jsx';
|
||||
import LocalizationStore from './localization_store.jsx';
|
||||
import ChannelStore from 'stores/channel_store.jsx';
|
||||
import TeamStore from 'stores/team_store.jsx';
|
||||
|
||||
import Constants from 'utils/constants.jsx';
|
||||
const ActionTypes = Constants.ActionTypes;
|
||||
const UserStatuses = Constants.UserStatuses;
|
||||
|
||||
const CHANGE_EVENT_DM_LIST = 'change_dm_list';
|
||||
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 = 'change';
|
||||
const CHANGE_EVENT_SESSIONS = 'change_sessions';
|
||||
const CHANGE_EVENT_AUDITS = 'change_audits';
|
||||
@@ -26,9 +30,26 @@ class UserStoreClass extends EventEmitter {
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.profiles_for_dm_list = {};
|
||||
// All the profiles, regardless of where they came from
|
||||
this.profiles = {};
|
||||
this.direct_profiles = {};
|
||||
this.paging_offset = 0;
|
||||
this.paging_count = 0;
|
||||
|
||||
// Lists of sorted IDs for users in a team
|
||||
this.profiles_in_team = {};
|
||||
this.in_team_offset = 0;
|
||||
this.in_team_count = 0;
|
||||
|
||||
// Lists of sorted IDs for users in a channel
|
||||
this.profiles_in_channel = {};
|
||||
this.in_channel_offset = {};
|
||||
this.in_channel_count = {};
|
||||
|
||||
// Lists of sorted IDs for users not in a channel
|
||||
this.profiles_not_in_channel = {};
|
||||
this.not_in_channel_offset = {};
|
||||
this.not_in_channel_count = {};
|
||||
|
||||
this.statuses = {};
|
||||
this.sessions = {};
|
||||
this.audits = {};
|
||||
@@ -48,16 +69,40 @@ class UserStoreClass extends EventEmitter {
|
||||
this.removeListener(CHANGE_EVENT, callback);
|
||||
}
|
||||
|
||||
emitDmListChange() {
|
||||
this.emit(CHANGE_EVENT_DM_LIST);
|
||||
emitInTeamChange() {
|
||||
this.emit(CHANGE_EVENT_IN_TEAM);
|
||||
}
|
||||
|
||||
addDmListChangeListener(callback) {
|
||||
this.on(CHANGE_EVENT_DM_LIST, callback);
|
||||
addInTeamChangeListener(callback) {
|
||||
this.on(CHANGE_EVENT_IN_TEAM, callback);
|
||||
}
|
||||
|
||||
removeDmListChangeListener(callback) {
|
||||
this.removeListener(CHANGE_EVENT_DM_LIST, callback);
|
||||
removeInTeamChangeListener(callback) {
|
||||
this.removeListener(CHANGE_EVENT_IN_TEAM, callback);
|
||||
}
|
||||
|
||||
emitInChannelChange() {
|
||||
this.emit(CHANGE_EVENT_IN_CHANNEL);
|
||||
}
|
||||
|
||||
addInChannelChangeListener(callback) {
|
||||
this.on(CHANGE_EVENT_IN_CHANNEL, callback);
|
||||
}
|
||||
|
||||
removeInChannelChangeListener(callback) {
|
||||
this.removeListener(CHANGE_EVENT_IN_CHANNEL, callback);
|
||||
}
|
||||
|
||||
emitNotInChannelChange() {
|
||||
this.emit(CHANGE_EVENT_NOT_IN_CHANNEL);
|
||||
}
|
||||
|
||||
addNotInChannelChangeListener(callback) {
|
||||
this.on(CHANGE_EVENT_NOT_IN_CHANNEL, callback);
|
||||
}
|
||||
|
||||
removeNotInChannelChangeListener(callback) {
|
||||
this.removeListener(CHANGE_EVENT_NOT_IN_CHANNEL, callback);
|
||||
}
|
||||
|
||||
emitSessionsChange() {
|
||||
@@ -96,6 +141,8 @@ class UserStoreClass extends EventEmitter {
|
||||
this.removeListener(CHANGE_EVENT_STATUSES, callback);
|
||||
}
|
||||
|
||||
// General
|
||||
|
||||
getCurrentUser() {
|
||||
return this.getProfiles()[this.currentUserId];
|
||||
}
|
||||
@@ -119,29 +166,30 @@ class UserStoreClass extends EventEmitter {
|
||||
return null;
|
||||
}
|
||||
|
||||
hasProfile(userId) {
|
||||
return this.getProfile(userId) != null;
|
||||
// System-Wide Profiles
|
||||
|
||||
saveProfiles(profiles) {
|
||||
const currentId = this.getCurrentId();
|
||||
if (profiles[currentId]) {
|
||||
Reflect.deleteProperty(profiles, currentId);
|
||||
}
|
||||
this.profiles = Object.assign({}, this.profiles, profiles);
|
||||
}
|
||||
|
||||
hasTeamProfile(userId) {
|
||||
return this.getProfiles()[userId];
|
||||
}
|
||||
|
||||
hasDirectProfile(userId) {
|
||||
return this.getDirectProfiles()[userId];
|
||||
getProfiles() {
|
||||
return this.profiles;
|
||||
}
|
||||
|
||||
getProfile(userId) {
|
||||
if (userId === this.getCurrentId()) {
|
||||
return this.getCurrentUser();
|
||||
if (this.profiles[userId]) {
|
||||
return Object.assign({}, this.profiles[userId]);
|
||||
}
|
||||
|
||||
const user = this.getProfiles()[userId];
|
||||
if (user) {
|
||||
return user;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.getDirectProfiles()[userId];
|
||||
hasProfile(userId) {
|
||||
return this.getProfile(userId) != null;
|
||||
}
|
||||
|
||||
getProfileByUsername(username) {
|
||||
@@ -162,22 +210,6 @@ class UserStoreClass extends EventEmitter {
|
||||
return profileUsernameMap;
|
||||
}
|
||||
|
||||
getDirectProfiles() {
|
||||
return this.direct_profiles;
|
||||
}
|
||||
|
||||
saveDirectProfile(profile) {
|
||||
this.direct_profiles[profile.id] = profile;
|
||||
}
|
||||
|
||||
saveDirectProfiles(profiles) {
|
||||
this.direct_profiles = profiles;
|
||||
}
|
||||
|
||||
getProfiles() {
|
||||
return this.profiles;
|
||||
}
|
||||
|
||||
getActiveOnlyProfiles(skipCurrent) {
|
||||
const active = {};
|
||||
const profiles = this.getProfiles();
|
||||
@@ -195,14 +227,54 @@ class UserStoreClass extends EventEmitter {
|
||||
getActiveOnlyProfileList() {
|
||||
const profileMap = this.getActiveOnlyProfiles();
|
||||
const profiles = [];
|
||||
const currentId = this.getCurrentId();
|
||||
|
||||
for (const id in profileMap) {
|
||||
if (profileMap.hasOwnProperty(id) && id !== currentId) {
|
||||
if (profileMap.hasOwnProperty(id)) {
|
||||
profiles.push(profileMap[id]);
|
||||
}
|
||||
}
|
||||
|
||||
profiles.sort((a, b) => {
|
||||
if (a.username < b.username) {
|
||||
return -1;
|
||||
}
|
||||
if (a.username > b.username) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
return profiles;
|
||||
}
|
||||
|
||||
getProfileList(skipCurrent) {
|
||||
const profiles = [];
|
||||
const currentId = this.getCurrentId();
|
||||
|
||||
for (const id in this.profiles) {
|
||||
if (this.profiles.hasOwnProperty(id)) {
|
||||
var profile = this.profiles[id];
|
||||
|
||||
if (skipCurrent && id === currentId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (profile.delete_at === 0) {
|
||||
profiles.push(profile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
profiles.sort((a, b) => {
|
||||
if (a.username < b.username) {
|
||||
return -1;
|
||||
}
|
||||
if (a.username > b.username) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
return profiles;
|
||||
}
|
||||
|
||||
@@ -210,44 +282,194 @@ class UserStoreClass extends EventEmitter {
|
||||
this.profiles[profile.id] = profile;
|
||||
}
|
||||
|
||||
saveProfiles(profiles) {
|
||||
const currentId = this.getCurrentId();
|
||||
const currentUser = this.profiles[currentId];
|
||||
if (currentUser) {
|
||||
if (currentId in this.profiles) {
|
||||
Reflect.deleteProperty(this.profiles, currentId);
|
||||
}
|
||||
// Team-Wide Profiles
|
||||
|
||||
this.profiles = profiles;
|
||||
this.profiles[currentId] = currentUser;
|
||||
} else {
|
||||
this.profiles = profiles;
|
||||
saveProfilesInTeam(teamId, profiles) {
|
||||
const oldProfileList = this.profiles_in_team[teamId] || [];
|
||||
const oldProfileMap = {};
|
||||
for (let i = 0; i < oldProfileList.length; i++) {
|
||||
oldProfileMap[oldProfileList[i]] = this.getProfile(oldProfileList[i]);
|
||||
}
|
||||
|
||||
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_in_team[teamId] = newProfileList;
|
||||
this.saveProfiles(profiles);
|
||||
}
|
||||
|
||||
getProfilesForDmList() {
|
||||
const currentId = this.getCurrentId();
|
||||
getProfileListInTeam(teamId = TeamStore.getCurrentId(), skipCurrent) {
|
||||
const userIds = this.profiles_in_team[teamId] || [];
|
||||
const profiles = [];
|
||||
const currentId = this.getCurrentId();
|
||||
|
||||
for (const id in this.profiles_for_dm_list) {
|
||||
if (this.profiles_for_dm_list.hasOwnProperty(id) && id !== currentId) {
|
||||
var profile = this.profiles_for_dm_list[id];
|
||||
for (let i = 0; i < userIds.length; i++) {
|
||||
const profile = this.getProfile(userIds[i]);
|
||||
|
||||
if (profile.delete_at === 0) {
|
||||
profiles.push(profile);
|
||||
}
|
||||
if (skipCurrent && profile.id === currentId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (profile) {
|
||||
profiles.push(profile);
|
||||
}
|
||||
}
|
||||
|
||||
profiles.sort((a, b) => a.username.localeCompare(b.username));
|
||||
|
||||
return profiles;
|
||||
}
|
||||
|
||||
saveProfilesForDmList(profiles) {
|
||||
this.profiles_for_dm_list = profiles;
|
||||
// Channel-Wide Profiles
|
||||
|
||||
saveProfilesInChannel(channelId = ChannelStore.getCurrentId(), profiles) {
|
||||
const oldProfileList = this.profiles_in_channel[channelId] || [];
|
||||
const oldProfileMap = {};
|
||||
for (let i = 0; i < oldProfileList.length; i++) {
|
||||
oldProfileMap[oldProfileList[i]] = this.getProfile(oldProfileList[i]);
|
||||
}
|
||||
|
||||
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_in_channel[channelId] = newProfileList;
|
||||
this.saveProfiles(profiles);
|
||||
}
|
||||
|
||||
saveProfileInChannel(channelId = ChannelStore.getCurrentId(), profile) {
|
||||
const profileMap = {};
|
||||
profileMap[profile.id] = profile;
|
||||
this.saveProfilesInChannel(channelId, profileMap);
|
||||
}
|
||||
|
||||
saveUserIdInChannel(channelId = ChannelStore.getCurrentId(), userId) {
|
||||
const profile = this.getProfile(userId);
|
||||
|
||||
// Must have profile or we can't sort the list
|
||||
if (!profile) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.saveProfileInChannel(channelId, profile);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
removeProfileInChannel(channelId, userId) {
|
||||
const userIds = this.profiles_in_channel[channelId];
|
||||
if (!userIds) {
|
||||
return;
|
||||
}
|
||||
|
||||
const index = userIds.indexOf(userId);
|
||||
if (index === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
userIds.splice(index, 1);
|
||||
}
|
||||
|
||||
getProfileListInChannel(channelId = ChannelStore.getCurrentId()) {
|
||||
const userIds = this.profiles_in_channel[channelId] || [];
|
||||
const profiles = [];
|
||||
|
||||
for (let i = 0; i < userIds.length; i++) {
|
||||
const profile = this.getProfile(userIds[i]);
|
||||
if (profile) {
|
||||
profiles.push(profile);
|
||||
}
|
||||
}
|
||||
|
||||
return profiles;
|
||||
}
|
||||
|
||||
saveProfilesNotInChannel(channelId = ChannelStore.getCurrentId(), profiles) {
|
||||
const oldProfileList = this.profiles_not_in_channel[channelId] || [];
|
||||
const oldProfileMap = {};
|
||||
for (let i = 0; i < oldProfileList.length; i++) {
|
||||
oldProfileMap[oldProfileList[i]] = this.getProfile(oldProfileList[i]);
|
||||
}
|
||||
|
||||
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_not_in_channel[channelId] = newProfileList;
|
||||
this.saveProfiles(profiles);
|
||||
}
|
||||
|
||||
saveProfileNotInChannel(channelId = ChannelStore.getCurrentId(), profile) {
|
||||
const profileMap = {};
|
||||
profileMap[profile.id] = profile;
|
||||
this.saveProfilesNotInChannel(channelId, profileMap);
|
||||
}
|
||||
|
||||
removeProfileNotInChannel(channelId, userId) {
|
||||
const userIds = this.profiles_not_in_channel[channelId];
|
||||
if (!userIds) {
|
||||
return;
|
||||
}
|
||||
|
||||
const index = userIds.indexOf(userId);
|
||||
if (index === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
userIds.splice(index, 1);
|
||||
}
|
||||
|
||||
getProfileListNotInChannel(channelId = ChannelStore.getCurrentId()) {
|
||||
const userIds = this.profiles_not_in_channel[channelId] || [];
|
||||
const profiles = [];
|
||||
|
||||
for (let i = 0; i < userIds.length; i++) {
|
||||
const profile = this.getProfile(userIds[i]);
|
||||
if (profile) {
|
||||
profiles.push(profile);
|
||||
}
|
||||
}
|
||||
|
||||
return profiles;
|
||||
}
|
||||
|
||||
// Other
|
||||
|
||||
setSessions(sessions) {
|
||||
this.sessions = sessions;
|
||||
}
|
||||
@@ -331,6 +553,58 @@ class UserStoreClass extends EventEmitter {
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
setPage(offset, count) {
|
||||
this.paging_offset = offset + count;
|
||||
this.paging_count = this.paging_count + count;
|
||||
}
|
||||
|
||||
getPagingOffset() {
|
||||
return this.paging_offset;
|
||||
}
|
||||
|
||||
getPagingCount() {
|
||||
return this.paging_count;
|
||||
}
|
||||
|
||||
setInTeamPage(offset, count) {
|
||||
this.in_team_offset = offset + count;
|
||||
this.in_team_count = this.in_team_count + count;
|
||||
}
|
||||
|
||||
getInTeamPagingOffset() {
|
||||
return this.in_team_offset;
|
||||
}
|
||||
|
||||
getInTeamPagingCount() {
|
||||
return this.in_team_count;
|
||||
}
|
||||
|
||||
setInChannelPage(channelId, offset, count) {
|
||||
this.in_channel_offset[channelId] = offset + count;
|
||||
this.in_channel_count[channelId] = this.dm_paging_count + count;
|
||||
}
|
||||
|
||||
getInChannelPagingOffset(channelId) {
|
||||
return this.in_channel_offset[channelId] | 0;
|
||||
}
|
||||
|
||||
getInChannelPagingCount(channelId) {
|
||||
return this.in_channel_count[channelId] | 0;
|
||||
}
|
||||
|
||||
setNotInChannelPage(channelId, offset, count) {
|
||||
this.not_in_channel_offset[channelId] = offset + count;
|
||||
this.not_in_channel_count[channelId] = this.dm_paging_count + count;
|
||||
}
|
||||
|
||||
getNotInChannelPagingOffset(channelId) {
|
||||
return this.not_in_channel_offset[channelId] | 0;
|
||||
}
|
||||
|
||||
getNotInChannelPagingCount(channelId) {
|
||||
return this.not_in_channel_count[channelId] | 0;
|
||||
}
|
||||
}
|
||||
|
||||
var UserStore = new UserStoreClass();
|
||||
@@ -340,16 +614,36 @@ UserStore.dispatchToken = AppDispatcher.register((payload) => {
|
||||
var action = payload.action;
|
||||
|
||||
switch (action.type) {
|
||||
case ActionTypes.RECEIVED_PROFILES_FOR_DM_LIST:
|
||||
UserStore.saveProfilesForDmList(action.profiles);
|
||||
UserStore.emitDmListChange();
|
||||
break;
|
||||
case ActionTypes.RECEIVED_PROFILES:
|
||||
UserStore.saveProfiles(action.profiles);
|
||||
if (action.offset != null && action.count != null) {
|
||||
UserStore.setPage(action.offset, action.count);
|
||||
}
|
||||
UserStore.emitChange();
|
||||
break;
|
||||
case ActionTypes.RECEIVED_DIRECT_PROFILES:
|
||||
UserStore.saveDirectProfiles(action.profiles);
|
||||
case ActionTypes.RECEIVED_PROFILES_IN_TEAM:
|
||||
UserStore.saveProfilesInTeam(action.team_id, action.profiles);
|
||||
if (action.offset != null && action.count != null) {
|
||||
UserStore.setInTeamPage(action.offset, action.count);
|
||||
}
|
||||
UserStore.emitInTeamChange();
|
||||
break;
|
||||
case ActionTypes.RECEIVED_PROFILES_IN_CHANNEL:
|
||||
UserStore.saveProfilesInChannel(action.channel_id, action.profiles);
|
||||
if (action.offset != null && action.count != null) {
|
||||
UserStore.setInChannelPage(action.offset, action.count);
|
||||
}
|
||||
UserStore.emitInChannelChange();
|
||||
break;
|
||||
case ActionTypes.RECEIVED_PROFILES_NOT_IN_CHANNEL:
|
||||
UserStore.saveProfilesNotInChannel(action.channel_id, action.profiles);
|
||||
if (action.offset != null && action.count != null) {
|
||||
UserStore.setNotInChannelPage(action.offset, action.count);
|
||||
}
|
||||
UserStore.emitNotInChannelChange();
|
||||
break;
|
||||
case ActionTypes.RECEIVED_PROFILE:
|
||||
UserStore.saveProfile(action.profile);
|
||||
UserStore.emitChange();
|
||||
break;
|
||||
case ActionTypes.RECEIVED_ME:
|
||||
|
||||
Ссылка в новой задаче
Block a user