Start moving webapp to Redux (#6140)
* Start moving webapp to Redux * Fix localforage import * Updates per feedback * Feedback udpates and a few fixes * Minor updates * Fix statuses, config not loading properly, getMe sanitizing too much * Fix preferences * Fix user autocomplete * Fix sessions and audits * Fix error handling for all redux actions * Use new directory structure for components and containers * Refresh immediately on logout instead of after timeout * Add fetch polyfill
Этот коммит содержится в:
коммит произвёл
Christopher Speller
родитель
cc07c00507
Коммит
6c4c706313
@@ -5,6 +5,7 @@ package api4
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
l4g "github.com/alecthomas/log4go"
|
||||
"github.com/mattermost/platform/app"
|
||||
@@ -202,7 +203,14 @@ func getClientConfig(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
w.Write([]byte(model.MapToJson(utils.ClientCfg)))
|
||||
respCfg := map[string]string{}
|
||||
for k, v := range utils.ClientCfg {
|
||||
respCfg[k] = v
|
||||
}
|
||||
|
||||
respCfg["NoAccounts"] = strconv.FormatBool(app.IsFirstUserAccount())
|
||||
|
||||
w.Write([]byte(model.MapToJson(respCfg)))
|
||||
}
|
||||
|
||||
func getClientLicense(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -111,7 +111,11 @@ func getUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
if HandleEtag(etag, "Get User", w, r) {
|
||||
return
|
||||
} else {
|
||||
app.SanitizeProfile(user, c.IsSystemAdmin())
|
||||
if c.Session.UserId == user.Id {
|
||||
user.Sanitize(map[string]bool{})
|
||||
} else {
|
||||
app.SanitizeProfile(user, c.IsSystemAdmin())
|
||||
}
|
||||
w.Header().Set(model.HEADER_ETAG_SERVER, etag)
|
||||
w.Write([]byte(user.ToJson()))
|
||||
return
|
||||
|
||||
@@ -5,21 +5,12 @@ import Client from 'client/web_client.jsx';
|
||||
import * as AsyncClient from 'utils/async_client.jsx';
|
||||
import {browserHistory} from 'react-router/es6';
|
||||
|
||||
export function revokeSession(altId, success, error) {
|
||||
Client.revokeSession(altId,
|
||||
() => {
|
||||
AsyncClient.getSessions();
|
||||
if (success) {
|
||||
success();
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
if (error) {
|
||||
error(err);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
// Redux actions
|
||||
import store from 'stores/redux_store.jsx';
|
||||
const dispatch = store.dispatch;
|
||||
const getState = store.getState;
|
||||
|
||||
import {getUser} from 'mattermost-redux/actions/users';
|
||||
|
||||
export function saveConfig(config, success, error) {
|
||||
Client.saveConfig(
|
||||
@@ -57,7 +48,7 @@ export function adminResetMfa(userId, success, error) {
|
||||
Client.adminResetMfa(
|
||||
userId,
|
||||
() => {
|
||||
AsyncClient.getUser(userId);
|
||||
getUser(userId)(dispatch, getState);
|
||||
|
||||
if (success) {
|
||||
success();
|
||||
|
||||
@@ -10,6 +10,12 @@ import Client from 'client/web_client.jsx';
|
||||
|
||||
import {ActionTypes} from 'utils/constants.jsx';
|
||||
|
||||
// Redux actions
|
||||
import store from 'stores/redux_store.jsx';
|
||||
const dispatch = store.dispatch;
|
||||
const getState = store.getState;
|
||||
import {getProfilesByIds} from 'mattermost-redux/actions/users';
|
||||
|
||||
export function loadEmoji(getProfiles = true) {
|
||||
Client.listEmoji(
|
||||
(data) => {
|
||||
@@ -42,5 +48,5 @@ function loadProfilesForEmoji(emojiList) {
|
||||
return;
|
||||
}
|
||||
|
||||
AsyncClient.getProfilesByIds(list);
|
||||
getProfilesByIds(list)(dispatch, getState);
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@ import UserStore from 'stores/user_store.jsx';
|
||||
import BrowserStore from 'stores/browser_store.jsx';
|
||||
import ErrorStore from 'stores/error_store.jsx';
|
||||
import TeamStore from 'stores/team_store.jsx';
|
||||
import PreferenceStore from 'stores/preference_store.jsx';
|
||||
import SearchStore from 'stores/search_store.jsx';
|
||||
|
||||
import {handleNewPost, loadPosts, loadPostsBefore, loadPostsAfter} from 'actions/post_actions.jsx';
|
||||
@@ -32,6 +31,12 @@ import en from 'i18n/en.json';
|
||||
import * as I18n from 'i18n/i18n.jsx';
|
||||
import {browserHistory} from 'react-router/es6';
|
||||
|
||||
// Redux actions
|
||||
import store from 'stores/redux_store.jsx';
|
||||
const dispatch = store.dispatch;
|
||||
const getState = store.getState;
|
||||
import {ChannelTypes} from 'mattermost-redux/action_types';
|
||||
|
||||
export function emitChannelClickEvent(channel) {
|
||||
function userVisitedFakeChannel(chan, success, fail) {
|
||||
const otherUserId = Utils.getUserIdFromChannelName(chan);
|
||||
@@ -77,6 +82,11 @@ export function emitChannelClickEvent(channel) {
|
||||
channelMember,
|
||||
prev: oldChannelId
|
||||
});
|
||||
|
||||
dispatch({
|
||||
type: ChannelTypes.SELECT_CHANNEL,
|
||||
data: chan.id
|
||||
}, getState);
|
||||
}
|
||||
|
||||
if (channel.fake) {
|
||||
@@ -94,85 +104,6 @@ export function emitChannelClickEvent(channel) {
|
||||
}
|
||||
}
|
||||
|
||||
export function emitInitialLoad(callback) {
|
||||
Client.getInitialLoad(
|
||||
(data) => {
|
||||
global.window.mm_config = data.client_cfg;
|
||||
global.window.mm_license = data.license_cfg;
|
||||
|
||||
if (global.window && global.window.analytics) {
|
||||
global.window.analytics.identify(global.window.mm_config.DiagnosticId, {}, {
|
||||
context: {
|
||||
ip: '0.0.0.0'
|
||||
},
|
||||
page: {
|
||||
path: '',
|
||||
referrer: '',
|
||||
search: '',
|
||||
title: '',
|
||||
url: ''
|
||||
},
|
||||
anonymousId: '00000000000000000000000000'
|
||||
});
|
||||
}
|
||||
|
||||
UserStore.setNoAccounts(data.no_accounts);
|
||||
|
||||
if (data.user && data.user.id) {
|
||||
global.window.mm_user = data.user;
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECEIVED_ME,
|
||||
me: data.user
|
||||
});
|
||||
}
|
||||
|
||||
if (data.preferences) {
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECEIVED_PREFERENCES,
|
||||
preferences: data.preferences
|
||||
});
|
||||
}
|
||||
|
||||
if (data.teams) {
|
||||
var teams = {};
|
||||
data.teams.forEach((team) => {
|
||||
teams[team.id] = team;
|
||||
});
|
||||
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECEIVED_ALL_TEAMS,
|
||||
teams
|
||||
});
|
||||
}
|
||||
|
||||
if (data.team_members) {
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECEIVED_MY_TEAM_MEMBERS,
|
||||
team_members: data.team_members
|
||||
});
|
||||
}
|
||||
|
||||
if (data.direct_profiles) {
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECEIVED_DIRECT_PROFILES,
|
||||
profiles: data.direct_profiles
|
||||
});
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
AsyncClient.dispatchError(err, 'getInitialLoad');
|
||||
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function doFocusPost(channelId, postId, data) {
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECEIVED_FOCUSED_POST,
|
||||
@@ -536,12 +467,11 @@ export function emitUserLoggedOutEvent(redirectTo = '/', shouldSignalLogout = tr
|
||||
export function clientLogout(redirectTo = '/') {
|
||||
BrowserStore.clear();
|
||||
ErrorStore.clearLastError();
|
||||
PreferenceStore.clear();
|
||||
UserStore.clear();
|
||||
TeamStore.clear();
|
||||
ChannelStore.clear();
|
||||
stopPeriodicStatusUpdates();
|
||||
WebsocketActions.close();
|
||||
localStorage.removeItem('currentUserId');
|
||||
window.location.href = redirectTo;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,12 @@ import Client from 'client/web_client.jsx';
|
||||
|
||||
import {ActionTypes} from 'utils/constants.jsx';
|
||||
|
||||
// Redux actions
|
||||
import store from 'stores/redux_store.jsx';
|
||||
const dispatch = store.dispatch;
|
||||
const getState = store.getState;
|
||||
import {getProfilesByIds} from 'mattermost-redux/actions/users';
|
||||
|
||||
export function loadIncomingHooks() {
|
||||
Client.listIncomingHooks(
|
||||
(data) => {
|
||||
@@ -42,7 +48,7 @@ function loadProfilesForIncomingHooks(hooks) {
|
||||
return;
|
||||
}
|
||||
|
||||
AsyncClient.getProfilesByIds(list);
|
||||
getProfilesByIds(list)(dispatch, getState);
|
||||
}
|
||||
|
||||
export function loadOutgoingHooks() {
|
||||
@@ -76,7 +82,7 @@ function loadProfilesForOutgoingHooks(hooks) {
|
||||
return;
|
||||
}
|
||||
|
||||
AsyncClient.getProfilesByIds(list);
|
||||
getProfilesByIds(list)(dispatch, getState);
|
||||
}
|
||||
|
||||
export function loadTeamCommands() {
|
||||
@@ -110,5 +116,5 @@ function loadProfilesForCommands(commands) {
|
||||
return;
|
||||
}
|
||||
|
||||
AsyncClient.getProfilesByIds(list);
|
||||
getProfilesByIds(list)(dispatch, getState);
|
||||
}
|
||||
|
||||
@@ -20,6 +20,12 @@ import Constants from 'utils/constants.jsx';
|
||||
const ActionTypes = Constants.ActionTypes;
|
||||
const Preferences = Constants.Preferences;
|
||||
|
||||
// Redux actions
|
||||
import store from 'stores/redux_store.jsx';
|
||||
const dispatch = store.dispatch;
|
||||
const getState = store.getState;
|
||||
import {getProfilesByIds} from 'mattermost-redux/actions/users';
|
||||
|
||||
export function handleNewPost(post, msg) {
|
||||
let websocketMessageProps = {};
|
||||
if (msg) {
|
||||
@@ -310,7 +316,7 @@ export function loadProfilesForPosts(posts) {
|
||||
return;
|
||||
}
|
||||
|
||||
AsyncClient.getProfilesByIds(list);
|
||||
getProfilesByIds(list)(dispatch, getState);
|
||||
}
|
||||
|
||||
export function addReaction(channelId, postId, emojiName) {
|
||||
|
||||
@@ -1,16 +1,19 @@
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import AppDispatcher from 'dispatcher/app_dispatcher.jsx';
|
||||
|
||||
import ChannelStore from 'stores/channel_store.jsx';
|
||||
import PostStore from 'stores/post_store.jsx';
|
||||
import PreferenceStore from 'stores/preference_store.jsx';
|
||||
import UserStore from 'stores/user_store.jsx';
|
||||
|
||||
import Client from 'client/web_client.jsx';
|
||||
import {Preferences, Constants} from 'utils/constants.jsx';
|
||||
|
||||
import {ActionTypes, Preferences, Constants} from 'utils/constants.jsx';
|
||||
// Redux actions
|
||||
import store from 'stores/redux_store.jsx';
|
||||
const dispatch = store.dispatch;
|
||||
const getState = store.getState;
|
||||
|
||||
import {getStatusesByIds} from 'mattermost-redux/actions/users';
|
||||
|
||||
export function loadStatusesForChannel(channelId = ChannelStore.getCurrentId()) {
|
||||
const postList = PostStore.getVisiblePosts(channelId);
|
||||
@@ -108,15 +111,7 @@ export function loadStatusesByIds(userIds) {
|
||||
return;
|
||||
}
|
||||
|
||||
Client.getStatusesByIds(
|
||||
userIds,
|
||||
(data) => {
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECEIVED_STATUSES,
|
||||
statuses: data
|
||||
});
|
||||
}
|
||||
);
|
||||
getStatusesByIds(userIds)(dispatch, getState);
|
||||
}
|
||||
|
||||
let intervalId = '';
|
||||
|
||||
@@ -13,6 +13,13 @@ import AppDispatcher from 'dispatcher/app_dispatcher.jsx';
|
||||
|
||||
import {browserHistory} from 'react-router/es6';
|
||||
|
||||
// Redux actions
|
||||
import store from 'stores/redux_store.jsx';
|
||||
const dispatch = store.dispatch;
|
||||
const getState = store.getState;
|
||||
|
||||
import {getUser} from 'mattermost-redux/actions/users';
|
||||
|
||||
export function checkIfTeamExists(teamName, onSuccess, onError) {
|
||||
Client.findTeamByName(teamName, onSuccess, onError);
|
||||
}
|
||||
@@ -62,7 +69,7 @@ export function removeUserFromTeam(teamId, userId, success, error) {
|
||||
TeamStore.removeMemberInTeam(teamId, userId);
|
||||
UserStore.removeProfileFromTeam(teamId, userId);
|
||||
UserStore.emitInTeamChange();
|
||||
AsyncClient.getUser(userId);
|
||||
getUser(userId)(dispatch, getState);
|
||||
AsyncClient.getTeamStats(teamId);
|
||||
|
||||
if (success) {
|
||||
|
||||
@@ -19,6 +19,79 @@ import Client from 'client/web_client.jsx';
|
||||
import {Constants, ActionTypes, Preferences} from 'utils/constants.jsx';
|
||||
import {browserHistory} from 'react-router/es6';
|
||||
|
||||
// Redux actions
|
||||
import store from 'stores/redux_store.jsx';
|
||||
const dispatch = store.dispatch;
|
||||
const getState = store.getState;
|
||||
|
||||
import {
|
||||
getProfiles,
|
||||
getProfilesInChannel,
|
||||
getProfilesInTeam,
|
||||
getProfilesWithoutTeam,
|
||||
getProfilesByIds,
|
||||
getMe,
|
||||
searchProfiles,
|
||||
autocompleteUsers as autocompleteRedux,
|
||||
updateMe,
|
||||
updateUserMfa,
|
||||
checkMfa as checkMfaRedux,
|
||||
updateUserPassword,
|
||||
createUser,
|
||||
login,
|
||||
loadMe as loadMeRedux
|
||||
} from 'mattermost-redux/actions/users';
|
||||
|
||||
import {getClientConfig, getLicenseConfig} from 'mattermost-redux/actions/general';
|
||||
|
||||
export function loadMe(callback) {
|
||||
loadMeRedux()(dispatch, getState).then(
|
||||
() => {
|
||||
localStorage.setItem('currentUserId', UserStore.getCurrentId());
|
||||
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function loadMeAndConfig(callback) {
|
||||
loadMe(() => {
|
||||
getClientConfig()(store.dispatch, store.getState).then(
|
||||
(config) => {
|
||||
global.window.mm_config = config;
|
||||
|
||||
if (global.window && global.window.analytics) {
|
||||
global.window.analytics.identify(global.window.mm_config.DiagnosticId, {}, {
|
||||
context: {
|
||||
ip: '0.0.0.0'
|
||||
},
|
||||
page: {
|
||||
path: '',
|
||||
referrer: '',
|
||||
search: '',
|
||||
title: '',
|
||||
url: ''
|
||||
},
|
||||
anonymousId: '00000000000000000000000000'
|
||||
});
|
||||
}
|
||||
|
||||
getLicenseConfig()(store.dispatch, store.getState).then(
|
||||
(license) => { // eslint-disable-line max-nested-callbacks
|
||||
global.window.mm_license = license;
|
||||
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export function switchFromLdapToEmail(email, password, token, ldapPassword, onSuccess, onError) {
|
||||
Client.ldapToEmail(
|
||||
email,
|
||||
@@ -38,80 +111,30 @@ export function switchFromLdapToEmail(email, password, token, ldapPassword, onSu
|
||||
);
|
||||
}
|
||||
|
||||
export function loadProfilesAndTeamMembers(offset, limit, teamId = TeamStore.getCurrentId(), success, error) {
|
||||
Client.getProfilesInTeam(
|
||||
teamId,
|
||||
offset,
|
||||
limit,
|
||||
export function loadProfilesAndTeamMembers(page, perPage, teamId = TeamStore.getCurrentId(), success) {
|
||||
getProfilesInTeam(teamId, page, perPage)(dispatch, getState).then(
|
||||
(data) => {
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECEIVED_PROFILES_IN_TEAM,
|
||||
profiles: data,
|
||||
team_id: teamId,
|
||||
offset,
|
||||
count: Object.keys(data).length
|
||||
});
|
||||
|
||||
loadTeamMembersForProfilesMap(data, teamId, success, error);
|
||||
loadStatusesForProfilesMap(data);
|
||||
},
|
||||
(err) => {
|
||||
AsyncClient.dispatchError(err, 'getProfilesInTeam');
|
||||
loadTeamMembersForProfilesList(data, teamId, success);
|
||||
loadStatusesForProfilesList(data);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function loadProfilesAndTeamMembersAndChannelMembers(offset, limit, teamId = TeamStore.getCurrentId(), channelId = ChannelStore.getCurrentId(), success, error) {
|
||||
Client.getProfilesInChannel(
|
||||
channelId,
|
||||
offset,
|
||||
limit,
|
||||
export function loadProfilesAndTeamMembersAndChannelMembers(page, perPage, teamId = TeamStore.getCurrentId(), channelId = ChannelStore.getCurrentId(), success, error) {
|
||||
getProfilesInChannel(channelId, page, perPage)(dispatch, getState).then(
|
||||
(data) => {
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECEIVED_PROFILES_IN_CHANNEL,
|
||||
profiles: data,
|
||||
channel_id: channelId,
|
||||
offset,
|
||||
count: Object.keys(data).length
|
||||
});
|
||||
|
||||
loadTeamMembersForProfilesMap(
|
||||
loadTeamMembersForProfilesList(
|
||||
data,
|
||||
teamId,
|
||||
() => {
|
||||
loadChannelMembersForProfilesMap(data, channelId, success, error);
|
||||
loadStatusesForProfilesMap(data);
|
||||
});
|
||||
},
|
||||
(err) => {
|
||||
AsyncClient.dispatchError(err, 'getProfilesInChannel');
|
||||
loadChannelMembersForProfilesList(data, channelId, success, error);
|
||||
loadStatusesForProfilesList(data);
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function loadTeamMembersForProfilesMap(profiles, teamId = TeamStore.getCurrentId(), success, error) {
|
||||
const membersToLoad = {};
|
||||
for (const pid in profiles) {
|
||||
if (!profiles.hasOwnProperty(pid)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!TeamStore.hasActiveMemberInTeam(teamId, pid)) {
|
||||
membersToLoad[pid] = true;
|
||||
}
|
||||
}
|
||||
|
||||
const list = Object.keys(membersToLoad);
|
||||
if (list.length === 0) {
|
||||
if (success) {
|
||||
success({});
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
loadTeamMembersForProfiles(list, teamId, success, error);
|
||||
}
|
||||
|
||||
export function loadTeamMembersForProfilesList(profiles, teamId = TeamStore.getCurrentId(), success, error) {
|
||||
const membersToLoad = {};
|
||||
for (let i = 0; i < profiles.length; i++) {
|
||||
@@ -133,24 +156,13 @@ export function loadTeamMembersForProfilesList(profiles, teamId = TeamStore.getC
|
||||
loadTeamMembersForProfiles(list, teamId, success, error);
|
||||
}
|
||||
|
||||
export function loadProfilesWithoutTeam(page, perPage, success, error) {
|
||||
Client.getProfilesWithoutTeam(
|
||||
page,
|
||||
perPage,
|
||||
export function loadProfilesWithoutTeam(page, perPage, success) {
|
||||
getProfilesWithoutTeam(page, perPage)(dispatch, getState).then(
|
||||
(data) => {
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECEIVED_PROFILES_WITHOUT_TEAM,
|
||||
profiles: data,
|
||||
page
|
||||
});
|
||||
|
||||
loadStatusesForProfilesMap(data);
|
||||
},
|
||||
(err) => {
|
||||
AsyncClient.dispatchError(err, 'getProfilesWithoutTeam');
|
||||
|
||||
if (error) {
|
||||
error(err);
|
||||
if (success) {
|
||||
success(data);
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -248,9 +260,9 @@ function populateDMChannelsWithProfiles(userIds) {
|
||||
}
|
||||
}
|
||||
|
||||
function populateChannelWithProfiles(channelId, userIds) {
|
||||
for (let i = 0; i < userIds.length; i++) {
|
||||
UserStore.saveUserIdInChannel(channelId, userIds[i]);
|
||||
function populateChannelWithProfiles(channelId, users) {
|
||||
for (let i = 0; i < users.length; i++) {
|
||||
UserStore.saveUserIdInChannel(channelId, users[i].id);
|
||||
}
|
||||
UserStore.emitInChannelChange();
|
||||
}
|
||||
@@ -360,17 +372,9 @@ export function loadProfilesForGM() {
|
||||
});
|
||||
}
|
||||
|
||||
Client.getProfilesInChannel(
|
||||
channel.id,
|
||||
0,
|
||||
Constants.MAX_USERS_IN_GM,
|
||||
getProfilesInChannel(channel.id, 0, Constants.MAX_USERS_IN_GM)(dispatch, getState).then(
|
||||
(data) => {
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECEIVED_PROFILES,
|
||||
profiles: data
|
||||
});
|
||||
|
||||
populateChannelWithProfiles(channel.id, Object.keys(data));
|
||||
populateChannelWithProfiles(channel.id, data);
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -420,20 +424,10 @@ export function loadProfilesForDM() {
|
||||
}
|
||||
|
||||
if (profilesToLoad.length > 0) {
|
||||
Client.getProfilesByIds(
|
||||
profilesToLoad,
|
||||
(data) => {
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECEIVED_PROFILES,
|
||||
profiles: data
|
||||
});
|
||||
|
||||
// Use membersToLoad so we get all the DM profiles even if they were already loaded
|
||||
getProfilesByIds(profilesToLoad)(dispatch, getState).then(
|
||||
() => {
|
||||
populateDMChannelsWithProfiles(profileIds);
|
||||
},
|
||||
(err) => {
|
||||
AsyncClient.dispatchError(err, 'getProfilesByIds');
|
||||
}
|
||||
);
|
||||
} else {
|
||||
populateDMChannelsWithProfiles(profileIds);
|
||||
@@ -491,119 +485,70 @@ function onThemeSaved(teamId, theme, onSuccess) {
|
||||
onSuccess();
|
||||
}
|
||||
|
||||
export function searchUsers(term, teamId = TeamStore.getCurrentId(), options = {}, success, error) {
|
||||
Client.searchUsers(
|
||||
term,
|
||||
teamId,
|
||||
options,
|
||||
export function searchUsers(term, teamId = TeamStore.getCurrentId(), options = {}, success) {
|
||||
searchProfiles(term, {team_id: teamId, ...options})(dispatch, getState).then(
|
||||
(data) => {
|
||||
loadStatusesForProfilesList(data);
|
||||
|
||||
if (success) {
|
||||
success(data);
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
AsyncClient.dispatchError(err, 'searchUsers');
|
||||
|
||||
if (error) {
|
||||
error(err);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function searchUsersNotInTeam(term, teamId = TeamStore.getCurrentId(), options = {}, success, error) {
|
||||
Client.searchUsersNotInTeam(
|
||||
term,
|
||||
teamId,
|
||||
options,
|
||||
export function searchUsersNotInTeam(term, teamId = TeamStore.getCurrentId(), options = {}, success) {
|
||||
searchProfiles(term, {not_in_team_id: teamId, ...options})(dispatch, getState).then(
|
||||
(data) => {
|
||||
loadStatusesForProfilesList(data);
|
||||
|
||||
if (success) {
|
||||
success(data);
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
AsyncClient.dispatchError(err, 'searchUsersNotInTeam');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
error(err);
|
||||
export function autocompleteUsersInChannel(username, channelId, success) {
|
||||
const channel = ChannelStore.get(channelId);
|
||||
const teamId = channel ? channel.team_id : TeamStore.getCurrentId();
|
||||
autocompleteRedux(username, teamId, channelId)(dispatch, getState).then(
|
||||
(data) => {
|
||||
if (success) {
|
||||
success(data);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function autocompleteUsersInChannel(username, channelId, success, error) {
|
||||
Client.autocompleteUsersInChannel(
|
||||
username,
|
||||
channelId,
|
||||
export function autocompleteUsersInTeam(username, success) {
|
||||
autocompleteRedux(username, TeamStore.getCurrentId())(dispatch, getState).then(
|
||||
(data) => {
|
||||
if (success) {
|
||||
success(data);
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
AsyncClient.dispatchError(err, 'autocompleteUsersInChannel');
|
||||
|
||||
if (error) {
|
||||
error(err);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function autocompleteUsersInTeam(username, success, error) {
|
||||
Client.autocompleteUsersInTeam(
|
||||
username,
|
||||
export function autocompleteUsers(username, success) {
|
||||
autocompleteRedux(username)(dispatch, getState).then(
|
||||
(data) => {
|
||||
if (success) {
|
||||
success(data);
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
AsyncClient.dispatchError(err, 'autocompleteUsersInTeam');
|
||||
|
||||
if (error) {
|
||||
error(err);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function autocompleteUsers(username, success, error) {
|
||||
Client.autocompleteUsers(
|
||||
username,
|
||||
export function updateUser(user, type, success, error) {
|
||||
updateMe(user)(dispatch, getState).then(
|
||||
(data) => {
|
||||
if (success) {
|
||||
if (data && success) {
|
||||
success(data);
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
AsyncClient.dispatchError(err, 'autocompleteUsers');
|
||||
|
||||
if (error) {
|
||||
error(err);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function updateUser(username, type, success, error) {
|
||||
Client.updateUser(
|
||||
username,
|
||||
type,
|
||||
(data) => {
|
||||
if (success) {
|
||||
success(data);
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
if (error) {
|
||||
error(err);
|
||||
} else {
|
||||
AsyncClient.dispatchError(err, 'updateUser');
|
||||
} else if (data == null && error) {
|
||||
const serverError = getState().requests.users.updateUser.error;
|
||||
error({id: serverError.server_error_id, ...serverError});
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -626,74 +571,55 @@ export function generateMfaSecret(success, error) {
|
||||
);
|
||||
}
|
||||
|
||||
export function updateUserNotifyProps(data, success, error) {
|
||||
Client.updateUserNotifyProps(
|
||||
data,
|
||||
() => {
|
||||
AsyncClient.getMe();
|
||||
|
||||
if (success) {
|
||||
success();
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
if (error) {
|
||||
error(err);
|
||||
}
|
||||
}
|
||||
export function updateUserNotifyProps(props, success, error) {
|
||||
updateMe({notify_props: props})(dispatch, getState).then(
|
||||
(data) => {
|
||||
if (data && success) {
|
||||
success(data);
|
||||
} else if (data == null && error) {
|
||||
const serverError = getState().requests.users.updateMe.error;
|
||||
error({id: serverError.server_error_id, ...serverError});
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function updateUserRoles(userId, newRoles, success, error) {
|
||||
Client.updateUserRoles(
|
||||
userId,
|
||||
newRoles,
|
||||
() => {
|
||||
AsyncClient.getUser(
|
||||
userId,
|
||||
success,
|
||||
error
|
||||
);
|
||||
},
|
||||
error
|
||||
updateUserRoles(userId, newRoles)(dispatch, getState).then(
|
||||
(data) => {
|
||||
if (data && success) {
|
||||
success(data);
|
||||
} else if (data == null && error) {
|
||||
const serverError = getState().requests.users.updateUser.error;
|
||||
error({id: serverError.server_error_id, ...serverError});
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function activateMfa(code, success, error) {
|
||||
Client.updateMfa(
|
||||
code,
|
||||
true,
|
||||
() => {
|
||||
AsyncClient.getMe();
|
||||
|
||||
if (success) {
|
||||
success();
|
||||
updateUserMfa(UserStore.getCurrentId(), true, code)(dispatch, getState).then(
|
||||
(data) => {
|
||||
if (data && success) {
|
||||
success(data);
|
||||
} else if (data == null && error) {
|
||||
const serverError = getState().requests.users.updateUser.error;
|
||||
error({id: serverError.server_error_id, ...serverError});
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
if (error) {
|
||||
error(err);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function deactivateMfa(success, error) {
|
||||
Client.updateMfa(
|
||||
'',
|
||||
false,
|
||||
() => {
|
||||
AsyncClient.getMe();
|
||||
|
||||
if (success) {
|
||||
success();
|
||||
updateUserMfa(UserStore.getCurrentId(), false)(dispatch, getState).then(
|
||||
(data) => {
|
||||
if (data && success) {
|
||||
success(data);
|
||||
} else if (data == null && error) {
|
||||
const serverError = getState().requests.users.updateUser.error;
|
||||
error({id: serverError.server_error_id, ...serverError});
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
if (error) {
|
||||
error(err);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -703,16 +629,13 @@ export function checkMfa(loginId, success, error) {
|
||||
return;
|
||||
}
|
||||
|
||||
Client.checkMfa(
|
||||
loginId,
|
||||
checkMfaRedux(loginId)(dispatch, getState).then(
|
||||
(data) => {
|
||||
if (success) {
|
||||
success(data && data.mfa_required === 'true');
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
if (error) {
|
||||
error(err);
|
||||
if (data && success) {
|
||||
success(data);
|
||||
} else if (data == null && error) {
|
||||
const serverError = getState().requests.users.checkMfa.error;
|
||||
error({id: serverError.server_error_id, ...serverError});
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -735,15 +658,13 @@ export function updateActive(userId, active, success, error) {
|
||||
}
|
||||
|
||||
export function updatePassword(userId, currentPassword, newPassword, success, error) {
|
||||
Client.updatePassword(userId, currentPassword, newPassword,
|
||||
() => {
|
||||
if (success) {
|
||||
success();
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
if (error) {
|
||||
error(err);
|
||||
updateUserPassword(userId, currentPassword, newPassword)(dispatch, getState).then(
|
||||
(data) => {
|
||||
if (data && success) {
|
||||
success(data);
|
||||
} else if (data == null && error) {
|
||||
const serverError = getState().requests.users.updateUser.error;
|
||||
error({id: serverError.server_error_id, ...serverError});
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -820,37 +741,27 @@ export function loginById(userId, password, mfaToken, success, error) {
|
||||
}
|
||||
|
||||
export function createUserWithInvite(user, data, emailHash, inviteId, success, error) {
|
||||
Client.createUserWithInvite(
|
||||
user,
|
||||
data,
|
||||
emailHash,
|
||||
inviteId,
|
||||
(response) => {
|
||||
if (success) {
|
||||
success(response);
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
if (error) {
|
||||
error(err);
|
||||
createUser(user, data, emailHash, inviteId)(dispatch, getState).then(
|
||||
(resp) => {
|
||||
if (resp && success) {
|
||||
success(resp);
|
||||
} else if (resp == null && error) {
|
||||
const serverError = getState().requests.users.create.error;
|
||||
error({id: serverError.server_error_id, ...serverError});
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function webLogin(loginId, password, token, success, error) {
|
||||
Client.webLogin(
|
||||
loginId,
|
||||
password,
|
||||
token,
|
||||
() => {
|
||||
if (success) {
|
||||
login(loginId, password, token)(dispatch, getState).then(
|
||||
(ok) => {
|
||||
if (ok && success) {
|
||||
localStorage.setItem('currentUserId', UserStore.getCurrentId());
|
||||
success();
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
if (error) {
|
||||
error(err);
|
||||
} else if (!ok && error) {
|
||||
const serverError = getState().requests.users.login.error;
|
||||
error({id: serverError.server_error_id, ...serverError});
|
||||
}
|
||||
}
|
||||
);
|
||||
@@ -907,7 +818,7 @@ export function uploadProfileImage(userPicture, success, error) {
|
||||
Client.uploadProfileImage(
|
||||
userPicture,
|
||||
() => {
|
||||
AsyncClient.getMe();
|
||||
getMe()(dispatch, getState);
|
||||
if (success) {
|
||||
success();
|
||||
}
|
||||
@@ -920,38 +831,24 @@ export function uploadProfileImage(userPicture, success, error) {
|
||||
);
|
||||
}
|
||||
|
||||
export function loadProfiles(offset = UserStore.getPagingOffset(), limit = Constants.PROFILE_CHUNK_SIZE, success, error) {
|
||||
Client.getProfiles(
|
||||
offset,
|
||||
limit,
|
||||
export function loadProfiles(page, perPage, success) {
|
||||
getProfiles(page, perPage)(dispatch, getState).then(
|
||||
(data) => {
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECEIVED_PROFILES,
|
||||
profiles: data
|
||||
});
|
||||
|
||||
if (success) {
|
||||
success(data);
|
||||
}
|
||||
},
|
||||
(err) => {
|
||||
AsyncClient.dispatchError(err, 'getProfiles');
|
||||
|
||||
if (error) {
|
||||
error(err);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function getMissingProfiles(ids, success, error) {
|
||||
export function getMissingProfiles(ids) {
|
||||
const missingIds = ids.filter((id) => !UserStore.hasProfile(id));
|
||||
|
||||
if (missingIds.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
AsyncClient.getProfilesByIds(missingIds, success, error);
|
||||
getProfilesByIds(missingIds)(dispatch, getState);
|
||||
}
|
||||
|
||||
export function loadMyTeamMembers() {
|
||||
|
||||
@@ -338,7 +338,6 @@ function handleUserUpdatedEvent(msg) {
|
||||
const user = msg.data.user;
|
||||
if (UserStore.getCurrentId() !== user.id) {
|
||||
UserStore.saveProfile(user);
|
||||
UserStore.emitChange(user.id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import LoadingScreen from './loading_screen.jsx';
|
||||
import AuditTable from './audit_table.jsx';
|
||||
import LoadingScreen from 'components/loading_screen.jsx';
|
||||
import AuditTable from 'components/audit_table.jsx';
|
||||
|
||||
import UserStore from 'stores/user_store.jsx';
|
||||
|
||||
import * as AsyncClient from 'utils/async_client.jsx';
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
|
||||
import $ from 'jquery';
|
||||
@@ -16,6 +15,13 @@ import {Modal} from 'react-bootstrap';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
|
||||
export default class AccessHistoryModal extends React.Component {
|
||||
static propTypes = {
|
||||
onHide: React.PropTypes.func.isRequired,
|
||||
actions: React.PropTypes.shape({
|
||||
getUserAudits: React.PropTypes.func.isRequired
|
||||
}).isRequired
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -37,7 +43,7 @@ export default class AccessHistoryModal extends React.Component {
|
||||
}
|
||||
|
||||
onShow() {
|
||||
AsyncClient.getAudits();
|
||||
this.props.actions.getUserAudits(UserStore.getCurrentId(), 0, 200);
|
||||
if (!Utils.isMobile()) {
|
||||
$('.modal-body').perfectScrollbar();
|
||||
}
|
||||
@@ -100,7 +106,3 @@ export default class AccessHistoryModal extends React.Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
AccessHistoryModal.propTypes = {
|
||||
onHide: React.PropTypes.func.isRequired
|
||||
};
|
||||
24
webapp/components/access_history_modal/index.js
Обычный файл
24
webapp/components/access_history_modal/index.js
Обычный файл
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {getUserAudits} from 'mattermost-redux/actions/users';
|
||||
|
||||
import AccessHistoryModal from './access_history_modal.jsx';
|
||||
|
||||
function mapStateToProps(state, ownProps) {
|
||||
return {
|
||||
...ownProps
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
getUserAudits
|
||||
}, dispatch)
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(AccessHistoryModal);
|
||||
@@ -1,11 +1,10 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import LoadingScreen from './loading_screen.jsx';
|
||||
import LoadingScreen from 'components/loading_screen.jsx';
|
||||
|
||||
import UserStore from 'stores/user_store.jsx';
|
||||
|
||||
import * as AsyncClient from 'utils/async_client.jsx';
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
|
||||
import $ from 'jquery';
|
||||
@@ -13,9 +12,15 @@ import React from 'react';
|
||||
import {Modal} from 'react-bootstrap';
|
||||
import {FormattedMessage, FormattedTime, FormattedDate} from 'react-intl';
|
||||
|
||||
import {revokeSession} from 'actions/admin_actions.jsx';
|
||||
|
||||
export default class ActivityLogModal extends React.Component {
|
||||
static propTypes = {
|
||||
onHide: React.PropTypes.func.isRequired,
|
||||
actions: React.PropTypes.shape({
|
||||
getSessions: React.PropTypes.func.isRequired,
|
||||
revokeSession: React.PropTypes.func.isRequired
|
||||
}).isRequired
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -35,7 +40,6 @@ export default class ActivityLogModal extends React.Component {
|
||||
getStateFromStores() {
|
||||
return {
|
||||
sessions: UserStore.getSessions(),
|
||||
serverError: null,
|
||||
clientError: null
|
||||
};
|
||||
}
|
||||
@@ -47,18 +51,11 @@ export default class ActivityLogModal extends React.Component {
|
||||
setTimeout(() => {
|
||||
modalContent.removeClass('animation--highlight');
|
||||
}, 1500);
|
||||
revokeSession(altId,
|
||||
null,
|
||||
(err) => {
|
||||
const state = this.getStateFromStores();
|
||||
state.serverError = err;
|
||||
this.setState(state);
|
||||
}
|
||||
);
|
||||
this.props.actions.revokeSession(UserStore.getCurrentId(), altId);
|
||||
}
|
||||
|
||||
onShow() {
|
||||
AsyncClient.getSessions();
|
||||
this.props.actions.getSessions(UserStore.getCurrentId());
|
||||
if (!Utils.isMobile()) {
|
||||
$('.modal-body').perfectScrollbar();
|
||||
}
|
||||
@@ -302,7 +299,3 @@ export default class ActivityLogModal extends React.Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ActivityLogModal.propTypes = {
|
||||
onHide: React.PropTypes.func.isRequired
|
||||
};
|
||||
25
webapp/components/activity_log_modal/index.js
Обычный файл
25
webapp/components/activity_log_modal/index.js
Обычный файл
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {revokeSession, getSessions} from 'mattermost-redux/actions/users';
|
||||
|
||||
import ActivityLogModal from './activity_log_modal.jsx';
|
||||
|
||||
function mapStateToProps(state, ownProps) {
|
||||
return {
|
||||
...ownProps
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
getSessions,
|
||||
revokeSession
|
||||
}, dispatch)
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ActivityLogModal);
|
||||
@@ -10,7 +10,6 @@ import {searchUsersNotInTeam} from 'actions/user_actions.jsx';
|
||||
import UserStore from 'stores/user_store.jsx';
|
||||
import TeamStore from 'stores/team_store.jsx';
|
||||
|
||||
import * as AsyncClient from 'utils/async_client.jsx';
|
||||
import Constants from 'utils/constants.jsx';
|
||||
import {displayUsernameForUser} from 'utils/utils.jsx';
|
||||
import Client from 'client/web_client.jsx';
|
||||
@@ -20,10 +19,20 @@ import {Modal} from 'react-bootstrap';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {browserHistory} from 'react-router/es6';
|
||||
|
||||
import store from 'stores/redux_store.jsx';
|
||||
import {searchProfilesNotInCurrentTeam} from 'mattermost-redux/selectors/entities/users';
|
||||
|
||||
const USERS_PER_PAGE = 50;
|
||||
const MAX_SELECTABLE_VALUES = 20;
|
||||
|
||||
export default class AddUsersToTeam extends React.Component {
|
||||
static propTypes = {
|
||||
onModalDismissed: React.PropTypes.func,
|
||||
actions: React.PropTypes.shape({
|
||||
getProfilesNotInTeam: React.PropTypes.func.isRequired
|
||||
}).isRequired
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -34,11 +43,12 @@ export default class AddUsersToTeam extends React.Component {
|
||||
this.onChange = this.onChange.bind(this);
|
||||
this.search = this.search.bind(this);
|
||||
this.addValue = this.addValue.bind(this);
|
||||
this.handlePageChange = this.handlePageChange.bind(this);
|
||||
|
||||
this.searchTimeoutId = 0;
|
||||
|
||||
this.state = {
|
||||
users: null,
|
||||
users: Object.assign([], UserStore.getProfileListNotInTeam(TeamStore.getCurrentId(), true)),
|
||||
values: [],
|
||||
show: true,
|
||||
search: false
|
||||
@@ -50,7 +60,7 @@ export default class AddUsersToTeam extends React.Component {
|
||||
UserStore.addNotInTeamChangeListener(this.onChange);
|
||||
UserStore.addStatusesChangeListener(this.onChange);
|
||||
|
||||
AsyncClient.getProfilesNotInTeam(TeamStore.getCurrentId(), 0, USERS_PER_PAGE * 2);
|
||||
this.props.actions.getProfilesNotInTeam(TeamStore.getCurrentId(), 0, USERS_PER_PAGE * 2);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
@@ -97,13 +107,14 @@ export default class AddUsersToTeam extends React.Component {
|
||||
this.setState({values});
|
||||
}
|
||||
|
||||
onChange(force) {
|
||||
if (this.state.search && !force) {
|
||||
return;
|
||||
onChange() {
|
||||
let users;
|
||||
if (this.term) {
|
||||
users = Object.assign([], searchProfilesNotInCurrentTeam(store.getState(), this.term, true));
|
||||
} else {
|
||||
users = Object.assign([], UserStore.getProfileListNotInTeam(TeamStore.getCurrentId(), true));
|
||||
}
|
||||
|
||||
const users = Object.assign([], UserStore.getProfileListNotInTeam(TeamStore.getCurrentId(), true));
|
||||
|
||||
for (let i = 0; i < users.length; i++) {
|
||||
const user = Object.assign({}, users[i]);
|
||||
user.value = user.id;
|
||||
@@ -118,53 +129,25 @@ export default class AddUsersToTeam extends React.Component {
|
||||
|
||||
handlePageChange(page, prevPage) {
|
||||
if (page > prevPage) {
|
||||
AsyncClient.getProfilesNotInTeam((page + 1) * USERS_PER_PAGE, USERS_PER_PAGE);
|
||||
this.props.actions.getProfilesNotInTeam(TeamStore.getCurrentId(), page + 1, USERS_PER_PAGE);
|
||||
}
|
||||
}
|
||||
|
||||
search(term) {
|
||||
clearTimeout(this.searchTimeoutId);
|
||||
this.term = term;
|
||||
|
||||
if (term === '') {
|
||||
this.onChange(true);
|
||||
this.setState({search: false});
|
||||
this.searchTimeoutId = '';
|
||||
this.onChange();
|
||||
return;
|
||||
}
|
||||
|
||||
const teamId = TeamStore.getCurrentId();
|
||||
|
||||
const searchTimeoutId = setTimeout(
|
||||
this.searchTimeoutId = setTimeout(
|
||||
() => {
|
||||
searchUsersNotInTeam(
|
||||
term,
|
||||
teamId,
|
||||
{},
|
||||
(users) => {
|
||||
if (searchTimeoutId !== this.searchTimeoutId) {
|
||||
return;
|
||||
}
|
||||
|
||||
let indexToDelete = -1;
|
||||
for (let i = 0; i < users.length; i++) {
|
||||
if (users[i].id === UserStore.getCurrentId()) {
|
||||
indexToDelete = i;
|
||||
}
|
||||
users[i].value = users[i].id;
|
||||
users[i].label = '@' + users[i].username;
|
||||
}
|
||||
|
||||
if (indexToDelete !== -1) {
|
||||
users.splice(indexToDelete, 1);
|
||||
}
|
||||
this.setState({search: true, users});
|
||||
}
|
||||
);
|
||||
searchUsersNotInTeam(term, TeamStore.getCurrentId(), {});
|
||||
},
|
||||
Constants.SEARCH_TIMEOUT_MILLISECONDS
|
||||
);
|
||||
|
||||
this.searchTimeoutId = searchTimeoutId;
|
||||
}
|
||||
|
||||
handleDelete(values) {
|
||||
@@ -272,7 +255,3 @@ export default class AddUsersToTeam extends React.Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
AddUsersToTeam.propTypes = {
|
||||
onModalDismissed: React.PropTypes.func
|
||||
};
|
||||
24
webapp/components/add_users_to_team/index.js
Обычный файл
24
webapp/components/add_users_to_team/index.js
Обычный файл
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {getProfilesNotInTeam} from 'mattermost-redux/actions/users';
|
||||
|
||||
import AddUsersToTeam from './add_users_to_team.jsx';
|
||||
|
||||
function mapStateToProps(state, ownProps) {
|
||||
return {
|
||||
...ownProps
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
getProfilesNotInTeam
|
||||
}, dispatch)
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(AddUsersToTeam);
|
||||
@@ -23,6 +23,9 @@ import * as Utils from 'utils/utils.jsx';
|
||||
|
||||
import SystemUsersList from './system_users_list.jsx';
|
||||
|
||||
import store from 'stores/redux_store.jsx';
|
||||
import {searchProfiles, searchProfilesInTeam} from 'mattermost-redux/selectors/entities/users';
|
||||
|
||||
const ALL_USERS = '';
|
||||
const NO_TEAM = 'no_team';
|
||||
|
||||
@@ -120,25 +123,18 @@ export default class SystemUsers extends React.Component {
|
||||
|
||||
updateUsersFromStore(teamId = this.state.teamId, term = this.state.term) {
|
||||
if (term) {
|
||||
if (teamId === this.state.teamId) {
|
||||
// Search results aren't in the store, so manually update the users in them
|
||||
const users = [...this.state.users];
|
||||
|
||||
for (let i = 0; i < users.length; i++) {
|
||||
const user = users[i];
|
||||
|
||||
if (UserStore.hasProfile(user.id)) {
|
||||
users[i] = UserStore.getProfile(user.id);
|
||||
}
|
||||
}
|
||||
|
||||
this.setState({
|
||||
users
|
||||
});
|
||||
let users;
|
||||
if (teamId) {
|
||||
users = searchProfilesInTeam(store.getState(), teamId, term);
|
||||
} else {
|
||||
this.doSearch(teamId, term, true);
|
||||
users = searchProfiles(store.getState(), term);
|
||||
}
|
||||
|
||||
if (users.length === 0 && UserStore.hasProfile(term)) {
|
||||
users = [UserStore.getProfile(term)];
|
||||
}
|
||||
|
||||
this.setState({users});
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -179,11 +175,11 @@ export default class SystemUsers extends React.Component {
|
||||
// Paging isn't supported while searching
|
||||
|
||||
if (this.state.teamId === ALL_USERS) {
|
||||
loadProfiles((page + 1) * USERS_PER_PAGE, USERS_PER_PAGE, this.loadComplete);
|
||||
loadProfiles(page, USERS_PER_PAGE, this.loadComplete);
|
||||
} else if (this.state.teamId === NO_TEAM) {
|
||||
loadProfilesWithoutTeam(page + 1, USERS_PER_PAGE, this.loadComplete);
|
||||
} else {
|
||||
loadProfilesAndTeamMembers((page + 1) * USERS_PER_PAGE, USERS_PER_PAGE, this.state.teamId, this.loadComplete);
|
||||
loadProfilesAndTeamMembers(page + 1, USERS_PER_PAGE, this.state.teamId, this.loadComplete);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -204,11 +200,9 @@ export default class SystemUsers extends React.Component {
|
||||
|
||||
doSearch(teamId, term, now = false) {
|
||||
clearTimeout(this.searchTimeoutId);
|
||||
this.term = term;
|
||||
|
||||
this.setState({
|
||||
loading: true,
|
||||
users: []
|
||||
});
|
||||
this.setState({loading: true});
|
||||
|
||||
const options = {
|
||||
[UserSearchOptions.ALLOW_INACTIVE]: true
|
||||
@@ -217,74 +211,45 @@ export default class SystemUsers extends React.Component {
|
||||
options[UserSearchOptions.WITHOUT_TEAM] = true;
|
||||
}
|
||||
|
||||
const searchTimeoutId = setTimeout(
|
||||
this.searchTimeoutId = setTimeout(
|
||||
() => {
|
||||
searchUsers(
|
||||
term,
|
||||
teamId,
|
||||
options,
|
||||
(users) => {
|
||||
if (searchTimeoutId !== this.searchTimeoutId) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (users.length > 0) {
|
||||
this.setState({
|
||||
loading: false,
|
||||
users
|
||||
});
|
||||
} else if (term.length === USER_ID_LENGTH) {
|
||||
if (users.length === 0 && term.length === USER_ID_LENGTH) {
|
||||
// This term didn't match any users name, but it does look like it might be a user's ID
|
||||
this.getUserById(term, searchTimeoutId);
|
||||
this.getUserById(term);
|
||||
} else {
|
||||
this.setState({
|
||||
loading: false
|
||||
});
|
||||
this.setState({loading: false});
|
||||
}
|
||||
},
|
||||
() => {
|
||||
this.setState({
|
||||
loading: false
|
||||
});
|
||||
this.setState({loading: false});
|
||||
}
|
||||
);
|
||||
},
|
||||
now ? 0 : Constants.SEARCH_TIMEOUT_MILLISECONDS
|
||||
);
|
||||
|
||||
this.searchTimeoutId = searchTimeoutId;
|
||||
}
|
||||
|
||||
getUserById(id, searchTimeoutId) {
|
||||
getUserById(id) {
|
||||
if (UserStore.hasProfile(id)) {
|
||||
this.setState({
|
||||
loading: false,
|
||||
users: [UserStore.getProfile(id)]
|
||||
});
|
||||
|
||||
this.setState({loading: false});
|
||||
return;
|
||||
}
|
||||
|
||||
getUser(
|
||||
id,
|
||||
(user) => {
|
||||
if (searchTimeoutId !== this.searchTimeoutId) {
|
||||
return;
|
||||
}
|
||||
|
||||
() => {
|
||||
this.setState({
|
||||
loading: false,
|
||||
users: [user]
|
||||
loading: false
|
||||
});
|
||||
},
|
||||
() => {
|
||||
if (searchTimeoutId !== this.searchTimeoutId) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
loading: false,
|
||||
users: []
|
||||
loading: false
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -5,11 +5,11 @@ import $ from 'jquery';
|
||||
import 'bootstrap';
|
||||
import NavbarSearchBox from './search_bar.jsx';
|
||||
import MessageWrapper from './message_wrapper.jsx';
|
||||
import PopoverListMembers from './popover_list_members.jsx';
|
||||
import PopoverListMembers from 'components/popover_list_members';
|
||||
import EditChannelHeaderModal from './edit_channel_header_modal.jsx';
|
||||
import EditChannelPurposeModal from './edit_channel_purpose_modal.jsx';
|
||||
import ChannelInfoModal from './channel_info_modal.jsx';
|
||||
import ChannelInviteModal from './channel_invite_modal.jsx';
|
||||
import ChannelInviteModal from 'components/channel_invite_modal';
|
||||
import ChannelMembersModal from './channel_members_modal.jsx';
|
||||
import ChannelNotificationsModal from './channel_notifications_modal.jsx';
|
||||
import DeleteChannelModal from './delete_channel_modal.jsx';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import ChannelInviteButton from './channel_invite_button.jsx';
|
||||
import ChannelInviteButton from 'components/channel_invite_button.jsx';
|
||||
import SearchableUserList from 'components/searchable_user_list/searchable_user_list_container.jsx';
|
||||
import LoadingScreen from './loading_screen.jsx';
|
||||
import LoadingScreen from 'components/loading_screen.jsx';
|
||||
|
||||
import ChannelStore from 'stores/channel_store.jsx';
|
||||
import UserStore from 'stores/user_store.jsx';
|
||||
@@ -19,9 +19,20 @@ import React from 'react';
|
||||
import {Modal} from 'react-bootstrap';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
|
||||
import store from 'stores/redux_store.jsx';
|
||||
import {searchProfilesNotInCurrentChannel} from 'mattermost-redux/selectors/entities/users';
|
||||
|
||||
const USERS_PER_PAGE = 50;
|
||||
|
||||
export default class ChannelInviteModal extends React.Component {
|
||||
static propTypes = {
|
||||
onHide: React.PropTypes.func.isRequired,
|
||||
channel: React.PropTypes.object.isRequired,
|
||||
actions: React.PropTypes.shape({
|
||||
getProfilesNotInChannel: React.PropTypes.func.isRequired
|
||||
}).isRequired
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -39,10 +50,9 @@ export default class ChannelInviteModal extends React.Component {
|
||||
const teamStats = TeamStore.getCurrentStats();
|
||||
|
||||
this.state = {
|
||||
users: null,
|
||||
users: UserStore.getProfileListNotInChannel(props.channel.id, true),
|
||||
total: teamStats.active_member_count - channelStats.member_count,
|
||||
show: true,
|
||||
search: false,
|
||||
statusChange: false
|
||||
};
|
||||
}
|
||||
@@ -53,7 +63,7 @@ export default class ChannelInviteModal extends React.Component {
|
||||
UserStore.addNotInChannelChangeListener(this.onChange);
|
||||
UserStore.addStatusesChangeListener(this.onStatusChange);
|
||||
|
||||
AsyncClient.getProfilesNotInChannel(this.props.channel.id, 0);
|
||||
this.props.actions.getProfilesNotInChannel(TeamStore.getCurrentId(), this.props.channel.id, 0);
|
||||
AsyncClient.getTeamStats(TeamStore.getCurrentId());
|
||||
}
|
||||
|
||||
@@ -64,17 +74,19 @@ export default class ChannelInviteModal extends React.Component {
|
||||
UserStore.removeStatusesChangeListener(this.onStatusChange);
|
||||
}
|
||||
|
||||
onChange(force) {
|
||||
if (this.state.search && !force) {
|
||||
this.search(this.term);
|
||||
return;
|
||||
onChange() {
|
||||
let users;
|
||||
if (this.term) {
|
||||
users = searchProfilesNotInCurrentChannel(store.getState(), this.term, true);
|
||||
} else {
|
||||
users = UserStore.getProfileListNotInChannel(this.props.channel.id, true);
|
||||
}
|
||||
|
||||
const channelStats = ChannelStore.getStats(this.props.channel.id);
|
||||
const teamStats = TeamStore.getCurrentStats();
|
||||
|
||||
this.setState({
|
||||
users: UserStore.getProfileListNotInChannel(this.props.channel.id, true),
|
||||
users,
|
||||
total: teamStats.active_member_count - channelStats.member_count
|
||||
});
|
||||
}
|
||||
@@ -103,40 +115,24 @@ export default class ChannelInviteModal extends React.Component {
|
||||
}
|
||||
|
||||
nextPage(page) {
|
||||
AsyncClient.getProfilesNotInChannel(this.props.channel.id, (page + 1) * USERS_PER_PAGE, USERS_PER_PAGE);
|
||||
this.props.actions.getProfilesNotInChannel(TeamStore.getCurrentId(), this.props.channel.id, (page + 1) * USERS_PER_PAGE, USERS_PER_PAGE);
|
||||
}
|
||||
|
||||
search(term) {
|
||||
clearTimeout(this.searchTimeoutId);
|
||||
|
||||
this.term = term;
|
||||
|
||||
if (term === '') {
|
||||
this.onChange(true);
|
||||
this.setState({search: false});
|
||||
this.searchTimeoutId = '';
|
||||
this.onChange();
|
||||
return;
|
||||
}
|
||||
|
||||
const searchTimeoutId = setTimeout(
|
||||
this.searchTimeoutId = setTimeout(
|
||||
() => {
|
||||
searchUsers(
|
||||
term,
|
||||
TeamStore.getCurrentId(),
|
||||
{not_in_channel_id: this.props.channel.id},
|
||||
(users) => {
|
||||
if (searchTimeoutId !== this.searchTimeoutId) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({search: true, users});
|
||||
}
|
||||
);
|
||||
searchUsers(term, TeamStore.getCurrentId(), {not_in_channel_id: this.props.channel.id});
|
||||
},
|
||||
Constants.SEARCH_TIMEOUT_MILLISECONDS
|
||||
);
|
||||
|
||||
this.searchTimeoutId = searchTimeoutId;
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -190,8 +186,3 @@ export default class ChannelInviteModal extends React.Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
ChannelInviteModal.propTypes = {
|
||||
onHide: React.PropTypes.func.isRequired,
|
||||
channel: React.PropTypes.object.isRequired
|
||||
};
|
||||
24
webapp/components/channel_invite_modal/index.js
Обычный файл
24
webapp/components/channel_invite_modal/index.js
Обычный файл
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {getProfilesNotInChannel} from 'mattermost-redux/actions/users';
|
||||
|
||||
import ChannelInviteModal from './channel_invite_modal.jsx';
|
||||
|
||||
function mapStateToProps(state, ownProps) {
|
||||
return {
|
||||
...ownProps
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
getProfilesNotInChannel
|
||||
}, dispatch)
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(ChannelInviteModal);
|
||||
@@ -209,19 +209,15 @@ export default class LoginController extends React.Component {
|
||||
}
|
||||
|
||||
finishSignin(team) {
|
||||
GlobalActions.emitInitialLoad(
|
||||
() => {
|
||||
const query = this.props.location.query;
|
||||
GlobalActions.loadDefaultLocale();
|
||||
if (query.redirect_to) {
|
||||
browserHistory.push(query.redirect_to);
|
||||
} else if (team) {
|
||||
browserHistory.push(`/${team.name}`);
|
||||
} else {
|
||||
GlobalActions.redirectUserToDefaultTeam();
|
||||
}
|
||||
}
|
||||
);
|
||||
const query = this.props.location.query;
|
||||
GlobalActions.loadDefaultLocale();
|
||||
if (query.redirect_to) {
|
||||
browserHistory.push(query.redirect_to);
|
||||
} else if (team) {
|
||||
browserHistory.push(`/${team.name}`);
|
||||
} else {
|
||||
GlobalActions.redirectUserToDefaultTeam();
|
||||
}
|
||||
}
|
||||
|
||||
handleLoginIdChange(e) {
|
||||
|
||||
@@ -17,6 +17,9 @@ import * as UserAgent from 'utils/user_agent.jsx';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import store from 'stores/redux_store.jsx';
|
||||
import {searchProfilesInCurrentChannel} from 'mattermost-redux/selectors/entities/users';
|
||||
|
||||
const USERS_PER_PAGE = 50;
|
||||
|
||||
export default class MemberListChannel extends React.Component {
|
||||
@@ -29,6 +32,7 @@ export default class MemberListChannel extends React.Component {
|
||||
this.loadComplete = this.loadComplete.bind(this);
|
||||
|
||||
this.searchTimeoutId = 0;
|
||||
this.term = '';
|
||||
|
||||
const stats = ChannelStore.getCurrentStats();
|
||||
|
||||
@@ -37,8 +41,6 @@ export default class MemberListChannel extends React.Component {
|
||||
teamMembers: Object.assign({}, TeamStore.getMembersInTeam()),
|
||||
channelMembers: Object.assign({}, ChannelStore.getMembersInChannel()),
|
||||
total: stats.member_count,
|
||||
search: false,
|
||||
term: '',
|
||||
loading: true
|
||||
};
|
||||
}
|
||||
@@ -66,16 +68,16 @@ export default class MemberListChannel extends React.Component {
|
||||
this.setState({loading: false});
|
||||
}
|
||||
|
||||
onChange(force) {
|
||||
if (this.state.search && !force) {
|
||||
return;
|
||||
} else if (this.state.search) {
|
||||
this.search(this.state.term);
|
||||
return;
|
||||
onChange() {
|
||||
let users;
|
||||
if (this.term) {
|
||||
users = searchProfilesInCurrentChannel(store.getState(), this.term);
|
||||
} else {
|
||||
users = UserStore.getProfileListInChannel();
|
||||
}
|
||||
|
||||
this.setState({
|
||||
users: UserStore.getProfileListInChannel(),
|
||||
users,
|
||||
teamMembers: Object.assign({}, TeamStore.getMembersInTeam()),
|
||||
channelMembers: Object.assign({}, ChannelStore.getMembersInChannel())
|
||||
});
|
||||
@@ -87,43 +89,30 @@ export default class MemberListChannel extends React.Component {
|
||||
}
|
||||
|
||||
nextPage(page) {
|
||||
loadProfilesAndTeamMembersAndChannelMembers((page + 1) * USERS_PER_PAGE, USERS_PER_PAGE);
|
||||
loadProfilesAndTeamMembersAndChannelMembers(page + 1, USERS_PER_PAGE);
|
||||
}
|
||||
|
||||
search(term) {
|
||||
clearTimeout(this.searchTimeoutId);
|
||||
this.term = term;
|
||||
|
||||
if (term === '') {
|
||||
this.setState({
|
||||
search: false,
|
||||
term,
|
||||
users: UserStore.getProfileListInChannel(),
|
||||
teamMembers: Object.assign([], TeamStore.getMembersInTeam()),
|
||||
channelMembers: Object.assign([], ChannelStore.getMembersInChannel())
|
||||
});
|
||||
this.setState({loading: false});
|
||||
this.searchTimeoutId = '';
|
||||
this.onChange();
|
||||
return;
|
||||
}
|
||||
|
||||
const searchTimeoutId = setTimeout(
|
||||
() => {
|
||||
searchUsers(
|
||||
term,
|
||||
TeamStore.getCurrentId(),
|
||||
{},
|
||||
searchUsers(term, TeamStore.getCurrentId(), {},
|
||||
(users) => {
|
||||
if (searchTimeoutId !== this.searchTimeoutId) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
loading: true,
|
||||
search: true,
|
||||
users,
|
||||
term,
|
||||
teamMembers: Object.assign([], TeamStore.getMembersInTeam()),
|
||||
channelMembers: Object.assign([], ChannelStore.getMembersInChannel())
|
||||
});
|
||||
this.setState({loading: true});
|
||||
|
||||
loadTeamMembersAndChannelMembersForProfilesList(users, TeamStore.getCurrentId(), ChannelStore.getCurrentId(), this.loadComplete);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// See License.txt for license information.
|
||||
|
||||
import SearchableUserList from 'components/searchable_user_list/searchable_user_list_container.jsx';
|
||||
import TeamMembersDropdown from 'components/team_members_dropdown.jsx';
|
||||
import TeamMembersDropdown from 'components/team_members_dropdown';
|
||||
|
||||
import UserStore from 'stores/user_store.jsx';
|
||||
import TeamStore from 'stores/team_store.jsx';
|
||||
@@ -16,6 +16,9 @@ import * as UserAgent from 'utils/user_agent.jsx';
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import store from 'stores/redux_store.jsx';
|
||||
import {searchProfilesInCurrentTeam} from 'mattermost-redux/selectors/entities/users';
|
||||
|
||||
const USERS_PER_PAGE = 50;
|
||||
|
||||
export default class MemberListTeam extends React.Component {
|
||||
@@ -29,6 +32,7 @@ export default class MemberListTeam extends React.Component {
|
||||
this.loadComplete = this.loadComplete.bind(this);
|
||||
|
||||
this.searchTimeoutId = 0;
|
||||
this.term = '';
|
||||
|
||||
const stats = TeamStore.getCurrentStats();
|
||||
|
||||
@@ -36,8 +40,6 @@ export default class MemberListTeam extends React.Component {
|
||||
users: UserStore.getProfileListInTeam(),
|
||||
teamMembers: Object.assign([], TeamStore.getMembersInTeam()),
|
||||
total: stats.total_member_count,
|
||||
search: false,
|
||||
term: '',
|
||||
loading: true
|
||||
};
|
||||
}
|
||||
@@ -67,15 +69,15 @@ export default class MemberListTeam extends React.Component {
|
||||
this.onChange(true);
|
||||
}
|
||||
|
||||
onChange(force) {
|
||||
if (this.state.search && !force) {
|
||||
return;
|
||||
} else if (this.state.search) {
|
||||
this.search(this.state.term);
|
||||
return;
|
||||
onChange() {
|
||||
let users;
|
||||
if (this.term) {
|
||||
users = searchProfilesInCurrentTeam(store.getState(), this.term);
|
||||
} else {
|
||||
users = UserStore.getProfileListInTeam();
|
||||
}
|
||||
|
||||
this.setState({users: UserStore.getProfileListInTeam(), teamMembers: Object.assign([], TeamStore.getMembersInTeam())});
|
||||
this.setState({users, teamMembers: Object.assign([], TeamStore.getMembersInTeam())});
|
||||
}
|
||||
|
||||
onStatsChange() {
|
||||
@@ -84,15 +86,17 @@ export default class MemberListTeam extends React.Component {
|
||||
}
|
||||
|
||||
nextPage(page) {
|
||||
loadProfilesAndTeamMembers((page + 1) * USERS_PER_PAGE, USERS_PER_PAGE);
|
||||
loadProfilesAndTeamMembers(page, USERS_PER_PAGE);
|
||||
}
|
||||
|
||||
search(term) {
|
||||
clearTimeout(this.searchTimeoutId);
|
||||
this.term = term;
|
||||
|
||||
if (term === '') {
|
||||
this.setState({search: false, term, users: UserStore.getProfileListInTeam(), teamMembers: Object.assign([], TeamStore.getMembersInTeam())});
|
||||
this.setState({loading: false});
|
||||
this.searchTimeoutId = '';
|
||||
this.onChange();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -106,7 +110,7 @@ export default class MemberListTeam extends React.Component {
|
||||
if (searchTimeoutId !== this.searchTimeoutId) {
|
||||
return;
|
||||
}
|
||||
this.setState({loading: true, search: true, users, term, teamMembers: Object.assign([], TeamStore.getMembersInTeam())});
|
||||
this.setState({loading: true});
|
||||
loadTeamMembersForProfilesList(users, TeamStore.getCurrentId(), this.loadComplete);
|
||||
}
|
||||
);
|
||||
|
||||
25
webapp/components/more_direct_channels/index.js
Обычный файл
25
webapp/components/more_direct_channels/index.js
Обычный файл
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {getProfiles, getProfilesInTeam} from 'mattermost-redux/actions/users';
|
||||
|
||||
import MoreDirectChannels from './more_direct_channels.jsx';
|
||||
|
||||
function mapStateToProps(state, ownProps) {
|
||||
return {
|
||||
...ownProps
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
getProfiles,
|
||||
getProfilesInTeam
|
||||
}, dispatch)
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(MoreDirectChannels);
|
||||
@@ -10,7 +10,6 @@ import {openDirectChannelToUser, openGroupChannelToUsers} from 'actions/channel_
|
||||
import UserStore from 'stores/user_store.jsx';
|
||||
import TeamStore from 'stores/team_store.jsx';
|
||||
|
||||
import * as AsyncClient from 'utils/async_client.jsx';
|
||||
import Constants from 'utils/constants.jsx';
|
||||
import {displayUsernameForUser} from 'utils/utils.jsx';
|
||||
import Client from 'client/web_client.jsx';
|
||||
@@ -20,10 +19,22 @@ import {Modal} from 'react-bootstrap';
|
||||
import {FormattedMessage} from 'react-intl';
|
||||
import {browserHistory} from 'react-router/es6';
|
||||
|
||||
import store from 'stores/redux_store.jsx';
|
||||
import {searchProfiles, searchProfilesInCurrentTeam} from 'mattermost-redux/selectors/entities/users';
|
||||
|
||||
const USERS_PER_PAGE = 50;
|
||||
const MAX_SELECTABLE_VALUES = Constants.MAX_USERS_IN_GM - 1;
|
||||
|
||||
export default class MoreDirectChannels extends React.Component {
|
||||
static propTypes = {
|
||||
startingUsers: React.PropTypes.arrayOf(React.PropTypes.object),
|
||||
onModalDismissed: React.PropTypes.func,
|
||||
actions: React.PropTypes.shape({
|
||||
getProfiles: React.PropTypes.func.isRequired,
|
||||
getProfilesInTeam: React.PropTypes.func.isRequired
|
||||
}).isRequired
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -36,6 +47,7 @@ export default class MoreDirectChannels extends React.Component {
|
||||
this.addValue = this.addValue.bind(this);
|
||||
|
||||
this.searchTimeoutId = 0;
|
||||
this.term = '';
|
||||
this.listType = global.window.mm_config.RestrictDirectMessage;
|
||||
|
||||
const values = [];
|
||||
@@ -63,9 +75,9 @@ export default class MoreDirectChannels extends React.Component {
|
||||
UserStore.addStatusesChangeListener(this.onChange);
|
||||
|
||||
if (this.listType === 'any') {
|
||||
AsyncClient.getProfiles(0, USERS_PER_PAGE * 2);
|
||||
this.props.actions.getProfiles(0, USERS_PER_PAGE * 2);
|
||||
} else {
|
||||
AsyncClient.getProfilesInTeam(TeamStore.getCurrentId(), 0, USERS_PER_PAGE * 2);
|
||||
this.props.actions.getProfilesInTeam(TeamStore.getCurrentId(), 0, USERS_PER_PAGE * 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -134,13 +146,15 @@ export default class MoreDirectChannels extends React.Component {
|
||||
this.setState({values});
|
||||
}
|
||||
|
||||
onChange(force) {
|
||||
if (this.state.search && !force) {
|
||||
return;
|
||||
}
|
||||
|
||||
onChange() {
|
||||
let users;
|
||||
if (this.listType === 'any') {
|
||||
if (this.term) {
|
||||
if (this.listType === 'any') {
|
||||
users = Object.assign([], searchProfiles(store.getState(), this.term, true));
|
||||
} else {
|
||||
users = Object.assign([], searchProfilesInCurrentTeam(store.getState(), this.term, true));
|
||||
}
|
||||
} else if (this.listType === 'any') {
|
||||
users = Object.assign([], UserStore.getProfileList(true));
|
||||
} else {
|
||||
users = Object.assign([], UserStore.getProfileListInTeam(TeamStore.getCurrentId(), true));
|
||||
@@ -160,17 +174,20 @@ export default class MoreDirectChannels extends React.Component {
|
||||
|
||||
handlePageChange(page, prevPage) {
|
||||
if (page > prevPage) {
|
||||
AsyncClient.getProfiles((page + 1) * USERS_PER_PAGE, USERS_PER_PAGE);
|
||||
if (this.listType === 'any') {
|
||||
this.props.actions.getProfiles(page + 1, USERS_PER_PAGE);
|
||||
} else {
|
||||
this.props.actions.getProfilesInTeam(page + 1, USERS_PER_PAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
search(term) {
|
||||
clearTimeout(this.searchTimeoutId);
|
||||
this.term = term;
|
||||
|
||||
if (term === '') {
|
||||
this.onChange(true);
|
||||
this.setState({search: false});
|
||||
this.searchTimeoutId = '';
|
||||
this.onChange();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -181,37 +198,12 @@ export default class MoreDirectChannels extends React.Component {
|
||||
teamId = TeamStore.getCurrentId();
|
||||
}
|
||||
|
||||
const searchTimeoutId = setTimeout(
|
||||
this.searchTimeoutId = setTimeout(
|
||||
() => {
|
||||
searchUsers(
|
||||
term,
|
||||
teamId,
|
||||
{},
|
||||
(users) => {
|
||||
if (searchTimeoutId !== this.searchTimeoutId) {
|
||||
return;
|
||||
}
|
||||
|
||||
let indexToDelete = -1;
|
||||
for (let i = 0; i < users.length; i++) {
|
||||
if (users[i].id === UserStore.getCurrentId()) {
|
||||
indexToDelete = i;
|
||||
}
|
||||
users[i].value = users[i].id;
|
||||
users[i].label = '@' + users[i].username;
|
||||
}
|
||||
|
||||
if (indexToDelete !== -1) {
|
||||
users.splice(indexToDelete, 1);
|
||||
}
|
||||
this.setState({search: true, users});
|
||||
}
|
||||
);
|
||||
searchUsers(term, teamId);
|
||||
},
|
||||
Constants.SEARCH_TIMEOUT_MILLISECONDS
|
||||
);
|
||||
|
||||
this.searchTimeoutId = searchTimeoutId;
|
||||
}
|
||||
|
||||
handleDelete(values) {
|
||||
@@ -334,8 +326,3 @@ export default class MoreDirectChannels extends React.Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
MoreDirectChannels.propTypes = {
|
||||
startingUsers: React.PropTypes.arrayOf(React.PropTypes.object),
|
||||
onModalDismissed: React.PropTypes.func
|
||||
};
|
||||
@@ -7,7 +7,7 @@ import EditChannelPurposeModal from './edit_channel_purpose_modal.jsx';
|
||||
import MessageWrapper from './message_wrapper.jsx';
|
||||
import NotifyCounts from './notify_counts.jsx';
|
||||
import ChannelInfoModal from './channel_info_modal.jsx';
|
||||
import ChannelInviteModal from './channel_invite_modal.jsx';
|
||||
import ChannelInviteModal from 'components/channel_invite_modal';
|
||||
import ChannelMembersModal from './channel_members_modal.jsx';
|
||||
import ChannelNotificationsModal from './channel_notifications_modal.jsx';
|
||||
import DeleteChannelModal from './delete_channel_modal.jsx';
|
||||
|
||||
24
webapp/components/popover_list_members/index.js
Обычный файл
24
webapp/components/popover_list_members/index.js
Обычный файл
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {getProfilesInChannel} from 'mattermost-redux/actions/users';
|
||||
|
||||
import PopoverListMembers from './popover_list_members.jsx';
|
||||
|
||||
function mapStateToProps(state, ownProps) {
|
||||
return {
|
||||
...ownProps
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
getProfilesInChannel
|
||||
}, dispatch)
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(PopoverListMembers);
|
||||
@@ -7,13 +7,12 @@ import TeamStore from 'stores/team_store.jsx';
|
||||
import UserStore from 'stores/user_store.jsx';
|
||||
import ChannelStore from 'stores/channel_store.jsx';
|
||||
|
||||
import TeamMembersModal from './team_members_modal.jsx';
|
||||
import ChannelMembersModal from './channel_members_modal.jsx';
|
||||
import ChannelInviteModal from './channel_invite_modal.jsx';
|
||||
import TeamMembersModal from 'components/team_members_modal.jsx';
|
||||
import ChannelMembersModal from 'components/channel_members_modal.jsx';
|
||||
import ChannelInviteModal from 'components/channel_invite_modal';
|
||||
|
||||
import {openDirectChannelToUser} from 'actions/channel_actions.jsx';
|
||||
|
||||
import * as AsyncClient from 'utils/async_client.jsx';
|
||||
import Client from 'client/web_client.jsx';
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
import Constants from 'utils/constants.jsx';
|
||||
@@ -26,6 +25,15 @@ import {FormattedMessage} from 'react-intl';
|
||||
import {browserHistory} from 'react-router/es6';
|
||||
|
||||
export default class PopoverListMembers extends React.Component {
|
||||
static propTypes = {
|
||||
channel: React.PropTypes.object.isRequired,
|
||||
members: React.PropTypes.array.isRequired,
|
||||
memberCount: React.PropTypes.number,
|
||||
actions: React.PropTypes.shape({
|
||||
getProfilesInChannel: React.PropTypes.func.isRequired
|
||||
}).isRequired
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -239,7 +247,7 @@ export default class PopoverListMembers extends React.Component {
|
||||
ref='member_popover_target'
|
||||
onClick={(e) => {
|
||||
this.setState({popoverTarget: e.target, showPopover: !this.state.showPopover});
|
||||
AsyncClient.getProfilesInChannel(this.props.channel.id, 0);
|
||||
this.props.actions.getProfilesInChannel(this.props.channel.id, 0);
|
||||
}}
|
||||
>
|
||||
{countText}
|
||||
@@ -272,8 +280,3 @@ export default class PopoverListMembers extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
PopoverListMembers.propTypes = {
|
||||
channel: React.PropTypes.object.isRequired,
|
||||
members: React.PropTypes.array.isRequired,
|
||||
memberCount: React.PropTypes.number
|
||||
};
|
||||
@@ -136,6 +136,7 @@ export default class Root extends React.Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Root.defaultProps = {
|
||||
};
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
import $ from 'jquery';
|
||||
import ReactDOM from 'react-dom';
|
||||
import NewChannelFlow from './new_channel_flow.jsx';
|
||||
import MoreDirectChannels from './more_direct_channels.jsx';
|
||||
import MoreDirectChannels from 'components/more_direct_channels';
|
||||
import MoreChannels from 'components/more_channels.jsx';
|
||||
import SidebarHeader from './sidebar_header.jsx';
|
||||
import UnreadChannelIndicator from './unread_channel_indicator.jsx';
|
||||
|
||||
@@ -14,7 +14,7 @@ import AboutBuildModal from './about_build_modal.jsx';
|
||||
import SidebarHeaderDropdownButton from './sidebar_header_dropdown_button.jsx';
|
||||
import TeamMembersModal from './team_members_modal.jsx';
|
||||
import UserSettingsModal from './user_settings/user_settings_modal.jsx';
|
||||
import AddUsersToTeam from './add_users_to_team.jsx';
|
||||
import AddUsersToTeam from 'components/add_users_to_team';
|
||||
|
||||
import {Constants, WebrtcActionTypes} from 'utils/constants.jsx';
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import TeamMembersModal from './team_members_modal.jsx';
|
||||
import ToggleModalButton from './toggle_modal_button.jsx';
|
||||
import UserSettingsModal from './user_settings/user_settings_modal.jsx';
|
||||
import AboutBuildModal from './about_build_modal.jsx';
|
||||
import AddUsersToTeam from './add_users_to_team.jsx';
|
||||
import AddUsersToTeam from 'components/add_users_to_team';
|
||||
|
||||
import UserStore from 'stores/user_store.jsx';
|
||||
import TeamStore from 'stores/team_store.jsx';
|
||||
|
||||
@@ -8,7 +8,7 @@ import {trackEvent} from 'actions/diagnostics_actions.jsx';
|
||||
|
||||
import BrowserStore from 'stores/browser_store.jsx';
|
||||
import {getInviteInfo} from 'actions/team_actions.jsx';
|
||||
import {loginById, createUserWithInvite} from 'actions/user_actions.jsx';
|
||||
import {loadMe, loginById, createUserWithInvite} from 'actions/user_actions.jsx';
|
||||
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
import Constants from 'utils/constants.jsx';
|
||||
@@ -108,7 +108,7 @@ export default class SignupEmail extends React.Component {
|
||||
}
|
||||
|
||||
finishSignup() {
|
||||
GlobalActions.emitInitialLoad(
|
||||
loadMe(
|
||||
() => {
|
||||
const query = this.props.location.query;
|
||||
GlobalActions.loadDefaultLocale();
|
||||
@@ -132,7 +132,7 @@ export default class SignupEmail extends React.Component {
|
||||
BrowserStore.setGlobalItem(this.state.hash, JSON.stringify({usedBefore: true}));
|
||||
}
|
||||
|
||||
GlobalActions.emitInitialLoad(
|
||||
loadMe(
|
||||
() => {
|
||||
const query = this.props.location.query;
|
||||
if (query.redirect_to) {
|
||||
|
||||
@@ -5,7 +5,7 @@ import FormError from 'components/form_error.jsx';
|
||||
|
||||
import * as GlobalActions from 'actions/global_actions.jsx';
|
||||
import {addUserToTeamFromInvite} from 'actions/team_actions.jsx';
|
||||
import {webLoginByLdap} from 'actions/user_actions.jsx';
|
||||
import {loadMe, webLoginByLdap} from 'actions/user_actions.jsx';
|
||||
import {trackEvent} from 'actions/diagnostics_actions.jsx';
|
||||
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
@@ -97,7 +97,7 @@ export default class SignupLdap extends React.Component {
|
||||
}
|
||||
|
||||
finishSignup() {
|
||||
GlobalActions.emitInitialLoad(
|
||||
loadMe(
|
||||
() => {
|
||||
const query = this.props.location.query;
|
||||
GlobalActions.loadDefaultLocale();
|
||||
|
||||
@@ -13,6 +13,7 @@ import * as AsyncClient from 'utils/async_client.jsx';
|
||||
import Client from 'client/web_client.jsx';
|
||||
import * as GlobalActions from 'actions/global_actions.jsx';
|
||||
import {addUserToTeamFromInvite, getInviteInfo} from 'actions/team_actions.jsx';
|
||||
import {loadMe} from 'actions/user_actions.jsx';
|
||||
|
||||
import logoImage from 'images/logo.png';
|
||||
import ErrorBar from 'components/error_bar.jsx';
|
||||
@@ -74,7 +75,7 @@ export default class SignupController extends React.Component {
|
||||
hash,
|
||||
inviteId,
|
||||
(team) => {
|
||||
GlobalActions.emitInitialLoad(
|
||||
loadMe(
|
||||
() => {
|
||||
browserHistory.push('/' + team.name + '/channels/town-square');
|
||||
}
|
||||
|
||||
@@ -127,14 +127,14 @@ export default class AtMentionProvider extends Provider {
|
||||
return;
|
||||
}
|
||||
|
||||
const members = data.in_channel;
|
||||
const members = Object.assign([], data.users);
|
||||
for (const id of Object.keys(members)) {
|
||||
members[id].type = Constants.MENTION_MEMBERS;
|
||||
members[id] = {...members[id], type: Constants.MENTION_MEMBERS};
|
||||
}
|
||||
|
||||
const nonmembers = data.out_of_channel;
|
||||
const nonmembers = data.out_of_channel || [];
|
||||
for (const id of Object.keys(nonmembers)) {
|
||||
nonmembers[id].type = Constants.MENTION_NONMEMBERS;
|
||||
nonmembers[id] = {...nonmembers[id], type: Constants.MENTION_NONMEMBERS};
|
||||
}
|
||||
|
||||
let specialMentions = [];
|
||||
|
||||
@@ -72,7 +72,7 @@ export default class SearchUserProvider extends Provider {
|
||||
return;
|
||||
}
|
||||
|
||||
const users = data.in_team;
|
||||
const users = Object.assign([], data.users);
|
||||
const mentions = users.map((user) => user.username);
|
||||
|
||||
AppDispatcher.handleServerAction({
|
||||
|
||||
@@ -67,7 +67,9 @@ export default class SwitchChannelProvider extends Provider {
|
||||
|
||||
autocompleteUsers(
|
||||
channelPrefix,
|
||||
(users) => {
|
||||
(data) => {
|
||||
const users = Object.assign([], data.users);
|
||||
|
||||
if (this.shouldCancelDispatch(channelPrefix)) {
|
||||
return;
|
||||
}
|
||||
|
||||
24
webapp/components/team_members_dropdown/index.js
Обычный файл
24
webapp/components/team_members_dropdown/index.js
Обычный файл
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {getUser} from 'mattermost-redux/actions/users';
|
||||
|
||||
import TeamMembersDropdown from './team_members_dropdown.jsx';
|
||||
|
||||
function mapStateToProps(state, ownProps) {
|
||||
return {
|
||||
...ownProps
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
getUser
|
||||
}, dispatch)
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(TeamMembersDropdown);
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import ConfirmModal from './confirm_modal.jsx';
|
||||
import ConfirmModal from 'components/confirm_modal.jsx';
|
||||
|
||||
import TeamStore from 'stores/team_store.jsx';
|
||||
import UserStore from 'stores/user_store.jsx';
|
||||
@@ -18,6 +18,14 @@ import {FormattedMessage} from 'react-intl';
|
||||
import {browserHistory} from 'react-router/es6';
|
||||
|
||||
export default class TeamMembersDropdown extends React.Component {
|
||||
static propTypes = {
|
||||
user: React.PropTypes.object.isRequired,
|
||||
teamMember: React.PropTypes.object.isRequired,
|
||||
actions: React.PropTypes.shape({
|
||||
getUser: React.PropTypes.func.isRequired
|
||||
}).isRequired
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -48,7 +56,7 @@ export default class TeamMembersDropdown extends React.Component {
|
||||
this.props.user.id,
|
||||
'team_user',
|
||||
() => {
|
||||
AsyncClient.getUser(this.props.user.id);
|
||||
this.props.actions.getUser(this.props.user.id);
|
||||
|
||||
if (this.props.user.id === me.id) {
|
||||
loadMyTeamMembers();
|
||||
@@ -110,7 +118,7 @@ export default class TeamMembersDropdown extends React.Component {
|
||||
this.props.user.id,
|
||||
'team_user team_admin',
|
||||
() => {
|
||||
AsyncClient.getUser(this.props.user.id);
|
||||
this.props.actions.getUser(this.props.user.id);
|
||||
},
|
||||
(err) => {
|
||||
this.setState({serverError: err.message});
|
||||
@@ -145,7 +153,7 @@ export default class TeamMembersDropdown extends React.Component {
|
||||
this.props.user.id,
|
||||
this.state.newRole,
|
||||
() => {
|
||||
AsyncClient.getUser(this.props.user.id);
|
||||
this.props.actions.getUser(this.props.user.id);
|
||||
|
||||
const teamUrl = TeamStore.getCurrentTeamUrl();
|
||||
if (teamUrl) {
|
||||
@@ -385,8 +393,3 @@ export default class TeamMembersDropdown extends React.Component {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
TeamMembersDropdown.propTypes = {
|
||||
user: React.PropTypes.object.isRequired,
|
||||
teamMember: React.PropTypes.object.isRequired
|
||||
};
|
||||
@@ -4,8 +4,8 @@
|
||||
import UserStore from 'stores/user_store.jsx';
|
||||
import * as utils from 'utils/utils.jsx';
|
||||
import NotificationsTab from './user_settings_notifications.jsx';
|
||||
import SecurityTab from './user_settings_security.jsx';
|
||||
import GeneralTab from './user_settings_general.jsx';
|
||||
import SecurityTab from './user_settings_security';
|
||||
import GeneralTab from './user_settings_general';
|
||||
import DisplayTab from './user_settings_display.jsx';
|
||||
import AdvancedTab from './user_settings_advanced.jsx';
|
||||
|
||||
|
||||
24
webapp/components/user_settings/user_settings_general/index.js
Обычный файл
24
webapp/components/user_settings/user_settings_general/index.js
Обычный файл
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {getMe} from 'mattermost-redux/actions/users';
|
||||
|
||||
import UserSettingsGeneralTab from './user_settings_general.jsx';
|
||||
|
||||
function mapStateToProps(state, ownProps) {
|
||||
return {
|
||||
...ownProps
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
getMe
|
||||
}, dispatch)
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(UserSettingsGeneralTab);
|
||||
@@ -2,16 +2,15 @@
|
||||
// See License.txt for license information.
|
||||
|
||||
import $ from 'jquery';
|
||||
import SettingItemMin from '../setting_item_min.jsx';
|
||||
import SettingItemMax from '../setting_item_max.jsx';
|
||||
import SettingPicture from '../setting_picture.jsx';
|
||||
import SettingItemMin from 'components/setting_item_min.jsx';
|
||||
import SettingItemMax from 'components/setting_item_max.jsx';
|
||||
import SettingPicture from 'components/setting_picture.jsx';
|
||||
|
||||
import UserStore from 'stores/user_store.jsx';
|
||||
import ErrorStore from 'stores/error_store.jsx';
|
||||
|
||||
import Client from 'client/web_client.jsx';
|
||||
import Constants from 'utils/constants.jsx';
|
||||
import * as AsyncClient from 'utils/async_client.jsx';
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
|
||||
import {intlShape, injectIntl, defineMessages, FormattedMessage, FormattedHTMLMessage, FormattedDate} from 'react-intl';
|
||||
@@ -80,6 +79,19 @@ const holders = defineMessages({
|
||||
import React from 'react';
|
||||
|
||||
class UserSettingsGeneralTab extends React.Component {
|
||||
static propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
user: React.PropTypes.object.isRequired,
|
||||
updateSection: React.PropTypes.func.isRequired,
|
||||
updateTab: React.PropTypes.func.isRequired,
|
||||
activeSection: React.PropTypes.string.isRequired,
|
||||
closeModal: React.PropTypes.func.isRequired,
|
||||
collapseModal: React.PropTypes.func.isRequired,
|
||||
actions: React.PropTypes.shape({
|
||||
getMe: React.PropTypes.func.isRequired
|
||||
}).isRequired
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.submitActive = false;
|
||||
@@ -205,7 +217,7 @@ class UserSettingsGeneralTab extends React.Component {
|
||||
updateUser(user, type,
|
||||
() => {
|
||||
this.updateSection('');
|
||||
AsyncClient.getMe();
|
||||
this.props.actions.getMe();
|
||||
const verificationEnabled = global.window.mm_config.SendEmailNotifications === 'true' && global.window.mm_config.RequireEmailVerification === 'true' && emailUpdated;
|
||||
|
||||
if (verificationEnabled) {
|
||||
@@ -1194,14 +1206,4 @@ class UserSettingsGeneralTab extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
UserSettingsGeneralTab.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
user: React.PropTypes.object.isRequired,
|
||||
updateSection: React.PropTypes.func.isRequired,
|
||||
updateTab: React.PropTypes.func.isRequired,
|
||||
activeSection: React.PropTypes.string.isRequired,
|
||||
closeModal: React.PropTypes.func.isRequired,
|
||||
collapseModal: React.PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default injectIntl(UserSettingsGeneralTab);
|
||||
24
webapp/components/user_settings/user_settings_security/index.js
Обычный файл
24
webapp/components/user_settings/user_settings_security/index.js
Обычный файл
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {connect} from 'react-redux';
|
||||
import {bindActionCreators} from 'redux';
|
||||
import {getMe} from 'mattermost-redux/actions/users';
|
||||
|
||||
import SecurityTab from './user_settings_security.jsx';
|
||||
|
||||
function mapStateToProps(state, ownProps) {
|
||||
return {
|
||||
...ownProps
|
||||
};
|
||||
}
|
||||
|
||||
function mapDispatchToProps(dispatch) {
|
||||
return {
|
||||
actions: bindActionCreators({
|
||||
getMe
|
||||
}, dispatch)
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(SecurityTab);
|
||||
@@ -1,15 +1,14 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import SettingItemMin from '../setting_item_min.jsx';
|
||||
import SettingItemMax from '../setting_item_max.jsx';
|
||||
import AccessHistoryModal from '../access_history_modal.jsx';
|
||||
import ActivityLogModal from '../activity_log_modal.jsx';
|
||||
import ToggleModalButton from '../toggle_modal_button.jsx';
|
||||
import SettingItemMin from 'components/setting_item_min.jsx';
|
||||
import SettingItemMax from 'components/setting_item_max.jsx';
|
||||
import AccessHistoryModal from 'components/access_history_modal';
|
||||
import ActivityLogModal from 'components/activity_log_modal';
|
||||
import ToggleModalButton from 'components/toggle_modal_button.jsx';
|
||||
|
||||
import PreferenceStore from 'stores/preference_store.jsx';
|
||||
|
||||
import * as AsyncClient from 'utils/async_client.jsx';
|
||||
import * as Utils from 'utils/utils.jsx';
|
||||
import Constants from 'utils/constants.jsx';
|
||||
|
||||
@@ -23,6 +22,19 @@ import {browserHistory, Link} from 'react-router/es6';
|
||||
import icon50 from 'images/icon50x50.png';
|
||||
|
||||
export default class SecurityTab extends React.Component {
|
||||
static propTypes = {
|
||||
user: React.PropTypes.object,
|
||||
activeSection: React.PropTypes.string,
|
||||
updateSection: React.PropTypes.func,
|
||||
updateTab: React.PropTypes.func,
|
||||
closeModal: React.PropTypes.func.isRequired,
|
||||
collapseModal: React.PropTypes.func.isRequired,
|
||||
setEnforceFocus: React.PropTypes.func.isRequired,
|
||||
actions: React.PropTypes.shape({
|
||||
getMe: React.PropTypes.func.isRequired
|
||||
}).isRequired
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
@@ -98,7 +110,7 @@ export default class SecurityTab extends React.Component {
|
||||
newPassword,
|
||||
() => {
|
||||
this.props.updateSection('');
|
||||
AsyncClient.getMe();
|
||||
this.props.actions.getMe();
|
||||
this.setState(this.getDefaultState());
|
||||
},
|
||||
(err) => {
|
||||
@@ -1022,12 +1034,3 @@ SecurityTab.defaultProps = {
|
||||
user: {},
|
||||
activeSection: ''
|
||||
};
|
||||
SecurityTab.propTypes = {
|
||||
user: React.PropTypes.object,
|
||||
activeSection: React.PropTypes.string,
|
||||
updateSection: React.PropTypes.func,
|
||||
updateTab: React.PropTypes.func,
|
||||
closeModal: React.PropTypes.func.isRequired,
|
||||
collapseModal: React.PropTypes.func.isRequired,
|
||||
setEnforceFocus: React.PropTypes.func.isRequired
|
||||
};
|
||||
@@ -19,8 +19,10 @@
|
||||
"intl": "1.2.5",
|
||||
"jasny-bootstrap": "3.1.3",
|
||||
"jquery": "3.1.1",
|
||||
"localforage": "1.5.0",
|
||||
"marked": "mattermost/marked#8f5902fff9bad793cd6c66e0c44002c9e79e1317",
|
||||
"match-at": "0.1.0",
|
||||
"mattermost-redux": "mattermost/mattermost-redux#webapp-part2",
|
||||
"object-assign": "4.1.1",
|
||||
"pdfjs-dist": "1.7.363",
|
||||
"perfect-scrollbar": "0.6.16",
|
||||
@@ -30,19 +32,26 @@
|
||||
"react-custom-scrollbars": "4.0.2",
|
||||
"react-dom": "15.4.2",
|
||||
"react-intl": "2.2.3",
|
||||
"react-redux": "5.0.4",
|
||||
"react-router": "2.8.1",
|
||||
"react-select": "1.0.0-rc.3",
|
||||
"redux-batched-actions": "0.1.5",
|
||||
"redux-persist": "4.6.0",
|
||||
"redux-persist-transform-filter": "0.0.9",
|
||||
"superagent": "3.5.0",
|
||||
"twemoji": "2.2.5",
|
||||
"velocity-animate": "1.4.3",
|
||||
"webrtc-adapter": "3.2.0",
|
||||
"whatwg-fetch": "2.0.3",
|
||||
"xregexp": "3.1.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-cli": "6.24.1",
|
||||
"babel-core": "6.24.0",
|
||||
"babel-eslint": "7.1.1",
|
||||
"babel-jest": "19.0.0",
|
||||
"babel-loader": "6.4.0",
|
||||
"babel-plugin-module-resolver": "2.7.0",
|
||||
"babel-plugin-transform-runtime": "6.23.0",
|
||||
"babel-polyfill": "6.23.0",
|
||||
"babel-preset-es2015": "6.24.0",
|
||||
@@ -73,9 +82,11 @@
|
||||
"raw-loader": "0.5.1",
|
||||
"react-addons-test-utils": "15.4.2",
|
||||
"react-dom": "15.4.2",
|
||||
"react-outside-event": "1.2.4",
|
||||
"remote-redux-devtools": "0.5.7",
|
||||
"remote-redux-devtools-on-debugger": "0.7.0",
|
||||
"sass-loader": "6.0.3",
|
||||
"style-loader": "0.13.2",
|
||||
"react-outside-event": "1.2.4",
|
||||
"url-loader": "0.5.8",
|
||||
"webpack": "2.2.1",
|
||||
"webpack-node-externals": "1.5.4"
|
||||
|
||||
@@ -6,22 +6,28 @@ require('perfect-scrollbar/jquery')($);
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import {Provider} from 'react-redux';
|
||||
import {Router, browserHistory} from 'react-router/es6';
|
||||
import PDFJS from 'pdfjs-dist';
|
||||
import * as GlobalActions from 'actions/global_actions.jsx';
|
||||
|
||||
import * as Websockets from 'actions/websocket_actions.jsx';
|
||||
import {loadMeAndConfig} from 'actions/user_actions.jsx';
|
||||
import BrowserStore from 'stores/browser_store.jsx';
|
||||
import ChannelStore from 'stores/channel_store.jsx';
|
||||
import UserStore from 'stores/user_store.jsx';
|
||||
import * as I18n from 'i18n/i18n.jsx';
|
||||
import * as AsyncClient from 'utils/async_client.jsx';
|
||||
|
||||
import {getClientConfig, getLicenseConfig, setUrl} from 'mattermost-redux/actions/general';
|
||||
|
||||
// Import our styles
|
||||
import 'bootstrap-colorpicker/dist/css/bootstrap-colorpicker.css';
|
||||
import 'google-fonts/google-fonts.css';
|
||||
import 'sass/styles.scss';
|
||||
import 'katex/dist/katex.min.css';
|
||||
|
||||
import store from 'stores/redux_store.jsx';
|
||||
|
||||
// Import the root of our routing tree
|
||||
import rRoot from 'routes/route_root.jsx';
|
||||
|
||||
@@ -51,11 +57,26 @@ function preRenderSetup(callwhendone) {
|
||||
|
||||
var d1 = $.Deferred(); //eslint-disable-line new-cap
|
||||
|
||||
GlobalActions.emitInitialLoad(
|
||||
() => {
|
||||
d1.resolve();
|
||||
}
|
||||
);
|
||||
setUrl(window.location.origin);
|
||||
|
||||
const currentUserId = localStorage.getItem('currentUserId');
|
||||
|
||||
if (currentUserId) {
|
||||
loadMeAndConfig(() => d1.resolve());
|
||||
} else {
|
||||
getClientConfig()(store.dispatch, store.getState).then(
|
||||
(config) => {
|
||||
global.window.mm_config = config;
|
||||
|
||||
getLicenseConfig()(store.dispatch, store.getState).then(
|
||||
(license) => {
|
||||
global.window.mm_license = license;
|
||||
d1.resolve();
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Make sure the websockets close and reset version
|
||||
$(window).on('beforeunload',
|
||||
@@ -86,10 +107,12 @@ function preRenderSetup(callwhendone) {
|
||||
|
||||
function renderRootComponent() {
|
||||
ReactDOM.render((
|
||||
<Router
|
||||
history={browserHistory}
|
||||
routes={rRoot}
|
||||
/>
|
||||
<Provider store={store}>
|
||||
<Router
|
||||
history={browserHistory}
|
||||
routes={rRoot}
|
||||
/>
|
||||
</Provider>
|
||||
),
|
||||
document.getElementById('root'));
|
||||
}
|
||||
|
||||
112
webapp/store/index.js
Обычный файл
112
webapp/store/index.js
Обычный файл
@@ -0,0 +1,112 @@
|
||||
// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import {batchActions} from 'redux-batched-actions';
|
||||
import configureServiceStore from 'mattermost-redux/store';
|
||||
import {General, RequestStatus} from 'mattermost-redux/constants';
|
||||
import reduxInitialState from 'mattermost-redux/store/initial_state';
|
||||
import {createTransform, persistStore} from 'redux-persist';
|
||||
import localForage from 'localforage';
|
||||
|
||||
import {transformSet} from './utils';
|
||||
|
||||
const usersSetTransform = [
|
||||
'profilesInChannel',
|
||||
'profilesNotInChannel',
|
||||
'profilesInTeam',
|
||||
'profilesNotInTeam'
|
||||
];
|
||||
|
||||
const teamSetTransform = [
|
||||
'membersInTeam'
|
||||
];
|
||||
|
||||
const setTransforms = [
|
||||
...usersSetTransform,
|
||||
...teamSetTransform
|
||||
];
|
||||
|
||||
export default function configureStore(initialState) {
|
||||
const setTransformer = createTransform(
|
||||
(inboundState, key) => {
|
||||
if (key === 'entities') {
|
||||
const state = {...inboundState};
|
||||
for (const prop in state) {
|
||||
if (state.hasOwnProperty(prop)) {
|
||||
state[prop] = transformSet(state[prop], setTransforms);
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
return inboundState;
|
||||
},
|
||||
(outboundState, key) => {
|
||||
if (key === 'entities') {
|
||||
const state = {...outboundState};
|
||||
for (const prop in state) {
|
||||
if (state.hasOwnProperty(prop)) {
|
||||
state[prop] = transformSet(state[prop], setTransforms, false);
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
return outboundState;
|
||||
}
|
||||
);
|
||||
|
||||
const offlineOptions = {
|
||||
persist: (store, options) => {
|
||||
const persistor = persistStore(store, {storage: localForage, ...options}, () => {
|
||||
store.dispatch({
|
||||
type: General.STORE_REHYDRATION_COMPLETE,
|
||||
complete: true
|
||||
});
|
||||
});
|
||||
|
||||
let purging = false;
|
||||
|
||||
// check to see if the logout request was successful
|
||||
store.subscribe(() => {
|
||||
const state = store.getState();
|
||||
if (state.requests.users.logout.status === RequestStatus.SUCCESS && !purging) {
|
||||
purging = true;
|
||||
|
||||
persistor.purge();
|
||||
|
||||
store.dispatch(batchActions([
|
||||
{
|
||||
type: General.OFFLINE_STORE_RESET,
|
||||
data: Object.assign({}, reduxInitialState, initialState)
|
||||
}
|
||||
]));
|
||||
|
||||
localStorage.removeItem('currentUserId');
|
||||
window.location.href = '/';
|
||||
|
||||
setTimeout(() => {
|
||||
purging = false;
|
||||
}, 500);
|
||||
}
|
||||
});
|
||||
|
||||
return persistor;
|
||||
},
|
||||
persistOptions: {
|
||||
autoRehydrate: {
|
||||
log: false
|
||||
},
|
||||
blacklist: ['errors', 'offline', 'requests', 'entities'],
|
||||
debounce: 500,
|
||||
transforms: [
|
||||
setTransformer
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
return configureServiceStore({}, {}, offlineOptions);
|
||||
}
|
||||
|
||||
42
webapp/store/utils.js
Обычный файл
42
webapp/store/utils.js
Обычный файл
@@ -0,0 +1,42 @@
|
||||
// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
function transformFromSet(incoming) {
|
||||
const state = {...incoming};
|
||||
|
||||
for (const key in state) {
|
||||
if (state.hasOwnProperty(key)) {
|
||||
if (state[key] instanceof Set) {
|
||||
state[key] = Array.from([...state[key]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
function transformToSet(incoming) {
|
||||
const state = {...incoming};
|
||||
|
||||
for (const key in state) {
|
||||
if (state.hasOwnProperty(key)) {
|
||||
state[key] = new Set(state[key]);
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
export function transformSet(incoming, setTransforms, toStorage = true) {
|
||||
const state = {...incoming};
|
||||
|
||||
const transformer = toStorage ? transformFromSet : transformToSet;
|
||||
|
||||
for (const key in state) {
|
||||
if (state.hasOwnProperty(key) && setTransforms.includes(key)) {
|
||||
state[key] = transformer(state[key]);
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
@@ -8,6 +8,10 @@ import EventEmitter from 'events';
|
||||
|
||||
const CHANGE_EVENT = 'change';
|
||||
|
||||
import store from 'stores/redux_store.jsx';
|
||||
import * as Selectors from 'mattermost-redux/selectors/entities/preferences';
|
||||
import {PreferenceTypes} from 'mattermost-redux/action_types';
|
||||
|
||||
class PreferenceStore extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
@@ -16,6 +20,23 @@ class PreferenceStore extends EventEmitter {
|
||||
this.dispatchToken = AppDispatcher.register(this.handleEventPayload);
|
||||
|
||||
this.preferences = new Map();
|
||||
this.entities = Selectors.getMyPreferences(store.getState());
|
||||
Object.keys(this.entities).forEach((key) => {
|
||||
this.preferences.set(key, this.entities[key].value);
|
||||
});
|
||||
|
||||
store.subscribe(() => {
|
||||
const newEntities = Selectors.getMyPreferences(store.getState());
|
||||
if (this.entities !== newEntities) {
|
||||
this.preferences = new Map();
|
||||
Object.keys(newEntities).forEach((key) => {
|
||||
this.preferences.set(key, newEntities[key].value);
|
||||
});
|
||||
this.emitChange();
|
||||
}
|
||||
|
||||
this.entities = newEntities;
|
||||
});
|
||||
|
||||
this.setMaxListeners(600);
|
||||
}
|
||||
@@ -79,21 +100,24 @@ class PreferenceStore extends EventEmitter {
|
||||
}
|
||||
|
||||
setPreference(category, name, value) {
|
||||
this.preferences.set(this.getKey(category, name), value);
|
||||
store.dispatch({
|
||||
type: PreferenceTypes.RECEIVED_PREFERENCES,
|
||||
data: [{category, name, value}]
|
||||
});
|
||||
}
|
||||
|
||||
setPreferencesFromServer(newPreferences) {
|
||||
for (const preference of newPreferences) {
|
||||
this.setPreference(preference.category, preference.name, preference.value);
|
||||
}
|
||||
store.dispatch({
|
||||
type: PreferenceTypes.RECEIVED_PREFERENCES,
|
||||
data: newPreferences
|
||||
});
|
||||
}
|
||||
|
||||
deletePreference(preference) {
|
||||
this.preferences.delete(this.getKey(preference.category, preference.name));
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.preferences.clear();
|
||||
store.dispatch({
|
||||
type: PreferenceTypes.DELETED_PREFERENCES,
|
||||
data: [preference]
|
||||
});
|
||||
}
|
||||
|
||||
emitChange(category) {
|
||||
|
||||
19
webapp/stores/redux_store.jsx
Обычный файл
19
webapp/stores/redux_store.jsx
Обычный файл
@@ -0,0 +1,19 @@
|
||||
// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
// This is a temporary store while we are transitioning from Flux to Redux. This file exports
|
||||
// the configured Redux store for use by actions and selectors.
|
||||
|
||||
import configureStore from 'store';
|
||||
const store = configureStore();
|
||||
|
||||
export function bindActionToRedux(action, ...args) {
|
||||
return async () => {
|
||||
await action(...args)(store.dispatch, store.getState);
|
||||
};
|
||||
}
|
||||
|
||||
window.store = store;
|
||||
|
||||
export default store;
|
||||
|
||||
@@ -17,17 +17,33 @@ const CHANGE_EVENT = 'change';
|
||||
const STATS_EVENT = 'stats';
|
||||
const UNREAD_EVENT = 'unread';
|
||||
|
||||
import store from 'stores/redux_store.jsx';
|
||||
import * as Selectors from 'mattermost-redux/selectors/entities/teams';
|
||||
import {TeamTypes} from 'mattermost-redux/action_types';
|
||||
|
||||
var Utils;
|
||||
|
||||
class TeamStoreClass extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
this.clear();
|
||||
|
||||
store.subscribe(() => {
|
||||
const newEntities = store.getState().entities.teams;
|
||||
|
||||
if (newEntities.teams !== this.entities.teams) {
|
||||
this.emitChange();
|
||||
}
|
||||
if (newEntities.myMembers !== this.entities.myMembers) {
|
||||
this.emitChange();
|
||||
}
|
||||
|
||||
this.entities = newEntities;
|
||||
});
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.teams = {};
|
||||
this.my_team_members = [];
|
||||
this.entities = {};
|
||||
this.members_in_team = {};
|
||||
this.members_not_in_team = {};
|
||||
this.stats = {};
|
||||
@@ -91,7 +107,7 @@ class TeamStoreClass extends EventEmitter {
|
||||
}
|
||||
|
||||
getAll() {
|
||||
return this.teams;
|
||||
return store.getState().entities.teams.teams;
|
||||
}
|
||||
|
||||
getCurrentId() {
|
||||
@@ -100,10 +116,14 @@ class TeamStoreClass extends EventEmitter {
|
||||
|
||||
setCurrentId(id) {
|
||||
this.currentTeamId = id;
|
||||
store.dispatch({
|
||||
type: TeamTypes.SELECT_TEAM,
|
||||
data: id
|
||||
});
|
||||
}
|
||||
|
||||
getCurrent() {
|
||||
const team = this.teams[this.currentTeamId];
|
||||
const team = this.getAll()[this.currentTeamId];
|
||||
|
||||
if (team) {
|
||||
return team;
|
||||
@@ -165,17 +185,21 @@ class TeamStoreClass extends EventEmitter {
|
||||
}
|
||||
|
||||
saveTeam(team) {
|
||||
this.teams[team.id] = team;
|
||||
this.saveTeams([team]);
|
||||
}
|
||||
|
||||
saveTeams(teams) {
|
||||
this.teams = teams;
|
||||
store.dispatch({
|
||||
type: TeamTypes.RECEIVED_TEAMS_LIST,
|
||||
data: teams
|
||||
});
|
||||
}
|
||||
|
||||
updateTeam(team) {
|
||||
const t = JSON.parse(team);
|
||||
if (this.teams && this.teams[t.id]) {
|
||||
this.teams[t.id] = t;
|
||||
const teams = this.getAll();
|
||||
if (teams && teams[t.id]) {
|
||||
this.saveTeam(t);
|
||||
}
|
||||
|
||||
if (this.teamListings && this.teamListings[t.id]) {
|
||||
@@ -193,7 +217,7 @@ class TeamStoreClass extends EventEmitter {
|
||||
|
||||
saveMyTeam(team) {
|
||||
this.saveTeam(team);
|
||||
this.currentTeamId = team.id;
|
||||
this.setCurrentId(team.id);
|
||||
}
|
||||
|
||||
saveStats(teamId, stats) {
|
||||
@@ -201,20 +225,26 @@ class TeamStoreClass extends EventEmitter {
|
||||
}
|
||||
|
||||
saveMyTeamMembers(members) {
|
||||
this.my_team_members = members;
|
||||
store.dispatch({
|
||||
type: TeamTypes.RECEIVED_MY_TEAM_MEMBERS,
|
||||
data: members
|
||||
});
|
||||
}
|
||||
|
||||
appendMyTeamMember(member) {
|
||||
this.my_team_members.push(member);
|
||||
const members = this.getMyTeamMembers();
|
||||
members.push(member);
|
||||
this.saveMyTeamMembers(members);
|
||||
}
|
||||
|
||||
saveMyTeamMembersUnread(members) {
|
||||
for (let i = 0; i < this.my_team_members.length; i++) {
|
||||
const team = this.my_team_members[i];
|
||||
const myMembers = this.getMyTeamMembers();
|
||||
for (let i = 0; i < myMembers.length; i++) {
|
||||
const team = myMembers[i];
|
||||
const member = members.filter((m) => m.team_id === team.team_id)[0];
|
||||
|
||||
if (member) {
|
||||
this.my_team_members[i] = Object.assign({},
|
||||
myMembers[i] = Object.assign({},
|
||||
team,
|
||||
{
|
||||
msg_count: member.msg_count,
|
||||
@@ -222,19 +252,23 @@ class TeamStoreClass extends EventEmitter {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
this.saveMyTeamMembers(myMembers);
|
||||
}
|
||||
|
||||
removeMyTeamMember(teamId) {
|
||||
for (let i = 0; i < this.my_team_members.length; i++) {
|
||||
if (this.my_team_members[i].team_id === teamId) {
|
||||
this.my_team_members.splice(i, 1);
|
||||
const myMembers = this.getMyTeamMembers();
|
||||
for (let i = 0; i < myMembers.length; i++) {
|
||||
if (myMembers[i].team_id === teamId) {
|
||||
myMembers.splice(i, 1);
|
||||
}
|
||||
}
|
||||
this.emitChange();
|
||||
|
||||
this.saveMyTeamMembers(myMembers);
|
||||
}
|
||||
|
||||
getMyTeamMembers() {
|
||||
return this.my_team_members;
|
||||
return Object.values(Selectors.getTeamMemberships(store.getState()));
|
||||
}
|
||||
|
||||
saveMembersInTeam(teamId = this.getCurrentId(), members) {
|
||||
@@ -320,19 +354,21 @@ class TeamStoreClass extends EventEmitter {
|
||||
}
|
||||
|
||||
updateUnreadCount(teamId, totalMsgCount, channelMember) {
|
||||
const member = this.my_team_members.filter((m) => m.team_id === teamId)[0];
|
||||
let member = this.getMyTeamMembers().filter((m) => m.team_id === teamId)[0];
|
||||
if (member) {
|
||||
member = Object.assign({}, member);
|
||||
member.msg_count -= (totalMsgCount - channelMember.msg_count);
|
||||
member.mention_count -= channelMember.mention_count;
|
||||
}
|
||||
}
|
||||
|
||||
subtractUnread(teamId, msgs, mentions) {
|
||||
const member = this.my_team_members.filter((m) => m.team_id === teamId)[0];
|
||||
let member = this.getMyTeamMembers().filter((m) => m.team_id === teamId)[0];
|
||||
if (member) {
|
||||
const msgCount = member.msg_count - msgs;
|
||||
const mentionCount = member.mention_count - mentions;
|
||||
|
||||
member = Object.assign({}, member);
|
||||
member.msg_count = (msgCount > 0) ? msgCount : 0;
|
||||
member.mention_count = (mentionCount > 0) ? mentionCount : 0;
|
||||
}
|
||||
@@ -344,7 +380,7 @@ class TeamStoreClass extends EventEmitter {
|
||||
return;
|
||||
}
|
||||
|
||||
const member = this.my_team_members.filter((m) => m.team_id === id)[0];
|
||||
const member = Object.assign({}, this.getMyTeamMembers().filter((m) => m.team_id === id)[0]);
|
||||
member.msg_count++;
|
||||
}
|
||||
|
||||
@@ -355,7 +391,7 @@ class TeamStoreClass extends EventEmitter {
|
||||
}
|
||||
|
||||
if (mentions.indexOf(UserStore.getCurrentId()) !== -1) {
|
||||
const member = this.my_team_members.filter((m) => m.team_id === id)[0];
|
||||
const member = Object.assign({}, this.getMyTeamMembers().filter((m) => m.team_id === id)[0]);
|
||||
member.mention_count++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,12 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See License.txt for license information.
|
||||
|
||||
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
|
||||
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_NOT_IN_CHANNEL = 'change_not_in_channel';
|
||||
@@ -23,48 +19,52 @@ const CHANGE_EVENT_SESSIONS = 'change_sessions';
|
||||
const CHANGE_EVENT_AUDITS = 'change_audits';
|
||||
const CHANGE_EVENT_STATUSES = 'change_statuses';
|
||||
|
||||
import store from 'stores/redux_store.jsx';
|
||||
import * as Selectors from 'mattermost-redux/selectors/entities/users';
|
||||
import {UserTypes} from 'mattermost-redux/action_types';
|
||||
|
||||
var Utils;
|
||||
|
||||
class UserStoreClass extends EventEmitter {
|
||||
constructor() {
|
||||
super();
|
||||
this.clear();
|
||||
}
|
||||
|
||||
clear() {
|
||||
// All the profiles, regardless of where they came from
|
||||
this.profiles = {};
|
||||
this.paging_offset = 0;
|
||||
this.paging_count = 0;
|
||||
|
||||
// Lists of sorted IDs for users in a team
|
||||
this.profiles_not_in_team = {};
|
||||
this.not_in_team_offset = 0;
|
||||
this.not_in_team_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 = {};
|
||||
|
||||
// Lists of sorted IDs for users without a team
|
||||
this.profiles_without_team = {};
|
||||
|
||||
this.statuses = {};
|
||||
this.sessions = {};
|
||||
this.audits = [];
|
||||
this.currentUserId = '';
|
||||
this.noAccounts = false;
|
||||
this.entities = {};
|
||||
|
||||
store.subscribe(() => {
|
||||
const newEntities = store.getState().entities.users;
|
||||
|
||||
if (newEntities.profiles !== this.entities.profiles) {
|
||||
this.emitChange();
|
||||
}
|
||||
if (newEntities.profilesInChannel !== this.entities.profilesInChannel) {
|
||||
this.emitInChannelChange();
|
||||
}
|
||||
if (newEntities.profilesNotInChannel !== this.entities.profilesNotInChannel) {
|
||||
this.emitNotInChannelChange();
|
||||
}
|
||||
if (newEntities.profilesInTeam !== this.entities.profilesInTeam) {
|
||||
this.emitInTeamChange();
|
||||
}
|
||||
if (newEntities.profilesNotInTeam !== this.entities.profilesNotInTeam) {
|
||||
this.emitNotInTeamChange();
|
||||
}
|
||||
if (newEntities.profilesWithoutTeam !== this.entities.profilesWithoutTeam) {
|
||||
this.emitWithoutTeamChange();
|
||||
}
|
||||
if (newEntities.statuses !== this.entities.statuses) {
|
||||
this.emitStatusesChange();
|
||||
}
|
||||
if (newEntities.myAudits !== this.entities.myAudits) {
|
||||
this.emitAuditsChange();
|
||||
}
|
||||
if (newEntities.mySessions !== this.entities.mySessions) {
|
||||
this.emitSessionsChange();
|
||||
}
|
||||
|
||||
this.entities = newEntities;
|
||||
});
|
||||
}
|
||||
|
||||
emitChange(userId) {
|
||||
@@ -178,49 +178,21 @@ class UserStoreClass extends EventEmitter {
|
||||
// General
|
||||
|
||||
getCurrentUser() {
|
||||
return this.getProfiles()[this.currentUserId];
|
||||
}
|
||||
|
||||
setCurrentUser(user) {
|
||||
this.saveProfile(user);
|
||||
this.currentUserId = user.id;
|
||||
global.window.mm_current_user_id = this.currentUserId;
|
||||
if (LocalizationStore.getLocale() !== user.locale) {
|
||||
setTimeout(() => GlobalActions.newLocalizationSelected(user.locale), 0);
|
||||
}
|
||||
return Selectors.getCurrentUser(store.getState());
|
||||
}
|
||||
|
||||
getCurrentId() {
|
||||
var user = this.getCurrentUser();
|
||||
|
||||
if (user) {
|
||||
return user.id;
|
||||
}
|
||||
|
||||
return null;
|
||||
return Selectors.getCurrentUserId(store.getState());
|
||||
}
|
||||
|
||||
// System-Wide Profiles
|
||||
|
||||
saveProfiles(profiles) {
|
||||
const newProfiles = Object.assign({}, profiles);
|
||||
const currentId = this.getCurrentId();
|
||||
if (newProfiles[currentId]) {
|
||||
Reflect.deleteProperty(newProfiles, currentId);
|
||||
}
|
||||
this.profiles = Object.assign({}, this.profiles, newProfiles);
|
||||
}
|
||||
|
||||
getProfiles() {
|
||||
return this.profiles;
|
||||
return Selectors.getUsers(store.getState());
|
||||
}
|
||||
|
||||
getProfile(userId) {
|
||||
if (this.profiles[userId]) {
|
||||
return Object.assign({}, this.profiles[userId]);
|
||||
}
|
||||
|
||||
return null;
|
||||
return Selectors.getUser(store.getState(), userId);
|
||||
}
|
||||
|
||||
getProfileListForIds(userIds, skipCurrent = false, skipInactive = false) {
|
||||
@@ -257,17 +229,7 @@ class UserStoreClass extends EventEmitter {
|
||||
}
|
||||
|
||||
getProfilesUsernameMap() {
|
||||
var profileUsernameMap = {};
|
||||
|
||||
var profiles = this.getProfiles();
|
||||
for (var key in profiles) {
|
||||
if (profiles.hasOwnProperty(key)) {
|
||||
var profile = profiles[key];
|
||||
profileUsernameMap[profile.username] = profile;
|
||||
}
|
||||
}
|
||||
|
||||
return profileUsernameMap;
|
||||
return Selectors.getUsersByUsername(store.getState());
|
||||
}
|
||||
|
||||
getActiveOnlyProfiles(skipCurrent) {
|
||||
@@ -310,10 +272,11 @@ class UserStoreClass extends EventEmitter {
|
||||
getProfileList(skipCurrent = false, allowInactive = false) {
|
||||
const profiles = [];
|
||||
const currentId = this.getCurrentId();
|
||||
const profileMap = this.getProfiles();
|
||||
|
||||
for (const id in this.profiles) {
|
||||
if (this.profiles.hasOwnProperty(id)) {
|
||||
var profile = this.profiles[id];
|
||||
for (const id in profileMap) {
|
||||
if (profileMap.hasOwnProperty(id)) {
|
||||
var profile = profileMap[id];
|
||||
|
||||
if (skipCurrent && id === currentId) {
|
||||
continue;
|
||||
@@ -339,103 +302,32 @@ class UserStoreClass extends EventEmitter {
|
||||
}
|
||||
|
||||
saveProfile(profile) {
|
||||
this.profiles[profile.id] = profile;
|
||||
store.dispatch({
|
||||
type: UserTypes.RECEIVED_PROFILE,
|
||||
data: profile
|
||||
});
|
||||
}
|
||||
|
||||
// Team-Wide 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);
|
||||
}
|
||||
|
||||
getProfileListInTeam(teamId = TeamStore.getCurrentId(), skipCurrent = false, skipInactive = false) {
|
||||
const userIds = this.profiles_in_team[teamId] || [];
|
||||
const userIds = Array.from(Selectors.getUserIdsInTeams(store.getState())[teamId] || []);
|
||||
|
||||
return this.getProfileListForIds(userIds, skipCurrent, skipInactive);
|
||||
}
|
||||
|
||||
removeProfileFromTeam(teamId, userId) {
|
||||
const userIds = this.profiles_in_team[teamId];
|
||||
if (!userIds) {
|
||||
return;
|
||||
}
|
||||
|
||||
const index = userIds.indexOf(userId);
|
||||
if (index === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
userIds.splice(index, 1);
|
||||
store.dispatch({
|
||||
type: UserTypes.RECEIVED_PROFILE_NOT_IN_TEAM,
|
||||
data: {user_id: userId},
|
||||
id: teamId
|
||||
});
|
||||
}
|
||||
|
||||
// Not In Team Profiles
|
||||
|
||||
saveProfilesNotInTeam(teamId, profiles) {
|
||||
const oldProfileList = this.profiles_not_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_not_in_team[teamId] = newProfileList;
|
||||
this.saveProfiles(profiles);
|
||||
}
|
||||
|
||||
removeProfileNotInTeam(teamId, userId) {
|
||||
const userIds = this.profiles_not_in_team[teamId];
|
||||
if (!userIds) {
|
||||
return;
|
||||
}
|
||||
|
||||
const index = userIds.indexOf(userId);
|
||||
if (index === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
userIds.splice(index, 1);
|
||||
}
|
||||
|
||||
getProfileListNotInTeam(teamId = TeamStore.getCurrentId(), skipCurrent = false, skipInactive = false) {
|
||||
const userIds = this.profiles_not_in_team[teamId] || [];
|
||||
const userIds = Array.from(Selectors.getUserIdsNotInTeams(store.getState())[teamId] || []);
|
||||
const profiles = [];
|
||||
const currentId = this.getCurrentId();
|
||||
|
||||
@@ -460,178 +352,84 @@ class UserStoreClass extends EventEmitter {
|
||||
return 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;
|
||||
removeProfileNotInTeam(teamId, userId) {
|
||||
store.dispatch({
|
||||
type: UserTypes.RECEIVED_PROFILE_IN_TEAM,
|
||||
data: {user_id: userId},
|
||||
id: teamId
|
||||
});
|
||||
|
||||
this.profiles_in_channel[channelId] = newProfileList;
|
||||
this.saveProfiles(profiles);
|
||||
}
|
||||
|
||||
// Channel-Wide Profiles
|
||||
|
||||
saveProfileInChannel(channelId = ChannelStore.getCurrentId(), profile) {
|
||||
const profileMap = {};
|
||||
profileMap[profile.id] = profile;
|
||||
this.saveProfilesInChannel(channelId, profileMap);
|
||||
store.dispatch({
|
||||
type: UserTypes.RECEIVED_PROFILE_IN_CHANNEL,
|
||||
data: {user_id: profile.id},
|
||||
id: channelId
|
||||
});
|
||||
}
|
||||
|
||||
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;
|
||||
store.dispatch({
|
||||
type: UserTypes.RECEIVED_PROFILE_IN_CHANNEL,
|
||||
data: {user_id: userId},
|
||||
id: channelId
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
store.dispatch({
|
||||
type: UserTypes.RECEIVED_PROFILE_NOT_IN_CHANNEL,
|
||||
data: {user_id: userId},
|
||||
id: channelId
|
||||
});
|
||||
}
|
||||
|
||||
getProfileListInChannel(channelId = ChannelStore.getCurrentId(), skipCurrent = false) {
|
||||
const userIds = this.profiles_in_channel[channelId] || [];
|
||||
const userIds = Array.from(Selectors.getUserIdsInChannels(store.getState())[channelId] || []);
|
||||
|
||||
return this.getProfileListForIds(userIds, skipCurrent, false);
|
||||
}
|
||||
|
||||
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);
|
||||
store.dispatch({
|
||||
type: UserTypes.RECEIVED_PROFILE_NOT_IN_CHANNEL,
|
||||
data: {user_id: profile.id},
|
||||
id: channelId
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
store.dispatch({
|
||||
type: UserTypes.RECEIVED_PROFILE_IN_CHANNEL,
|
||||
data: {user_id: userId},
|
||||
id: channelId
|
||||
});
|
||||
}
|
||||
|
||||
getProfileListNotInChannel(channelId = ChannelStore.getCurrentId(), skipInactive = false) {
|
||||
const userIds = this.profiles_not_in_channel[channelId] || [];
|
||||
const userIds = Array.from(Selectors.getUserIdsNotInChannels(store.getState())[channelId] || []);
|
||||
|
||||
return this.getProfileListForIds(userIds, false, skipInactive);
|
||||
}
|
||||
|
||||
// Profiles without any teams
|
||||
|
||||
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]);
|
||||
}
|
||||
|
||||
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 || [];
|
||||
const userIds = Array.from(Selectors.getUserIdsWithoutTeam(store.getState()) || []);
|
||||
|
||||
return this.getProfileListForIds(userIds, skipCurrent, skipInactive);
|
||||
}
|
||||
|
||||
// Other
|
||||
|
||||
setSessions(sessions) {
|
||||
this.sessions = sessions;
|
||||
}
|
||||
|
||||
getSessions() {
|
||||
return this.sessions;
|
||||
}
|
||||
|
||||
setAudits(audits) {
|
||||
this.audits = audits;
|
||||
return store.getState().entities.users.mySessions;
|
||||
}
|
||||
|
||||
getAudits() {
|
||||
return this.audits;
|
||||
return store.getState().entities.users.myAudits;
|
||||
}
|
||||
|
||||
getCurrentMentionKeys() {
|
||||
@@ -668,17 +466,16 @@ class UserStoreClass extends EventEmitter {
|
||||
return keys;
|
||||
}
|
||||
|
||||
setStatuses(statuses) {
|
||||
this.statuses = Object.assign(this.statuses, statuses);
|
||||
}
|
||||
|
||||
setStatus(userId, status) {
|
||||
this.statuses[userId] = status;
|
||||
this.emitStatusesChange();
|
||||
const data = [{user_id: userId, status}];
|
||||
store.dispatch({
|
||||
type: UserTypes.RECEIVED_STATUSES,
|
||||
data
|
||||
});
|
||||
}
|
||||
|
||||
getStatuses() {
|
||||
return this.statuses;
|
||||
return store.getState().entities.users.statuses;
|
||||
}
|
||||
|
||||
getStatus(id) {
|
||||
@@ -686,7 +483,7 @@ class UserStoreClass extends EventEmitter {
|
||||
}
|
||||
|
||||
getNoAccounts() {
|
||||
return this.noAccounts;
|
||||
return global.window.mm_config.NoAccounts === 'true';
|
||||
}
|
||||
|
||||
setNoAccounts(noAccounts) {
|
||||
@@ -706,141 +503,9 @@ 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;
|
||||
}
|
||||
|
||||
setNotInTeamPage(offset, count) {
|
||||
this.not_in_team_offset = offset + count;
|
||||
this.not_in_team_count = this.not_in_team_count + count;
|
||||
}
|
||||
|
||||
getNotInTeamPagingOffset() {
|
||||
return this.not_in_team_offset;
|
||||
}
|
||||
|
||||
getNotInTeamPagingCount() {
|
||||
return this.not_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();
|
||||
UserStore.setMaxListeners(600);
|
||||
|
||||
UserStore.dispatchToken = AppDispatcher.register((payload) => {
|
||||
var action = payload.action;
|
||||
|
||||
switch (action.type) {
|
||||
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_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_NOT_IN_TEAM:
|
||||
UserStore.saveProfilesNotInTeam(action.team_id, action.profiles);
|
||||
if (action.offset != null && action.count != null) {
|
||||
UserStore.setNotInTeamPage(action.offset, action.count);
|
||||
}
|
||||
UserStore.emitNotInTeamChange();
|
||||
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_PROFILES_WITHOUT_TEAM:
|
||||
UserStore.saveProfilesWithoutTeam(action.profiles);
|
||||
UserStore.emitWithoutTeamChange();
|
||||
break;
|
||||
case ActionTypes.RECEIVED_PROFILE:
|
||||
UserStore.saveProfile(action.profile);
|
||||
UserStore.emitChange();
|
||||
break;
|
||||
case ActionTypes.RECEIVED_ME:
|
||||
UserStore.setCurrentUser(action.me);
|
||||
UserStore.emitChange(action.me.id);
|
||||
break;
|
||||
case ActionTypes.RECEIVED_SESSIONS:
|
||||
UserStore.setSessions(action.sessions);
|
||||
UserStore.emitSessionsChange();
|
||||
break;
|
||||
case ActionTypes.RECEIVED_AUDITS:
|
||||
UserStore.setAudits(action.audits);
|
||||
UserStore.emitAuditsChange();
|
||||
break;
|
||||
case ActionTypes.RECEIVED_STATUSES:
|
||||
UserStore.setStatuses(action.statuses);
|
||||
UserStore.emitStatusesChange();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
});
|
||||
|
||||
export {UserStore as default};
|
||||
|
||||
@@ -8,7 +8,6 @@ import TeamStore from 'stores/team_store.jsx';
|
||||
import ErrorStore from 'stores/error_store.jsx';
|
||||
|
||||
import * as GlobalActions from 'actions/global_actions.jsx';
|
||||
import {loadStatusesForProfilesMap} from 'actions/status_actions.jsx';
|
||||
|
||||
import AppDispatcher from 'dispatcher/app_dispatcher.jsx';
|
||||
import Client from 'client/web_client.jsx';
|
||||
@@ -323,231 +322,6 @@ export function getUser(userId, success, error) {
|
||||
);
|
||||
}
|
||||
|
||||
export function getProfiles(offset = UserStore.getPagingOffset(), limit = Constants.PROFILE_CHUNK_SIZE) {
|
||||
const callName = `getProfiles${offset}${limit}`;
|
||||
|
||||
if (isCallInProgress(callName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
callTracker[callName] = utils.getTimestamp();
|
||||
Client.getProfiles(
|
||||
offset,
|
||||
limit,
|
||||
(data) => {
|
||||
callTracker[callName] = 0;
|
||||
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECEIVED_PROFILES,
|
||||
profiles: data
|
||||
});
|
||||
},
|
||||
(err) => {
|
||||
callTracker[callName] = 0;
|
||||
dispatchError(err, 'getProfiles');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function getProfilesInTeam(teamId = TeamStore.getCurrentId(), offset = UserStore.getInTeamPagingOffset(), limit = Constants.PROFILE_CHUNK_SIZE) {
|
||||
const callName = `getProfilesInTeam${teamId}${offset}${limit}`;
|
||||
|
||||
if (isCallInProgress(callName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
callTracker[callName] = utils.getTimestamp();
|
||||
Client.getProfilesInTeam(
|
||||
teamId,
|
||||
offset,
|
||||
limit,
|
||||
(data) => {
|
||||
callTracker[callName] = 0;
|
||||
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECEIVED_PROFILES_IN_TEAM,
|
||||
profiles: data,
|
||||
team_id: teamId,
|
||||
offset,
|
||||
count: Object.keys(data).length
|
||||
});
|
||||
},
|
||||
(err) => {
|
||||
callTracker[callName] = 0;
|
||||
dispatchError(err, 'getProfilesInTeam');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function getProfilesNotInTeam(teamId = TeamStore.getCurrentId(), offset = UserStore.getInTeamPagingOffset(), limit = Constants.PROFILE_CHUNK_SIZE) {
|
||||
const callName = `getProfilesNotInTeam${teamId}${offset}${limit}`;
|
||||
|
||||
if (isCallInProgress(callName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
callTracker[callName] = utils.getTimestamp();
|
||||
Client.getProfilesNotInTeam(
|
||||
teamId,
|
||||
offset,
|
||||
limit,
|
||||
(data) => {
|
||||
callTracker[callName] = 0;
|
||||
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECEIVED_PROFILES_NOT_IN_TEAM,
|
||||
profiles: data,
|
||||
team_id: teamId,
|
||||
offset,
|
||||
count: Object.keys(data).length
|
||||
});
|
||||
},
|
||||
(err) => {
|
||||
callTracker[callName] = 0;
|
||||
dispatchError(err, 'getProfilesNotInTeam');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function getProfilesInChannel(channelId = ChannelStore.getCurrentId(), offset = UserStore.getInChannelPagingOffset(), limit = Constants.PROFILE_CHUNK_SIZE) {
|
||||
const callName = `getProfilesInChannel${channelId}${offset}${limit}`;
|
||||
|
||||
if (isCallInProgress()) {
|
||||
return;
|
||||
}
|
||||
|
||||
callTracker[callName] = utils.getTimestamp();
|
||||
Client.getProfilesInChannel(
|
||||
channelId,
|
||||
offset,
|
||||
limit,
|
||||
(data) => {
|
||||
callTracker[callName] = 0;
|
||||
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECEIVED_PROFILES_IN_CHANNEL,
|
||||
channel_id: channelId,
|
||||
profiles: data,
|
||||
offset,
|
||||
count: Object.keys(data).length
|
||||
});
|
||||
|
||||
loadStatusesForProfilesMap(data);
|
||||
},
|
||||
(err) => {
|
||||
callTracker[callName] = 0;
|
||||
dispatchError(err, 'getProfilesInChannel');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function getProfilesNotInChannel(channelId = ChannelStore.getCurrentId(), offset = UserStore.getNotInChannelPagingOffset(), limit = Constants.PROFILE_CHUNK_SIZE) {
|
||||
const callName = `getProfilesNotInChannel${channelId}${offset}${limit}`;
|
||||
|
||||
if (isCallInProgress(callName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
callTracker[callName] = utils.getTimestamp();
|
||||
Client.getProfilesNotInChannel(
|
||||
channelId,
|
||||
offset,
|
||||
limit,
|
||||
(data) => {
|
||||
callTracker[callName] = 0;
|
||||
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECEIVED_PROFILES_NOT_IN_CHANNEL,
|
||||
channel_id: channelId,
|
||||
profiles: data,
|
||||
offset,
|
||||
count: Object.keys(data).length
|
||||
});
|
||||
|
||||
loadStatusesForProfilesMap(data);
|
||||
},
|
||||
(err) => {
|
||||
callTracker[callName] = 0;
|
||||
dispatchError(err, 'getProfilesNotInChannel');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function getProfilesByIds(userIds) {
|
||||
const callName = 'getProfilesByIds' + JSON.stringify(userIds);
|
||||
|
||||
if (isCallInProgress(callName)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!userIds || userIds.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
callTracker[callName] = utils.getTimestamp();
|
||||
Client.getProfilesByIds(
|
||||
userIds,
|
||||
(data) => {
|
||||
callTracker[callName] = 0;
|
||||
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECEIVED_PROFILES,
|
||||
profiles: data
|
||||
});
|
||||
},
|
||||
(err) => {
|
||||
callTracker[callName] = 0;
|
||||
dispatchError(err, 'getProfilesByIds');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function getSessions() {
|
||||
if (isCallInProgress('getSessions')) {
|
||||
return;
|
||||
}
|
||||
|
||||
callTracker.getSessions = utils.getTimestamp();
|
||||
Client.getSessions(
|
||||
UserStore.getCurrentId(),
|
||||
(data) => {
|
||||
callTracker.getSessions = 0;
|
||||
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECEIVED_SESSIONS,
|
||||
sessions: data
|
||||
});
|
||||
},
|
||||
(err) => {
|
||||
callTracker.getSessions = 0;
|
||||
dispatchError(err, 'getSessions');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function getAudits() {
|
||||
if (isCallInProgress('getAudits')) {
|
||||
return;
|
||||
}
|
||||
|
||||
callTracker.getAudits = utils.getTimestamp();
|
||||
Client.getAudits(
|
||||
UserStore.getCurrentId(),
|
||||
(data) => {
|
||||
callTracker.getAudits = 0;
|
||||
|
||||
AppDispatcher.handleServerAction({
|
||||
type: ActionTypes.RECEIVED_AUDITS,
|
||||
audits: data
|
||||
});
|
||||
},
|
||||
(err) => {
|
||||
callTracker.getAudits = 0;
|
||||
dispatchError(err, 'getAudits');
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
export function getLogs() {
|
||||
if (isCallInProgress('getLogs')) {
|
||||
return;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// See License.txt for license information.
|
||||
|
||||
import * as Utils from './utils.jsx';
|
||||
import ChannelInviteModal from 'components/channel_invite_modal.jsx';
|
||||
import ChannelInviteModal from 'components/channel_invite_modal';
|
||||
import EditChannelHeaderModal from 'components/edit_channel_header_modal.jsx';
|
||||
import ToggleModalButton from 'components/toggle_modal_button.jsx';
|
||||
import UserProfile from 'components/user_profile.jsx';
|
||||
|
||||
@@ -23,7 +23,7 @@ if (NPM_TARGET === 'test') {
|
||||
}
|
||||
|
||||
var config = {
|
||||
entry: ['babel-polyfill', './root.jsx', 'root.html'],
|
||||
entry: ['babel-polyfill', 'whatwg-fetch', './root.jsx', 'root.html'],
|
||||
output: {
|
||||
path: 'dist',
|
||||
publicPath: '/static/',
|
||||
@@ -33,7 +33,7 @@ var config = {
|
||||
module: {
|
||||
loaders: [
|
||||
{
|
||||
test: /\.jsx?$/,
|
||||
test: /\.(js|jsx)?$/,
|
||||
loader: 'babel-loader',
|
||||
exclude: /(node_modules|non_npm_dependencies)/,
|
||||
query: {
|
||||
|
||||
Ссылка в новой задаче
Block a user