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 (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
l4g "github.com/alecthomas/log4go"
|
l4g "github.com/alecthomas/log4go"
|
||||||
"github.com/mattermost/platform/app"
|
"github.com/mattermost/platform/app"
|
||||||
@@ -202,7 +203,14 @@ func getClientConfig(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
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) {
|
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) {
|
if HandleEtag(etag, "Get User", w, r) {
|
||||||
return
|
return
|
||||||
} else {
|
} 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.Header().Set(model.HEADER_ETAG_SERVER, etag)
|
||||||
w.Write([]byte(user.ToJson()))
|
w.Write([]byte(user.ToJson()))
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -5,21 +5,12 @@ import Client from 'client/web_client.jsx';
|
|||||||
import * as AsyncClient from 'utils/async_client.jsx';
|
import * as AsyncClient from 'utils/async_client.jsx';
|
||||||
import {browserHistory} from 'react-router/es6';
|
import {browserHistory} from 'react-router/es6';
|
||||||
|
|
||||||
export function revokeSession(altId, success, error) {
|
// Redux actions
|
||||||
Client.revokeSession(altId,
|
import store from 'stores/redux_store.jsx';
|
||||||
() => {
|
const dispatch = store.dispatch;
|
||||||
AsyncClient.getSessions();
|
const getState = store.getState;
|
||||||
if (success) {
|
|
||||||
success();
|
import {getUser} from 'mattermost-redux/actions/users';
|
||||||
}
|
|
||||||
},
|
|
||||||
(err) => {
|
|
||||||
if (error) {
|
|
||||||
error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function saveConfig(config, success, error) {
|
export function saveConfig(config, success, error) {
|
||||||
Client.saveConfig(
|
Client.saveConfig(
|
||||||
@@ -57,7 +48,7 @@ export function adminResetMfa(userId, success, error) {
|
|||||||
Client.adminResetMfa(
|
Client.adminResetMfa(
|
||||||
userId,
|
userId,
|
||||||
() => {
|
() => {
|
||||||
AsyncClient.getUser(userId);
|
getUser(userId)(dispatch, getState);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
success();
|
success();
|
||||||
|
|||||||
@@ -10,6 +10,12 @@ import Client from 'client/web_client.jsx';
|
|||||||
|
|
||||||
import {ActionTypes} from 'utils/constants.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) {
|
export function loadEmoji(getProfiles = true) {
|
||||||
Client.listEmoji(
|
Client.listEmoji(
|
||||||
(data) => {
|
(data) => {
|
||||||
@@ -42,5 +48,5 @@ function loadProfilesForEmoji(emojiList) {
|
|||||||
return;
|
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 BrowserStore from 'stores/browser_store.jsx';
|
||||||
import ErrorStore from 'stores/error_store.jsx';
|
import ErrorStore from 'stores/error_store.jsx';
|
||||||
import TeamStore from 'stores/team_store.jsx';
|
import TeamStore from 'stores/team_store.jsx';
|
||||||
import PreferenceStore from 'stores/preference_store.jsx';
|
|
||||||
import SearchStore from 'stores/search_store.jsx';
|
import SearchStore from 'stores/search_store.jsx';
|
||||||
|
|
||||||
import {handleNewPost, loadPosts, loadPostsBefore, loadPostsAfter} from 'actions/post_actions.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 * as I18n from 'i18n/i18n.jsx';
|
||||||
import {browserHistory} from 'react-router/es6';
|
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) {
|
export function emitChannelClickEvent(channel) {
|
||||||
function userVisitedFakeChannel(chan, success, fail) {
|
function userVisitedFakeChannel(chan, success, fail) {
|
||||||
const otherUserId = Utils.getUserIdFromChannelName(chan);
|
const otherUserId = Utils.getUserIdFromChannelName(chan);
|
||||||
@@ -77,6 +82,11 @@ export function emitChannelClickEvent(channel) {
|
|||||||
channelMember,
|
channelMember,
|
||||||
prev: oldChannelId
|
prev: oldChannelId
|
||||||
});
|
});
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: ChannelTypes.SELECT_CHANNEL,
|
||||||
|
data: chan.id
|
||||||
|
}, getState);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (channel.fake) {
|
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) {
|
export function doFocusPost(channelId, postId, data) {
|
||||||
AppDispatcher.handleServerAction({
|
AppDispatcher.handleServerAction({
|
||||||
type: ActionTypes.RECEIVED_FOCUSED_POST,
|
type: ActionTypes.RECEIVED_FOCUSED_POST,
|
||||||
@@ -536,12 +467,11 @@ export function emitUserLoggedOutEvent(redirectTo = '/', shouldSignalLogout = tr
|
|||||||
export function clientLogout(redirectTo = '/') {
|
export function clientLogout(redirectTo = '/') {
|
||||||
BrowserStore.clear();
|
BrowserStore.clear();
|
||||||
ErrorStore.clearLastError();
|
ErrorStore.clearLastError();
|
||||||
PreferenceStore.clear();
|
|
||||||
UserStore.clear();
|
|
||||||
TeamStore.clear();
|
TeamStore.clear();
|
||||||
ChannelStore.clear();
|
ChannelStore.clear();
|
||||||
stopPeriodicStatusUpdates();
|
stopPeriodicStatusUpdates();
|
||||||
WebsocketActions.close();
|
WebsocketActions.close();
|
||||||
|
localStorage.removeItem('currentUserId');
|
||||||
window.location.href = redirectTo;
|
window.location.href = redirectTo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,12 @@ import Client from 'client/web_client.jsx';
|
|||||||
|
|
||||||
import {ActionTypes} from 'utils/constants.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() {
|
export function loadIncomingHooks() {
|
||||||
Client.listIncomingHooks(
|
Client.listIncomingHooks(
|
||||||
(data) => {
|
(data) => {
|
||||||
@@ -42,7 +48,7 @@ function loadProfilesForIncomingHooks(hooks) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncClient.getProfilesByIds(list);
|
getProfilesByIds(list)(dispatch, getState);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loadOutgoingHooks() {
|
export function loadOutgoingHooks() {
|
||||||
@@ -76,7 +82,7 @@ function loadProfilesForOutgoingHooks(hooks) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncClient.getProfilesByIds(list);
|
getProfilesByIds(list)(dispatch, getState);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loadTeamCommands() {
|
export function loadTeamCommands() {
|
||||||
@@ -110,5 +116,5 @@ function loadProfilesForCommands(commands) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncClient.getProfilesByIds(list);
|
getProfilesByIds(list)(dispatch, getState);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,12 @@ import Constants from 'utils/constants.jsx';
|
|||||||
const ActionTypes = Constants.ActionTypes;
|
const ActionTypes = Constants.ActionTypes;
|
||||||
const Preferences = Constants.Preferences;
|
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) {
|
export function handleNewPost(post, msg) {
|
||||||
let websocketMessageProps = {};
|
let websocketMessageProps = {};
|
||||||
if (msg) {
|
if (msg) {
|
||||||
@@ -310,7 +316,7 @@ export function loadProfilesForPosts(posts) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncClient.getProfilesByIds(list);
|
getProfilesByIds(list)(dispatch, getState);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function addReaction(channelId, postId, emojiName) {
|
export function addReaction(channelId, postId, emojiName) {
|
||||||
|
|||||||
@@ -1,16 +1,19 @@
|
|||||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
import AppDispatcher from 'dispatcher/app_dispatcher.jsx';
|
|
||||||
|
|
||||||
import ChannelStore from 'stores/channel_store.jsx';
|
import ChannelStore from 'stores/channel_store.jsx';
|
||||||
import PostStore from 'stores/post_store.jsx';
|
import PostStore from 'stores/post_store.jsx';
|
||||||
import PreferenceStore from 'stores/preference_store.jsx';
|
import PreferenceStore from 'stores/preference_store.jsx';
|
||||||
import UserStore from 'stores/user_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()) {
|
export function loadStatusesForChannel(channelId = ChannelStore.getCurrentId()) {
|
||||||
const postList = PostStore.getVisiblePosts(channelId);
|
const postList = PostStore.getVisiblePosts(channelId);
|
||||||
@@ -108,15 +111,7 @@ export function loadStatusesByIds(userIds) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Client.getStatusesByIds(
|
getStatusesByIds(userIds)(dispatch, getState);
|
||||||
userIds,
|
|
||||||
(data) => {
|
|
||||||
AppDispatcher.handleServerAction({
|
|
||||||
type: ActionTypes.RECEIVED_STATUSES,
|
|
||||||
statuses: data
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let intervalId = '';
|
let intervalId = '';
|
||||||
|
|||||||
@@ -13,6 +13,13 @@ import AppDispatcher from 'dispatcher/app_dispatcher.jsx';
|
|||||||
|
|
||||||
import {browserHistory} from 'react-router/es6';
|
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) {
|
export function checkIfTeamExists(teamName, onSuccess, onError) {
|
||||||
Client.findTeamByName(teamName, onSuccess, onError);
|
Client.findTeamByName(teamName, onSuccess, onError);
|
||||||
}
|
}
|
||||||
@@ -62,7 +69,7 @@ export function removeUserFromTeam(teamId, userId, success, error) {
|
|||||||
TeamStore.removeMemberInTeam(teamId, userId);
|
TeamStore.removeMemberInTeam(teamId, userId);
|
||||||
UserStore.removeProfileFromTeam(teamId, userId);
|
UserStore.removeProfileFromTeam(teamId, userId);
|
||||||
UserStore.emitInTeamChange();
|
UserStore.emitInTeamChange();
|
||||||
AsyncClient.getUser(userId);
|
getUser(userId)(dispatch, getState);
|
||||||
AsyncClient.getTeamStats(teamId);
|
AsyncClient.getTeamStats(teamId);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
|
|||||||
@@ -19,6 +19,79 @@ import Client from 'client/web_client.jsx';
|
|||||||
import {Constants, ActionTypes, Preferences} from 'utils/constants.jsx';
|
import {Constants, ActionTypes, Preferences} from 'utils/constants.jsx';
|
||||||
import {browserHistory} from 'react-router/es6';
|
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) {
|
export function switchFromLdapToEmail(email, password, token, ldapPassword, onSuccess, onError) {
|
||||||
Client.ldapToEmail(
|
Client.ldapToEmail(
|
||||||
email,
|
email,
|
||||||
@@ -38,80 +111,30 @@ export function switchFromLdapToEmail(email, password, token, ldapPassword, onSu
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loadProfilesAndTeamMembers(offset, limit, teamId = TeamStore.getCurrentId(), success, error) {
|
export function loadProfilesAndTeamMembers(page, perPage, teamId = TeamStore.getCurrentId(), success) {
|
||||||
Client.getProfilesInTeam(
|
getProfilesInTeam(teamId, page, perPage)(dispatch, getState).then(
|
||||||
teamId,
|
|
||||||
offset,
|
|
||||||
limit,
|
|
||||||
(data) => {
|
(data) => {
|
||||||
AppDispatcher.handleServerAction({
|
loadTeamMembersForProfilesList(data, teamId, success);
|
||||||
type: ActionTypes.RECEIVED_PROFILES_IN_TEAM,
|
loadStatusesForProfilesList(data);
|
||||||
profiles: data,
|
|
||||||
team_id: teamId,
|
|
||||||
offset,
|
|
||||||
count: Object.keys(data).length
|
|
||||||
});
|
|
||||||
|
|
||||||
loadTeamMembersForProfilesMap(data, teamId, success, error);
|
|
||||||
loadStatusesForProfilesMap(data);
|
|
||||||
},
|
|
||||||
(err) => {
|
|
||||||
AsyncClient.dispatchError(err, 'getProfilesInTeam');
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loadProfilesAndTeamMembersAndChannelMembers(offset, limit, teamId = TeamStore.getCurrentId(), channelId = ChannelStore.getCurrentId(), success, error) {
|
export function loadProfilesAndTeamMembersAndChannelMembers(page, perPage, teamId = TeamStore.getCurrentId(), channelId = ChannelStore.getCurrentId(), success, error) {
|
||||||
Client.getProfilesInChannel(
|
getProfilesInChannel(channelId, page, perPage)(dispatch, getState).then(
|
||||||
channelId,
|
|
||||||
offset,
|
|
||||||
limit,
|
|
||||||
(data) => {
|
(data) => {
|
||||||
AppDispatcher.handleServerAction({
|
loadTeamMembersForProfilesList(
|
||||||
type: ActionTypes.RECEIVED_PROFILES_IN_CHANNEL,
|
|
||||||
profiles: data,
|
|
||||||
channel_id: channelId,
|
|
||||||
offset,
|
|
||||||
count: Object.keys(data).length
|
|
||||||
});
|
|
||||||
|
|
||||||
loadTeamMembersForProfilesMap(
|
|
||||||
data,
|
data,
|
||||||
teamId,
|
teamId,
|
||||||
() => {
|
() => {
|
||||||
loadChannelMembersForProfilesMap(data, channelId, success, error);
|
loadChannelMembersForProfilesList(data, channelId, success, error);
|
||||||
loadStatusesForProfilesMap(data);
|
loadStatusesForProfilesList(data);
|
||||||
});
|
}
|
||||||
},
|
);
|
||||||
(err) => {
|
|
||||||
AsyncClient.dispatchError(err, 'getProfilesInChannel');
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
export function loadTeamMembersForProfilesList(profiles, teamId = TeamStore.getCurrentId(), success, error) {
|
||||||
const membersToLoad = {};
|
const membersToLoad = {};
|
||||||
for (let i = 0; i < profiles.length; i++) {
|
for (let i = 0; i < profiles.length; i++) {
|
||||||
@@ -133,24 +156,13 @@ export function loadTeamMembersForProfilesList(profiles, teamId = TeamStore.getC
|
|||||||
loadTeamMembersForProfiles(list, teamId, success, error);
|
loadTeamMembersForProfiles(list, teamId, success, error);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loadProfilesWithoutTeam(page, perPage, success, error) {
|
export function loadProfilesWithoutTeam(page, perPage, success) {
|
||||||
Client.getProfilesWithoutTeam(
|
getProfilesWithoutTeam(page, perPage)(dispatch, getState).then(
|
||||||
page,
|
|
||||||
perPage,
|
|
||||||
(data) => {
|
(data) => {
|
||||||
AppDispatcher.handleServerAction({
|
|
||||||
type: ActionTypes.RECEIVED_PROFILES_WITHOUT_TEAM,
|
|
||||||
profiles: data,
|
|
||||||
page
|
|
||||||
});
|
|
||||||
|
|
||||||
loadStatusesForProfilesMap(data);
|
loadStatusesForProfilesMap(data);
|
||||||
},
|
|
||||||
(err) => {
|
|
||||||
AsyncClient.dispatchError(err, 'getProfilesWithoutTeam');
|
|
||||||
|
|
||||||
if (error) {
|
if (success) {
|
||||||
error(err);
|
success(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -248,9 +260,9 @@ function populateDMChannelsWithProfiles(userIds) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function populateChannelWithProfiles(channelId, userIds) {
|
function populateChannelWithProfiles(channelId, users) {
|
||||||
for (let i = 0; i < userIds.length; i++) {
|
for (let i = 0; i < users.length; i++) {
|
||||||
UserStore.saveUserIdInChannel(channelId, userIds[i]);
|
UserStore.saveUserIdInChannel(channelId, users[i].id);
|
||||||
}
|
}
|
||||||
UserStore.emitInChannelChange();
|
UserStore.emitInChannelChange();
|
||||||
}
|
}
|
||||||
@@ -360,17 +372,9 @@ export function loadProfilesForGM() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
Client.getProfilesInChannel(
|
getProfilesInChannel(channel.id, 0, Constants.MAX_USERS_IN_GM)(dispatch, getState).then(
|
||||||
channel.id,
|
|
||||||
0,
|
|
||||||
Constants.MAX_USERS_IN_GM,
|
|
||||||
(data) => {
|
(data) => {
|
||||||
AppDispatcher.handleServerAction({
|
populateChannelWithProfiles(channel.id, data);
|
||||||
type: ActionTypes.RECEIVED_PROFILES,
|
|
||||||
profiles: data
|
|
||||||
});
|
|
||||||
|
|
||||||
populateChannelWithProfiles(channel.id, Object.keys(data));
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -420,20 +424,10 @@ export function loadProfilesForDM() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (profilesToLoad.length > 0) {
|
if (profilesToLoad.length > 0) {
|
||||||
Client.getProfilesByIds(
|
getProfilesByIds(profilesToLoad)(dispatch, getState).then(
|
||||||
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
|
|
||||||
populateDMChannelsWithProfiles(profileIds);
|
populateDMChannelsWithProfiles(profileIds);
|
||||||
},
|
},
|
||||||
(err) => {
|
|
||||||
AsyncClient.dispatchError(err, 'getProfilesByIds');
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
populateDMChannelsWithProfiles(profileIds);
|
populateDMChannelsWithProfiles(profileIds);
|
||||||
@@ -491,119 +485,70 @@ function onThemeSaved(teamId, theme, onSuccess) {
|
|||||||
onSuccess();
|
onSuccess();
|
||||||
}
|
}
|
||||||
|
|
||||||
export function searchUsers(term, teamId = TeamStore.getCurrentId(), options = {}, success, error) {
|
export function searchUsers(term, teamId = TeamStore.getCurrentId(), options = {}, success) {
|
||||||
Client.searchUsers(
|
searchProfiles(term, {team_id: teamId, ...options})(dispatch, getState).then(
|
||||||
term,
|
|
||||||
teamId,
|
|
||||||
options,
|
|
||||||
(data) => {
|
(data) => {
|
||||||
loadStatusesForProfilesList(data);
|
loadStatusesForProfilesList(data);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
success(data);
|
success(data);
|
||||||
}
|
}
|
||||||
},
|
|
||||||
(err) => {
|
|
||||||
AsyncClient.dispatchError(err, 'searchUsers');
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
error(err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function searchUsersNotInTeam(term, teamId = TeamStore.getCurrentId(), options = {}, success, error) {
|
export function searchUsersNotInTeam(term, teamId = TeamStore.getCurrentId(), options = {}, success) {
|
||||||
Client.searchUsersNotInTeam(
|
searchProfiles(term, {not_in_team_id: teamId, ...options})(dispatch, getState).then(
|
||||||
term,
|
|
||||||
teamId,
|
|
||||||
options,
|
|
||||||
(data) => {
|
(data) => {
|
||||||
loadStatusesForProfilesList(data);
|
loadStatusesForProfilesList(data);
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
success(data);
|
success(data);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
(err) => {
|
);
|
||||||
AsyncClient.dispatchError(err, 'searchUsersNotInTeam');
|
}
|
||||||
|
|
||||||
if (error) {
|
export function autocompleteUsersInChannel(username, channelId, success) {
|
||||||
error(err);
|
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) {
|
export function autocompleteUsersInTeam(username, success) {
|
||||||
Client.autocompleteUsersInChannel(
|
autocompleteRedux(username, TeamStore.getCurrentId())(dispatch, getState).then(
|
||||||
username,
|
|
||||||
channelId,
|
|
||||||
(data) => {
|
(data) => {
|
||||||
if (success) {
|
if (success) {
|
||||||
success(data);
|
success(data);
|
||||||
}
|
}
|
||||||
},
|
|
||||||
(err) => {
|
|
||||||
AsyncClient.dispatchError(err, 'autocompleteUsersInChannel');
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
error(err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function autocompleteUsersInTeam(username, success, error) {
|
export function autocompleteUsers(username, success) {
|
||||||
Client.autocompleteUsersInTeam(
|
autocompleteRedux(username)(dispatch, getState).then(
|
||||||
username,
|
|
||||||
(data) => {
|
(data) => {
|
||||||
if (success) {
|
if (success) {
|
||||||
success(data);
|
success(data);
|
||||||
}
|
}
|
||||||
},
|
|
||||||
(err) => {
|
|
||||||
AsyncClient.dispatchError(err, 'autocompleteUsersInTeam');
|
|
||||||
|
|
||||||
if (error) {
|
|
||||||
error(err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function autocompleteUsers(username, success, error) {
|
export function updateUser(user, type, success, error) {
|
||||||
Client.autocompleteUsers(
|
updateMe(user)(dispatch, getState).then(
|
||||||
username,
|
|
||||||
(data) => {
|
(data) => {
|
||||||
if (success) {
|
if (data && success) {
|
||||||
success(data);
|
success(data);
|
||||||
}
|
} else if (data == null && error) {
|
||||||
},
|
const serverError = getState().requests.users.updateUser.error;
|
||||||
(err) => {
|
error({id: serverError.server_error_id, ...serverError});
|
||||||
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');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -626,74 +571,55 @@ export function generateMfaSecret(success, error) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateUserNotifyProps(data, success, error) {
|
export function updateUserNotifyProps(props, success, error) {
|
||||||
Client.updateUserNotifyProps(
|
updateMe({notify_props: props})(dispatch, getState).then(
|
||||||
data,
|
(data) => {
|
||||||
() => {
|
if (data && success) {
|
||||||
AsyncClient.getMe();
|
success(data);
|
||||||
|
} else if (data == null && error) {
|
||||||
if (success) {
|
const serverError = getState().requests.users.updateMe.error;
|
||||||
success();
|
error({id: serverError.server_error_id, ...serverError});
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
(err) => {
|
|
||||||
if (error) {
|
|
||||||
error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateUserRoles(userId, newRoles, success, error) {
|
export function updateUserRoles(userId, newRoles, success, error) {
|
||||||
Client.updateUserRoles(
|
updateUserRoles(userId, newRoles)(dispatch, getState).then(
|
||||||
userId,
|
(data) => {
|
||||||
newRoles,
|
if (data && success) {
|
||||||
() => {
|
success(data);
|
||||||
AsyncClient.getUser(
|
} else if (data == null && error) {
|
||||||
userId,
|
const serverError = getState().requests.users.updateUser.error;
|
||||||
success,
|
error({id: serverError.server_error_id, ...serverError});
|
||||||
error
|
}
|
||||||
);
|
}
|
||||||
},
|
|
||||||
error
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function activateMfa(code, success, error) {
|
export function activateMfa(code, success, error) {
|
||||||
Client.updateMfa(
|
updateUserMfa(UserStore.getCurrentId(), true, code)(dispatch, getState).then(
|
||||||
code,
|
(data) => {
|
||||||
true,
|
if (data && success) {
|
||||||
() => {
|
success(data);
|
||||||
AsyncClient.getMe();
|
} else if (data == null && error) {
|
||||||
|
const serverError = getState().requests.users.updateUser.error;
|
||||||
if (success) {
|
error({id: serverError.server_error_id, ...serverError});
|
||||||
success();
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(err) => {
|
|
||||||
if (error) {
|
|
||||||
error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deactivateMfa(success, error) {
|
export function deactivateMfa(success, error) {
|
||||||
Client.updateMfa(
|
updateUserMfa(UserStore.getCurrentId(), false)(dispatch, getState).then(
|
||||||
'',
|
(data) => {
|
||||||
false,
|
if (data && success) {
|
||||||
() => {
|
success(data);
|
||||||
AsyncClient.getMe();
|
} else if (data == null && error) {
|
||||||
|
const serverError = getState().requests.users.updateUser.error;
|
||||||
if (success) {
|
error({id: serverError.server_error_id, ...serverError});
|
||||||
success();
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
(err) => {
|
|
||||||
if (error) {
|
|
||||||
error(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -703,16 +629,13 @@ export function checkMfa(loginId, success, error) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Client.checkMfa(
|
checkMfaRedux(loginId)(dispatch, getState).then(
|
||||||
loginId,
|
|
||||||
(data) => {
|
(data) => {
|
||||||
if (success) {
|
if (data && success) {
|
||||||
success(data && data.mfa_required === 'true');
|
success(data);
|
||||||
}
|
} else if (data == null && error) {
|
||||||
},
|
const serverError = getState().requests.users.checkMfa.error;
|
||||||
(err) => {
|
error({id: serverError.server_error_id, ...serverError});
|
||||||
if (error) {
|
|
||||||
error(err);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -735,15 +658,13 @@ export function updateActive(userId, active, success, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function updatePassword(userId, currentPassword, newPassword, success, error) {
|
export function updatePassword(userId, currentPassword, newPassword, success, error) {
|
||||||
Client.updatePassword(userId, currentPassword, newPassword,
|
updateUserPassword(userId, currentPassword, newPassword)(dispatch, getState).then(
|
||||||
() => {
|
(data) => {
|
||||||
if (success) {
|
if (data && success) {
|
||||||
success();
|
success(data);
|
||||||
}
|
} else if (data == null && error) {
|
||||||
},
|
const serverError = getState().requests.users.updateUser.error;
|
||||||
(err) => {
|
error({id: serverError.server_error_id, ...serverError});
|
||||||
if (error) {
|
|
||||||
error(err);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -820,37 +741,27 @@ export function loginById(userId, password, mfaToken, success, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function createUserWithInvite(user, data, emailHash, inviteId, success, error) {
|
export function createUserWithInvite(user, data, emailHash, inviteId, success, error) {
|
||||||
Client.createUserWithInvite(
|
createUser(user, data, emailHash, inviteId)(dispatch, getState).then(
|
||||||
user,
|
(resp) => {
|
||||||
data,
|
if (resp && success) {
|
||||||
emailHash,
|
success(resp);
|
||||||
inviteId,
|
} else if (resp == null && error) {
|
||||||
(response) => {
|
const serverError = getState().requests.users.create.error;
|
||||||
if (success) {
|
error({id: serverError.server_error_id, ...serverError});
|
||||||
success(response);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
(err) => {
|
|
||||||
if (error) {
|
|
||||||
error(err);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function webLogin(loginId, password, token, success, error) {
|
export function webLogin(loginId, password, token, success, error) {
|
||||||
Client.webLogin(
|
login(loginId, password, token)(dispatch, getState).then(
|
||||||
loginId,
|
(ok) => {
|
||||||
password,
|
if (ok && success) {
|
||||||
token,
|
localStorage.setItem('currentUserId', UserStore.getCurrentId());
|
||||||
() => {
|
|
||||||
if (success) {
|
|
||||||
success();
|
success();
|
||||||
}
|
} else if (!ok && error) {
|
||||||
},
|
const serverError = getState().requests.users.login.error;
|
||||||
(err) => {
|
error({id: serverError.server_error_id, ...serverError});
|
||||||
if (error) {
|
|
||||||
error(err);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -907,7 +818,7 @@ export function uploadProfileImage(userPicture, success, error) {
|
|||||||
Client.uploadProfileImage(
|
Client.uploadProfileImage(
|
||||||
userPicture,
|
userPicture,
|
||||||
() => {
|
() => {
|
||||||
AsyncClient.getMe();
|
getMe()(dispatch, getState);
|
||||||
if (success) {
|
if (success) {
|
||||||
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) {
|
export function loadProfiles(page, perPage, success) {
|
||||||
Client.getProfiles(
|
getProfiles(page, perPage)(dispatch, getState).then(
|
||||||
offset,
|
|
||||||
limit,
|
|
||||||
(data) => {
|
(data) => {
|
||||||
AppDispatcher.handleServerAction({
|
|
||||||
type: ActionTypes.RECEIVED_PROFILES,
|
|
||||||
profiles: data
|
|
||||||
});
|
|
||||||
|
|
||||||
if (success) {
|
if (success) {
|
||||||
success(data);
|
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));
|
const missingIds = ids.filter((id) => !UserStore.hasProfile(id));
|
||||||
|
|
||||||
if (missingIds.length === 0) {
|
if (missingIds.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncClient.getProfilesByIds(missingIds, success, error);
|
getProfilesByIds(missingIds)(dispatch, getState);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loadMyTeamMembers() {
|
export function loadMyTeamMembers() {
|
||||||
|
|||||||
@@ -338,7 +338,6 @@ function handleUserUpdatedEvent(msg) {
|
|||||||
const user = msg.data.user;
|
const user = msg.data.user;
|
||||||
if (UserStore.getCurrentId() !== user.id) {
|
if (UserStore.getCurrentId() !== user.id) {
|
||||||
UserStore.saveProfile(user);
|
UserStore.saveProfile(user);
|
||||||
UserStore.emitChange(user.id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
import LoadingScreen from './loading_screen.jsx';
|
import LoadingScreen from 'components/loading_screen.jsx';
|
||||||
import AuditTable from './audit_table.jsx';
|
import AuditTable from 'components/audit_table.jsx';
|
||||||
|
|
||||||
import UserStore from 'stores/user_store.jsx';
|
import UserStore from 'stores/user_store.jsx';
|
||||||
|
|
||||||
import * as AsyncClient from 'utils/async_client.jsx';
|
|
||||||
import * as Utils from 'utils/utils.jsx';
|
import * as Utils from 'utils/utils.jsx';
|
||||||
|
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
@@ -16,6 +15,13 @@ import {Modal} from 'react-bootstrap';
|
|||||||
import {FormattedMessage} from 'react-intl';
|
import {FormattedMessage} from 'react-intl';
|
||||||
|
|
||||||
export default class AccessHistoryModal extends React.Component {
|
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) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
@@ -37,7 +43,7 @@ export default class AccessHistoryModal extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onShow() {
|
onShow() {
|
||||||
AsyncClient.getAudits();
|
this.props.actions.getUserAudits(UserStore.getCurrentId(), 0, 200);
|
||||||
if (!Utils.isMobile()) {
|
if (!Utils.isMobile()) {
|
||||||
$('.modal-body').perfectScrollbar();
|
$('.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.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See License.txt for license information.
|
// 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 UserStore from 'stores/user_store.jsx';
|
||||||
|
|
||||||
import * as AsyncClient from 'utils/async_client.jsx';
|
|
||||||
import * as Utils from 'utils/utils.jsx';
|
import * as Utils from 'utils/utils.jsx';
|
||||||
|
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
@@ -13,9 +12,15 @@ import React from 'react';
|
|||||||
import {Modal} from 'react-bootstrap';
|
import {Modal} from 'react-bootstrap';
|
||||||
import {FormattedMessage, FormattedTime, FormattedDate} from 'react-intl';
|
import {FormattedMessage, FormattedTime, FormattedDate} from 'react-intl';
|
||||||
|
|
||||||
import {revokeSession} from 'actions/admin_actions.jsx';
|
|
||||||
|
|
||||||
export default class ActivityLogModal extends React.Component {
|
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) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
@@ -35,7 +40,6 @@ export default class ActivityLogModal extends React.Component {
|
|||||||
getStateFromStores() {
|
getStateFromStores() {
|
||||||
return {
|
return {
|
||||||
sessions: UserStore.getSessions(),
|
sessions: UserStore.getSessions(),
|
||||||
serverError: null,
|
|
||||||
clientError: null
|
clientError: null
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -47,18 +51,11 @@ export default class ActivityLogModal extends React.Component {
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
modalContent.removeClass('animation--highlight');
|
modalContent.removeClass('animation--highlight');
|
||||||
}, 1500);
|
}, 1500);
|
||||||
revokeSession(altId,
|
this.props.actions.revokeSession(UserStore.getCurrentId(), altId);
|
||||||
null,
|
|
||||||
(err) => {
|
|
||||||
const state = this.getStateFromStores();
|
|
||||||
state.serverError = err;
|
|
||||||
this.setState(state);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onShow() {
|
onShow() {
|
||||||
AsyncClient.getSessions();
|
this.props.actions.getSessions(UserStore.getCurrentId());
|
||||||
if (!Utils.isMobile()) {
|
if (!Utils.isMobile()) {
|
||||||
$('.modal-body').perfectScrollbar();
|
$('.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 UserStore from 'stores/user_store.jsx';
|
||||||
import TeamStore from 'stores/team_store.jsx';
|
import TeamStore from 'stores/team_store.jsx';
|
||||||
|
|
||||||
import * as AsyncClient from 'utils/async_client.jsx';
|
|
||||||
import Constants from 'utils/constants.jsx';
|
import Constants from 'utils/constants.jsx';
|
||||||
import {displayUsernameForUser} from 'utils/utils.jsx';
|
import {displayUsernameForUser} from 'utils/utils.jsx';
|
||||||
import Client from 'client/web_client.jsx';
|
import Client from 'client/web_client.jsx';
|
||||||
@@ -20,10 +19,20 @@ import {Modal} from 'react-bootstrap';
|
|||||||
import {FormattedMessage} from 'react-intl';
|
import {FormattedMessage} from 'react-intl';
|
||||||
import {browserHistory} from 'react-router/es6';
|
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 USERS_PER_PAGE = 50;
|
||||||
const MAX_SELECTABLE_VALUES = 20;
|
const MAX_SELECTABLE_VALUES = 20;
|
||||||
|
|
||||||
export default class AddUsersToTeam extends React.Component {
|
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) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
@@ -34,11 +43,12 @@ export default class AddUsersToTeam extends React.Component {
|
|||||||
this.onChange = this.onChange.bind(this);
|
this.onChange = this.onChange.bind(this);
|
||||||
this.search = this.search.bind(this);
|
this.search = this.search.bind(this);
|
||||||
this.addValue = this.addValue.bind(this);
|
this.addValue = this.addValue.bind(this);
|
||||||
|
this.handlePageChange = this.handlePageChange.bind(this);
|
||||||
|
|
||||||
this.searchTimeoutId = 0;
|
this.searchTimeoutId = 0;
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
users: null,
|
users: Object.assign([], UserStore.getProfileListNotInTeam(TeamStore.getCurrentId(), true)),
|
||||||
values: [],
|
values: [],
|
||||||
show: true,
|
show: true,
|
||||||
search: false
|
search: false
|
||||||
@@ -50,7 +60,7 @@ export default class AddUsersToTeam extends React.Component {
|
|||||||
UserStore.addNotInTeamChangeListener(this.onChange);
|
UserStore.addNotInTeamChangeListener(this.onChange);
|
||||||
UserStore.addStatusesChangeListener(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() {
|
componentWillUnmount() {
|
||||||
@@ -97,13 +107,14 @@ export default class AddUsersToTeam extends React.Component {
|
|||||||
this.setState({values});
|
this.setState({values});
|
||||||
}
|
}
|
||||||
|
|
||||||
onChange(force) {
|
onChange() {
|
||||||
if (this.state.search && !force) {
|
let users;
|
||||||
return;
|
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++) {
|
for (let i = 0; i < users.length; i++) {
|
||||||
const user = Object.assign({}, users[i]);
|
const user = Object.assign({}, users[i]);
|
||||||
user.value = user.id;
|
user.value = user.id;
|
||||||
@@ -118,53 +129,25 @@ export default class AddUsersToTeam extends React.Component {
|
|||||||
|
|
||||||
handlePageChange(page, prevPage) {
|
handlePageChange(page, prevPage) {
|
||||||
if (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) {
|
search(term) {
|
||||||
clearTimeout(this.searchTimeoutId);
|
clearTimeout(this.searchTimeoutId);
|
||||||
|
this.term = term;
|
||||||
|
|
||||||
if (term === '') {
|
if (term === '') {
|
||||||
this.onChange(true);
|
this.onChange();
|
||||||
this.setState({search: false});
|
|
||||||
this.searchTimeoutId = '';
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const teamId = TeamStore.getCurrentId();
|
this.searchTimeoutId = setTimeout(
|
||||||
|
|
||||||
const searchTimeoutId = setTimeout(
|
|
||||||
() => {
|
() => {
|
||||||
searchUsersNotInTeam(
|
searchUsersNotInTeam(term, TeamStore.getCurrentId(), {});
|
||||||
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});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
Constants.SEARCH_TIMEOUT_MILLISECONDS
|
Constants.SEARCH_TIMEOUT_MILLISECONDS
|
||||||
);
|
);
|
||||||
|
|
||||||
this.searchTimeoutId = searchTimeoutId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDelete(values) {
|
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 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 ALL_USERS = '';
|
||||||
const NO_TEAM = 'no_team';
|
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) {
|
updateUsersFromStore(teamId = this.state.teamId, term = this.state.term) {
|
||||||
if (term) {
|
if (term) {
|
||||||
if (teamId === this.state.teamId) {
|
let users;
|
||||||
// Search results aren't in the store, so manually update the users in them
|
if (teamId) {
|
||||||
const users = [...this.state.users];
|
users = searchProfilesInTeam(store.getState(), teamId, term);
|
||||||
|
|
||||||
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
|
|
||||||
});
|
|
||||||
} else {
|
} 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,11 +175,11 @@ export default class SystemUsers extends React.Component {
|
|||||||
// Paging isn't supported while searching
|
// Paging isn't supported while searching
|
||||||
|
|
||||||
if (this.state.teamId === ALL_USERS) {
|
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) {
|
} else if (this.state.teamId === NO_TEAM) {
|
||||||
loadProfilesWithoutTeam(page + 1, USERS_PER_PAGE, this.loadComplete);
|
loadProfilesWithoutTeam(page + 1, USERS_PER_PAGE, this.loadComplete);
|
||||||
} else {
|
} 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) {
|
doSearch(teamId, term, now = false) {
|
||||||
clearTimeout(this.searchTimeoutId);
|
clearTimeout(this.searchTimeoutId);
|
||||||
|
this.term = term;
|
||||||
|
|
||||||
this.setState({
|
this.setState({loading: true});
|
||||||
loading: true,
|
|
||||||
users: []
|
|
||||||
});
|
|
||||||
|
|
||||||
const options = {
|
const options = {
|
||||||
[UserSearchOptions.ALLOW_INACTIVE]: true
|
[UserSearchOptions.ALLOW_INACTIVE]: true
|
||||||
@@ -217,74 +211,45 @@ export default class SystemUsers extends React.Component {
|
|||||||
options[UserSearchOptions.WITHOUT_TEAM] = true;
|
options[UserSearchOptions.WITHOUT_TEAM] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchTimeoutId = setTimeout(
|
this.searchTimeoutId = setTimeout(
|
||||||
() => {
|
() => {
|
||||||
searchUsers(
|
searchUsers(
|
||||||
term,
|
term,
|
||||||
teamId,
|
teamId,
|
||||||
options,
|
options,
|
||||||
(users) => {
|
(users) => {
|
||||||
if (searchTimeoutId !== this.searchTimeoutId) {
|
if (users.length === 0 && term.length === USER_ID_LENGTH) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (users.length > 0) {
|
|
||||||
this.setState({
|
|
||||||
loading: false,
|
|
||||||
users
|
|
||||||
});
|
|
||||||
} else if (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 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 {
|
} else {
|
||||||
this.setState({
|
this.setState({loading: false});
|
||||||
loading: false
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
this.setState({
|
this.setState({loading: false});
|
||||||
loading: false
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
now ? 0 : Constants.SEARCH_TIMEOUT_MILLISECONDS
|
now ? 0 : Constants.SEARCH_TIMEOUT_MILLISECONDS
|
||||||
);
|
);
|
||||||
|
|
||||||
this.searchTimeoutId = searchTimeoutId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getUserById(id, searchTimeoutId) {
|
getUserById(id) {
|
||||||
if (UserStore.hasProfile(id)) {
|
if (UserStore.hasProfile(id)) {
|
||||||
this.setState({
|
this.setState({loading: false});
|
||||||
loading: false,
|
|
||||||
users: [UserStore.getProfile(id)]
|
|
||||||
});
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
getUser(
|
getUser(
|
||||||
id,
|
id,
|
||||||
(user) => {
|
() => {
|
||||||
if (searchTimeoutId !== this.searchTimeoutId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
loading: false,
|
loading: false
|
||||||
users: [user]
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
if (searchTimeoutId !== this.searchTimeoutId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
loading: false,
|
loading: false
|
||||||
users: []
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -5,11 +5,11 @@ import $ from 'jquery';
|
|||||||
import 'bootstrap';
|
import 'bootstrap';
|
||||||
import NavbarSearchBox from './search_bar.jsx';
|
import NavbarSearchBox from './search_bar.jsx';
|
||||||
import MessageWrapper from './message_wrapper.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 EditChannelHeaderModal from './edit_channel_header_modal.jsx';
|
||||||
import EditChannelPurposeModal from './edit_channel_purpose_modal.jsx';
|
import EditChannelPurposeModal from './edit_channel_purpose_modal.jsx';
|
||||||
import ChannelInfoModal from './channel_info_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 ChannelMembersModal from './channel_members_modal.jsx';
|
||||||
import ChannelNotificationsModal from './channel_notifications_modal.jsx';
|
import ChannelNotificationsModal from './channel_notifications_modal.jsx';
|
||||||
import DeleteChannelModal from './delete_channel_modal.jsx';
|
import DeleteChannelModal from './delete_channel_modal.jsx';
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See License.txt for license information.
|
// 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 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 ChannelStore from 'stores/channel_store.jsx';
|
||||||
import UserStore from 'stores/user_store.jsx';
|
import UserStore from 'stores/user_store.jsx';
|
||||||
@@ -19,9 +19,20 @@ import React from 'react';
|
|||||||
import {Modal} from 'react-bootstrap';
|
import {Modal} from 'react-bootstrap';
|
||||||
import {FormattedMessage} from 'react-intl';
|
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;
|
const USERS_PER_PAGE = 50;
|
||||||
|
|
||||||
export default class ChannelInviteModal extends React.Component {
|
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) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
@@ -39,10 +50,9 @@ export default class ChannelInviteModal extends React.Component {
|
|||||||
const teamStats = TeamStore.getCurrentStats();
|
const teamStats = TeamStore.getCurrentStats();
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
users: null,
|
users: UserStore.getProfileListNotInChannel(props.channel.id, true),
|
||||||
total: teamStats.active_member_count - channelStats.member_count,
|
total: teamStats.active_member_count - channelStats.member_count,
|
||||||
show: true,
|
show: true,
|
||||||
search: false,
|
|
||||||
statusChange: false
|
statusChange: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -53,7 +63,7 @@ export default class ChannelInviteModal extends React.Component {
|
|||||||
UserStore.addNotInChannelChangeListener(this.onChange);
|
UserStore.addNotInChannelChangeListener(this.onChange);
|
||||||
UserStore.addStatusesChangeListener(this.onStatusChange);
|
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());
|
AsyncClient.getTeamStats(TeamStore.getCurrentId());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,17 +74,19 @@ export default class ChannelInviteModal extends React.Component {
|
|||||||
UserStore.removeStatusesChangeListener(this.onStatusChange);
|
UserStore.removeStatusesChangeListener(this.onStatusChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
onChange(force) {
|
onChange() {
|
||||||
if (this.state.search && !force) {
|
let users;
|
||||||
this.search(this.term);
|
if (this.term) {
|
||||||
return;
|
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 channelStats = ChannelStore.getStats(this.props.channel.id);
|
||||||
const teamStats = TeamStore.getCurrentStats();
|
const teamStats = TeamStore.getCurrentStats();
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
users: UserStore.getProfileListNotInChannel(this.props.channel.id, true),
|
users,
|
||||||
total: teamStats.active_member_count - channelStats.member_count
|
total: teamStats.active_member_count - channelStats.member_count
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -103,40 +115,24 @@ export default class ChannelInviteModal extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nextPage(page) {
|
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) {
|
search(term) {
|
||||||
clearTimeout(this.searchTimeoutId);
|
clearTimeout(this.searchTimeoutId);
|
||||||
|
|
||||||
this.term = term;
|
this.term = term;
|
||||||
|
|
||||||
if (term === '') {
|
if (term === '') {
|
||||||
this.onChange(true);
|
this.onChange();
|
||||||
this.setState({search: false});
|
|
||||||
this.searchTimeoutId = '';
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchTimeoutId = setTimeout(
|
this.searchTimeoutId = setTimeout(
|
||||||
() => {
|
() => {
|
||||||
searchUsers(
|
searchUsers(term, TeamStore.getCurrentId(), {not_in_channel_id: this.props.channel.id});
|
||||||
term,
|
|
||||||
TeamStore.getCurrentId(),
|
|
||||||
{not_in_channel_id: this.props.channel.id},
|
|
||||||
(users) => {
|
|
||||||
if (searchTimeoutId !== this.searchTimeoutId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({search: true, users});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
Constants.SEARCH_TIMEOUT_MILLISECONDS
|
Constants.SEARCH_TIMEOUT_MILLISECONDS
|
||||||
);
|
);
|
||||||
|
|
||||||
this.searchTimeoutId = searchTimeoutId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
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) {
|
finishSignin(team) {
|
||||||
GlobalActions.emitInitialLoad(
|
const query = this.props.location.query;
|
||||||
() => {
|
GlobalActions.loadDefaultLocale();
|
||||||
const query = this.props.location.query;
|
if (query.redirect_to) {
|
||||||
GlobalActions.loadDefaultLocale();
|
browserHistory.push(query.redirect_to);
|
||||||
if (query.redirect_to) {
|
} else if (team) {
|
||||||
browserHistory.push(query.redirect_to);
|
browserHistory.push(`/${team.name}`);
|
||||||
} else if (team) {
|
} else {
|
||||||
browserHistory.push(`/${team.name}`);
|
GlobalActions.redirectUserToDefaultTeam();
|
||||||
} else {
|
}
|
||||||
GlobalActions.redirectUserToDefaultTeam();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleLoginIdChange(e) {
|
handleLoginIdChange(e) {
|
||||||
|
|||||||
@@ -17,6 +17,9 @@ import * as UserAgent from 'utils/user_agent.jsx';
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
import store from 'stores/redux_store.jsx';
|
||||||
|
import {searchProfilesInCurrentChannel} from 'mattermost-redux/selectors/entities/users';
|
||||||
|
|
||||||
const USERS_PER_PAGE = 50;
|
const USERS_PER_PAGE = 50;
|
||||||
|
|
||||||
export default class MemberListChannel extends React.Component {
|
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.loadComplete = this.loadComplete.bind(this);
|
||||||
|
|
||||||
this.searchTimeoutId = 0;
|
this.searchTimeoutId = 0;
|
||||||
|
this.term = '';
|
||||||
|
|
||||||
const stats = ChannelStore.getCurrentStats();
|
const stats = ChannelStore.getCurrentStats();
|
||||||
|
|
||||||
@@ -37,8 +41,6 @@ export default class MemberListChannel extends React.Component {
|
|||||||
teamMembers: Object.assign({}, TeamStore.getMembersInTeam()),
|
teamMembers: Object.assign({}, TeamStore.getMembersInTeam()),
|
||||||
channelMembers: Object.assign({}, ChannelStore.getMembersInChannel()),
|
channelMembers: Object.assign({}, ChannelStore.getMembersInChannel()),
|
||||||
total: stats.member_count,
|
total: stats.member_count,
|
||||||
search: false,
|
|
||||||
term: '',
|
|
||||||
loading: true
|
loading: true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -66,16 +68,16 @@ export default class MemberListChannel extends React.Component {
|
|||||||
this.setState({loading: false});
|
this.setState({loading: false});
|
||||||
}
|
}
|
||||||
|
|
||||||
onChange(force) {
|
onChange() {
|
||||||
if (this.state.search && !force) {
|
let users;
|
||||||
return;
|
if (this.term) {
|
||||||
} else if (this.state.search) {
|
users = searchProfilesInCurrentChannel(store.getState(), this.term);
|
||||||
this.search(this.state.term);
|
} else {
|
||||||
return;
|
users = UserStore.getProfileListInChannel();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
users: UserStore.getProfileListInChannel(),
|
users,
|
||||||
teamMembers: Object.assign({}, TeamStore.getMembersInTeam()),
|
teamMembers: Object.assign({}, TeamStore.getMembersInTeam()),
|
||||||
channelMembers: Object.assign({}, ChannelStore.getMembersInChannel())
|
channelMembers: Object.assign({}, ChannelStore.getMembersInChannel())
|
||||||
});
|
});
|
||||||
@@ -87,43 +89,30 @@ export default class MemberListChannel extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nextPage(page) {
|
nextPage(page) {
|
||||||
loadProfilesAndTeamMembersAndChannelMembers((page + 1) * USERS_PER_PAGE, USERS_PER_PAGE);
|
loadProfilesAndTeamMembersAndChannelMembers(page + 1, USERS_PER_PAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
search(term) {
|
search(term) {
|
||||||
clearTimeout(this.searchTimeoutId);
|
clearTimeout(this.searchTimeoutId);
|
||||||
|
this.term = term;
|
||||||
|
|
||||||
if (term === '') {
|
if (term === '') {
|
||||||
this.setState({
|
this.setState({loading: false});
|
||||||
search: false,
|
|
||||||
term,
|
|
||||||
users: UserStore.getProfileListInChannel(),
|
|
||||||
teamMembers: Object.assign([], TeamStore.getMembersInTeam()),
|
|
||||||
channelMembers: Object.assign([], ChannelStore.getMembersInChannel())
|
|
||||||
});
|
|
||||||
this.searchTimeoutId = '';
|
this.searchTimeoutId = '';
|
||||||
|
this.onChange();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchTimeoutId = setTimeout(
|
const searchTimeoutId = setTimeout(
|
||||||
() => {
|
() => {
|
||||||
searchUsers(
|
searchUsers(term, TeamStore.getCurrentId(), {},
|
||||||
term,
|
|
||||||
TeamStore.getCurrentId(),
|
|
||||||
{},
|
|
||||||
(users) => {
|
(users) => {
|
||||||
if (searchTimeoutId !== this.searchTimeoutId) {
|
if (searchTimeoutId !== this.searchTimeoutId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({
|
this.setState({loading: true});
|
||||||
loading: true,
|
|
||||||
search: true,
|
|
||||||
users,
|
|
||||||
term,
|
|
||||||
teamMembers: Object.assign([], TeamStore.getMembersInTeam()),
|
|
||||||
channelMembers: Object.assign([], ChannelStore.getMembersInChannel())
|
|
||||||
});
|
|
||||||
loadTeamMembersAndChannelMembersForProfilesList(users, TeamStore.getCurrentId(), ChannelStore.getCurrentId(), this.loadComplete);
|
loadTeamMembersAndChannelMembersForProfilesList(users, TeamStore.getCurrentId(), ChannelStore.getCurrentId(), this.loadComplete);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
import SearchableUserList from 'components/searchable_user_list/searchable_user_list_container.jsx';
|
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 UserStore from 'stores/user_store.jsx';
|
||||||
import TeamStore from 'stores/team_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 React from 'react';
|
||||||
|
|
||||||
|
import store from 'stores/redux_store.jsx';
|
||||||
|
import {searchProfilesInCurrentTeam} from 'mattermost-redux/selectors/entities/users';
|
||||||
|
|
||||||
const USERS_PER_PAGE = 50;
|
const USERS_PER_PAGE = 50;
|
||||||
|
|
||||||
export default class MemberListTeam extends React.Component {
|
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.loadComplete = this.loadComplete.bind(this);
|
||||||
|
|
||||||
this.searchTimeoutId = 0;
|
this.searchTimeoutId = 0;
|
||||||
|
this.term = '';
|
||||||
|
|
||||||
const stats = TeamStore.getCurrentStats();
|
const stats = TeamStore.getCurrentStats();
|
||||||
|
|
||||||
@@ -36,8 +40,6 @@ export default class MemberListTeam extends React.Component {
|
|||||||
users: UserStore.getProfileListInTeam(),
|
users: UserStore.getProfileListInTeam(),
|
||||||
teamMembers: Object.assign([], TeamStore.getMembersInTeam()),
|
teamMembers: Object.assign([], TeamStore.getMembersInTeam()),
|
||||||
total: stats.total_member_count,
|
total: stats.total_member_count,
|
||||||
search: false,
|
|
||||||
term: '',
|
|
||||||
loading: true
|
loading: true
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -67,15 +69,15 @@ export default class MemberListTeam extends React.Component {
|
|||||||
this.onChange(true);
|
this.onChange(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
onChange(force) {
|
onChange() {
|
||||||
if (this.state.search && !force) {
|
let users;
|
||||||
return;
|
if (this.term) {
|
||||||
} else if (this.state.search) {
|
users = searchProfilesInCurrentTeam(store.getState(), this.term);
|
||||||
this.search(this.state.term);
|
} else {
|
||||||
return;
|
users = UserStore.getProfileListInTeam();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState({users: UserStore.getProfileListInTeam(), teamMembers: Object.assign([], TeamStore.getMembersInTeam())});
|
this.setState({users, teamMembers: Object.assign([], TeamStore.getMembersInTeam())});
|
||||||
}
|
}
|
||||||
|
|
||||||
onStatsChange() {
|
onStatsChange() {
|
||||||
@@ -84,15 +86,17 @@ export default class MemberListTeam extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
nextPage(page) {
|
nextPage(page) {
|
||||||
loadProfilesAndTeamMembers((page + 1) * USERS_PER_PAGE, USERS_PER_PAGE);
|
loadProfilesAndTeamMembers(page, USERS_PER_PAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
search(term) {
|
search(term) {
|
||||||
clearTimeout(this.searchTimeoutId);
|
clearTimeout(this.searchTimeoutId);
|
||||||
|
this.term = term;
|
||||||
|
|
||||||
if (term === '') {
|
if (term === '') {
|
||||||
this.setState({search: false, term, users: UserStore.getProfileListInTeam(), teamMembers: Object.assign([], TeamStore.getMembersInTeam())});
|
this.setState({loading: false});
|
||||||
this.searchTimeoutId = '';
|
this.searchTimeoutId = '';
|
||||||
|
this.onChange();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,7 +110,7 @@ export default class MemberListTeam extends React.Component {
|
|||||||
if (searchTimeoutId !== this.searchTimeoutId) {
|
if (searchTimeoutId !== this.searchTimeoutId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.setState({loading: true, search: true, users, term, teamMembers: Object.assign([], TeamStore.getMembersInTeam())});
|
this.setState({loading: true});
|
||||||
loadTeamMembersForProfilesList(users, TeamStore.getCurrentId(), this.loadComplete);
|
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 UserStore from 'stores/user_store.jsx';
|
||||||
import TeamStore from 'stores/team_store.jsx';
|
import TeamStore from 'stores/team_store.jsx';
|
||||||
|
|
||||||
import * as AsyncClient from 'utils/async_client.jsx';
|
|
||||||
import Constants from 'utils/constants.jsx';
|
import Constants from 'utils/constants.jsx';
|
||||||
import {displayUsernameForUser} from 'utils/utils.jsx';
|
import {displayUsernameForUser} from 'utils/utils.jsx';
|
||||||
import Client from 'client/web_client.jsx';
|
import Client from 'client/web_client.jsx';
|
||||||
@@ -20,10 +19,22 @@ import {Modal} from 'react-bootstrap';
|
|||||||
import {FormattedMessage} from 'react-intl';
|
import {FormattedMessage} from 'react-intl';
|
||||||
import {browserHistory} from 'react-router/es6';
|
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 USERS_PER_PAGE = 50;
|
||||||
const MAX_SELECTABLE_VALUES = Constants.MAX_USERS_IN_GM - 1;
|
const MAX_SELECTABLE_VALUES = Constants.MAX_USERS_IN_GM - 1;
|
||||||
|
|
||||||
export default class MoreDirectChannels extends React.Component {
|
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) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
@@ -36,6 +47,7 @@ export default class MoreDirectChannels extends React.Component {
|
|||||||
this.addValue = this.addValue.bind(this);
|
this.addValue = this.addValue.bind(this);
|
||||||
|
|
||||||
this.searchTimeoutId = 0;
|
this.searchTimeoutId = 0;
|
||||||
|
this.term = '';
|
||||||
this.listType = global.window.mm_config.RestrictDirectMessage;
|
this.listType = global.window.mm_config.RestrictDirectMessage;
|
||||||
|
|
||||||
const values = [];
|
const values = [];
|
||||||
@@ -63,9 +75,9 @@ export default class MoreDirectChannels extends React.Component {
|
|||||||
UserStore.addStatusesChangeListener(this.onChange);
|
UserStore.addStatusesChangeListener(this.onChange);
|
||||||
|
|
||||||
if (this.listType === 'any') {
|
if (this.listType === 'any') {
|
||||||
AsyncClient.getProfiles(0, USERS_PER_PAGE * 2);
|
this.props.actions.getProfiles(0, USERS_PER_PAGE * 2);
|
||||||
} else {
|
} 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});
|
this.setState({values});
|
||||||
}
|
}
|
||||||
|
|
||||||
onChange(force) {
|
onChange() {
|
||||||
if (this.state.search && !force) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let users;
|
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));
|
users = Object.assign([], UserStore.getProfileList(true));
|
||||||
} else {
|
} else {
|
||||||
users = Object.assign([], UserStore.getProfileListInTeam(TeamStore.getCurrentId(), true));
|
users = Object.assign([], UserStore.getProfileListInTeam(TeamStore.getCurrentId(), true));
|
||||||
@@ -160,17 +174,20 @@ export default class MoreDirectChannels extends React.Component {
|
|||||||
|
|
||||||
handlePageChange(page, prevPage) {
|
handlePageChange(page, prevPage) {
|
||||||
if (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) {
|
search(term) {
|
||||||
clearTimeout(this.searchTimeoutId);
|
clearTimeout(this.searchTimeoutId);
|
||||||
|
this.term = term;
|
||||||
|
|
||||||
if (term === '') {
|
if (term === '') {
|
||||||
this.onChange(true);
|
this.onChange();
|
||||||
this.setState({search: false});
|
|
||||||
this.searchTimeoutId = '';
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,37 +198,12 @@ export default class MoreDirectChannels extends React.Component {
|
|||||||
teamId = TeamStore.getCurrentId();
|
teamId = TeamStore.getCurrentId();
|
||||||
}
|
}
|
||||||
|
|
||||||
const searchTimeoutId = setTimeout(
|
this.searchTimeoutId = setTimeout(
|
||||||
() => {
|
() => {
|
||||||
searchUsers(
|
searchUsers(term, teamId);
|
||||||
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});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
Constants.SEARCH_TIMEOUT_MILLISECONDS
|
Constants.SEARCH_TIMEOUT_MILLISECONDS
|
||||||
);
|
);
|
||||||
|
|
||||||
this.searchTimeoutId = searchTimeoutId;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDelete(values) {
|
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 MessageWrapper from './message_wrapper.jsx';
|
||||||
import NotifyCounts from './notify_counts.jsx';
|
import NotifyCounts from './notify_counts.jsx';
|
||||||
import ChannelInfoModal from './channel_info_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 ChannelMembersModal from './channel_members_modal.jsx';
|
||||||
import ChannelNotificationsModal from './channel_notifications_modal.jsx';
|
import ChannelNotificationsModal from './channel_notifications_modal.jsx';
|
||||||
import DeleteChannelModal from './delete_channel_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 UserStore from 'stores/user_store.jsx';
|
||||||
import ChannelStore from 'stores/channel_store.jsx';
|
import ChannelStore from 'stores/channel_store.jsx';
|
||||||
|
|
||||||
import TeamMembersModal from './team_members_modal.jsx';
|
import TeamMembersModal from 'components/team_members_modal.jsx';
|
||||||
import ChannelMembersModal from './channel_members_modal.jsx';
|
import ChannelMembersModal from 'components/channel_members_modal.jsx';
|
||||||
import ChannelInviteModal from './channel_invite_modal.jsx';
|
import ChannelInviteModal from 'components/channel_invite_modal';
|
||||||
|
|
||||||
import {openDirectChannelToUser} from 'actions/channel_actions.jsx';
|
import {openDirectChannelToUser} from 'actions/channel_actions.jsx';
|
||||||
|
|
||||||
import * as AsyncClient from 'utils/async_client.jsx';
|
|
||||||
import Client from 'client/web_client.jsx';
|
import Client from 'client/web_client.jsx';
|
||||||
import * as Utils from 'utils/utils.jsx';
|
import * as Utils from 'utils/utils.jsx';
|
||||||
import Constants from 'utils/constants.jsx';
|
import Constants from 'utils/constants.jsx';
|
||||||
@@ -26,6 +25,15 @@ import {FormattedMessage} from 'react-intl';
|
|||||||
import {browserHistory} from 'react-router/es6';
|
import {browserHistory} from 'react-router/es6';
|
||||||
|
|
||||||
export default class PopoverListMembers extends React.Component {
|
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) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
@@ -239,7 +247,7 @@ export default class PopoverListMembers extends React.Component {
|
|||||||
ref='member_popover_target'
|
ref='member_popover_target'
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
this.setState({popoverTarget: e.target, showPopover: !this.state.showPopover});
|
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}
|
{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 = {
|
Root.defaultProps = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import NewChannelFlow from './new_channel_flow.jsx';
|
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 MoreChannels from 'components/more_channels.jsx';
|
||||||
import SidebarHeader from './sidebar_header.jsx';
|
import SidebarHeader from './sidebar_header.jsx';
|
||||||
import UnreadChannelIndicator from './unread_channel_indicator.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 SidebarHeaderDropdownButton from './sidebar_header_dropdown_button.jsx';
|
||||||
import TeamMembersModal from './team_members_modal.jsx';
|
import TeamMembersModal from './team_members_modal.jsx';
|
||||||
import UserSettingsModal from './user_settings/user_settings_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';
|
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 ToggleModalButton from './toggle_modal_button.jsx';
|
||||||
import UserSettingsModal from './user_settings/user_settings_modal.jsx';
|
import UserSettingsModal from './user_settings/user_settings_modal.jsx';
|
||||||
import AboutBuildModal from './about_build_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 UserStore from 'stores/user_store.jsx';
|
||||||
import TeamStore from 'stores/team_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 BrowserStore from 'stores/browser_store.jsx';
|
||||||
import {getInviteInfo} from 'actions/team_actions.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 * as Utils from 'utils/utils.jsx';
|
||||||
import Constants from 'utils/constants.jsx';
|
import Constants from 'utils/constants.jsx';
|
||||||
@@ -108,7 +108,7 @@ export default class SignupEmail extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
finishSignup() {
|
finishSignup() {
|
||||||
GlobalActions.emitInitialLoad(
|
loadMe(
|
||||||
() => {
|
() => {
|
||||||
const query = this.props.location.query;
|
const query = this.props.location.query;
|
||||||
GlobalActions.loadDefaultLocale();
|
GlobalActions.loadDefaultLocale();
|
||||||
@@ -132,7 +132,7 @@ export default class SignupEmail extends React.Component {
|
|||||||
BrowserStore.setGlobalItem(this.state.hash, JSON.stringify({usedBefore: true}));
|
BrowserStore.setGlobalItem(this.state.hash, JSON.stringify({usedBefore: true}));
|
||||||
}
|
}
|
||||||
|
|
||||||
GlobalActions.emitInitialLoad(
|
loadMe(
|
||||||
() => {
|
() => {
|
||||||
const query = this.props.location.query;
|
const query = this.props.location.query;
|
||||||
if (query.redirect_to) {
|
if (query.redirect_to) {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import FormError from 'components/form_error.jsx';
|
|||||||
|
|
||||||
import * as GlobalActions from 'actions/global_actions.jsx';
|
import * as GlobalActions from 'actions/global_actions.jsx';
|
||||||
import {addUserToTeamFromInvite} from 'actions/team_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 {trackEvent} from 'actions/diagnostics_actions.jsx';
|
||||||
|
|
||||||
import * as Utils from 'utils/utils.jsx';
|
import * as Utils from 'utils/utils.jsx';
|
||||||
@@ -97,7 +97,7 @@ export default class SignupLdap extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
finishSignup() {
|
finishSignup() {
|
||||||
GlobalActions.emitInitialLoad(
|
loadMe(
|
||||||
() => {
|
() => {
|
||||||
const query = this.props.location.query;
|
const query = this.props.location.query;
|
||||||
GlobalActions.loadDefaultLocale();
|
GlobalActions.loadDefaultLocale();
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import * as AsyncClient from 'utils/async_client.jsx';
|
|||||||
import Client from 'client/web_client.jsx';
|
import Client from 'client/web_client.jsx';
|
||||||
import * as GlobalActions from 'actions/global_actions.jsx';
|
import * as GlobalActions from 'actions/global_actions.jsx';
|
||||||
import {addUserToTeamFromInvite, getInviteInfo} from 'actions/team_actions.jsx';
|
import {addUserToTeamFromInvite, getInviteInfo} from 'actions/team_actions.jsx';
|
||||||
|
import {loadMe} from 'actions/user_actions.jsx';
|
||||||
|
|
||||||
import logoImage from 'images/logo.png';
|
import logoImage from 'images/logo.png';
|
||||||
import ErrorBar from 'components/error_bar.jsx';
|
import ErrorBar from 'components/error_bar.jsx';
|
||||||
@@ -74,7 +75,7 @@ export default class SignupController extends React.Component {
|
|||||||
hash,
|
hash,
|
||||||
inviteId,
|
inviteId,
|
||||||
(team) => {
|
(team) => {
|
||||||
GlobalActions.emitInitialLoad(
|
loadMe(
|
||||||
() => {
|
() => {
|
||||||
browserHistory.push('/' + team.name + '/channels/town-square');
|
browserHistory.push('/' + team.name + '/channels/town-square');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -127,14 +127,14 @@ export default class AtMentionProvider extends Provider {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const members = data.in_channel;
|
const members = Object.assign([], data.users);
|
||||||
for (const id of Object.keys(members)) {
|
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)) {
|
for (const id of Object.keys(nonmembers)) {
|
||||||
nonmembers[id].type = Constants.MENTION_NONMEMBERS;
|
nonmembers[id] = {...nonmembers[id], type: Constants.MENTION_NONMEMBERS};
|
||||||
}
|
}
|
||||||
|
|
||||||
let specialMentions = [];
|
let specialMentions = [];
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ export default class SearchUserProvider extends Provider {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const users = data.in_team;
|
const users = Object.assign([], data.users);
|
||||||
const mentions = users.map((user) => user.username);
|
const mentions = users.map((user) => user.username);
|
||||||
|
|
||||||
AppDispatcher.handleServerAction({
|
AppDispatcher.handleServerAction({
|
||||||
|
|||||||
@@ -67,7 +67,9 @@ export default class SwitchChannelProvider extends Provider {
|
|||||||
|
|
||||||
autocompleteUsers(
|
autocompleteUsers(
|
||||||
channelPrefix,
|
channelPrefix,
|
||||||
(users) => {
|
(data) => {
|
||||||
|
const users = Object.assign([], data.users);
|
||||||
|
|
||||||
if (this.shouldCancelDispatch(channelPrefix)) {
|
if (this.shouldCancelDispatch(channelPrefix)) {
|
||||||
return;
|
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.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See License.txt for license information.
|
// 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 TeamStore from 'stores/team_store.jsx';
|
||||||
import UserStore from 'stores/user_store.jsx';
|
import UserStore from 'stores/user_store.jsx';
|
||||||
@@ -18,6 +18,14 @@ import {FormattedMessage} from 'react-intl';
|
|||||||
import {browserHistory} from 'react-router/es6';
|
import {browserHistory} from 'react-router/es6';
|
||||||
|
|
||||||
export default class TeamMembersDropdown extends React.Component {
|
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) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
@@ -48,7 +56,7 @@ export default class TeamMembersDropdown extends React.Component {
|
|||||||
this.props.user.id,
|
this.props.user.id,
|
||||||
'team_user',
|
'team_user',
|
||||||
() => {
|
() => {
|
||||||
AsyncClient.getUser(this.props.user.id);
|
this.props.actions.getUser(this.props.user.id);
|
||||||
|
|
||||||
if (this.props.user.id === me.id) {
|
if (this.props.user.id === me.id) {
|
||||||
loadMyTeamMembers();
|
loadMyTeamMembers();
|
||||||
@@ -110,7 +118,7 @@ export default class TeamMembersDropdown extends React.Component {
|
|||||||
this.props.user.id,
|
this.props.user.id,
|
||||||
'team_user team_admin',
|
'team_user team_admin',
|
||||||
() => {
|
() => {
|
||||||
AsyncClient.getUser(this.props.user.id);
|
this.props.actions.getUser(this.props.user.id);
|
||||||
},
|
},
|
||||||
(err) => {
|
(err) => {
|
||||||
this.setState({serverError: err.message});
|
this.setState({serverError: err.message});
|
||||||
@@ -145,7 +153,7 @@ export default class TeamMembersDropdown extends React.Component {
|
|||||||
this.props.user.id,
|
this.props.user.id,
|
||||||
this.state.newRole,
|
this.state.newRole,
|
||||||
() => {
|
() => {
|
||||||
AsyncClient.getUser(this.props.user.id);
|
this.props.actions.getUser(this.props.user.id);
|
||||||
|
|
||||||
const teamUrl = TeamStore.getCurrentTeamUrl();
|
const teamUrl = TeamStore.getCurrentTeamUrl();
|
||||||
if (teamUrl) {
|
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 UserStore from 'stores/user_store.jsx';
|
||||||
import * as utils from 'utils/utils.jsx';
|
import * as utils from 'utils/utils.jsx';
|
||||||
import NotificationsTab from './user_settings_notifications.jsx';
|
import NotificationsTab from './user_settings_notifications.jsx';
|
||||||
import SecurityTab from './user_settings_security.jsx';
|
import SecurityTab from './user_settings_security';
|
||||||
import GeneralTab from './user_settings_general.jsx';
|
import GeneralTab from './user_settings_general';
|
||||||
import DisplayTab from './user_settings_display.jsx';
|
import DisplayTab from './user_settings_display.jsx';
|
||||||
import AdvancedTab from './user_settings_advanced.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.
|
// See License.txt for license information.
|
||||||
|
|
||||||
import $ from 'jquery';
|
import $ from 'jquery';
|
||||||
import SettingItemMin from '../setting_item_min.jsx';
|
import SettingItemMin from 'components/setting_item_min.jsx';
|
||||||
import SettingItemMax from '../setting_item_max.jsx';
|
import SettingItemMax from 'components/setting_item_max.jsx';
|
||||||
import SettingPicture from '../setting_picture.jsx';
|
import SettingPicture from 'components/setting_picture.jsx';
|
||||||
|
|
||||||
import UserStore from 'stores/user_store.jsx';
|
import UserStore from 'stores/user_store.jsx';
|
||||||
import ErrorStore from 'stores/error_store.jsx';
|
import ErrorStore from 'stores/error_store.jsx';
|
||||||
|
|
||||||
import Client from 'client/web_client.jsx';
|
import Client from 'client/web_client.jsx';
|
||||||
import Constants from 'utils/constants.jsx';
|
import Constants from 'utils/constants.jsx';
|
||||||
import * as AsyncClient from 'utils/async_client.jsx';
|
|
||||||
import * as Utils from 'utils/utils.jsx';
|
import * as Utils from 'utils/utils.jsx';
|
||||||
|
|
||||||
import {intlShape, injectIntl, defineMessages, FormattedMessage, FormattedHTMLMessage, FormattedDate} from 'react-intl';
|
import {intlShape, injectIntl, defineMessages, FormattedMessage, FormattedHTMLMessage, FormattedDate} from 'react-intl';
|
||||||
@@ -80,6 +79,19 @@ const holders = defineMessages({
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
class UserSettingsGeneralTab extends React.Component {
|
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) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.submitActive = false;
|
this.submitActive = false;
|
||||||
@@ -205,7 +217,7 @@ class UserSettingsGeneralTab extends React.Component {
|
|||||||
updateUser(user, type,
|
updateUser(user, type,
|
||||||
() => {
|
() => {
|
||||||
this.updateSection('');
|
this.updateSection('');
|
||||||
AsyncClient.getMe();
|
this.props.actions.getMe();
|
||||||
const verificationEnabled = global.window.mm_config.SendEmailNotifications === 'true' && global.window.mm_config.RequireEmailVerification === 'true' && emailUpdated;
|
const verificationEnabled = global.window.mm_config.SendEmailNotifications === 'true' && global.window.mm_config.RequireEmailVerification === 'true' && emailUpdated;
|
||||||
|
|
||||||
if (verificationEnabled) {
|
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);
|
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.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
import SettingItemMin from '../setting_item_min.jsx';
|
import SettingItemMin from 'components/setting_item_min.jsx';
|
||||||
import SettingItemMax from '../setting_item_max.jsx';
|
import SettingItemMax from 'components/setting_item_max.jsx';
|
||||||
import AccessHistoryModal from '../access_history_modal.jsx';
|
import AccessHistoryModal from 'components/access_history_modal';
|
||||||
import ActivityLogModal from '../activity_log_modal.jsx';
|
import ActivityLogModal from 'components/activity_log_modal';
|
||||||
import ToggleModalButton from '../toggle_modal_button.jsx';
|
import ToggleModalButton from 'components/toggle_modal_button.jsx';
|
||||||
|
|
||||||
import PreferenceStore from 'stores/preference_store.jsx';
|
import PreferenceStore from 'stores/preference_store.jsx';
|
||||||
|
|
||||||
import * as AsyncClient from 'utils/async_client.jsx';
|
|
||||||
import * as Utils from 'utils/utils.jsx';
|
import * as Utils from 'utils/utils.jsx';
|
||||||
import Constants from 'utils/constants.jsx';
|
import Constants from 'utils/constants.jsx';
|
||||||
|
|
||||||
@@ -23,6 +22,19 @@ import {browserHistory, Link} from 'react-router/es6';
|
|||||||
import icon50 from 'images/icon50x50.png';
|
import icon50 from 'images/icon50x50.png';
|
||||||
|
|
||||||
export default class SecurityTab extends React.Component {
|
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) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
@@ -98,7 +110,7 @@ export default class SecurityTab extends React.Component {
|
|||||||
newPassword,
|
newPassword,
|
||||||
() => {
|
() => {
|
||||||
this.props.updateSection('');
|
this.props.updateSection('');
|
||||||
AsyncClient.getMe();
|
this.props.actions.getMe();
|
||||||
this.setState(this.getDefaultState());
|
this.setState(this.getDefaultState());
|
||||||
},
|
},
|
||||||
(err) => {
|
(err) => {
|
||||||
@@ -1022,12 +1034,3 @@ SecurityTab.defaultProps = {
|
|||||||
user: {},
|
user: {},
|
||||||
activeSection: ''
|
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",
|
"intl": "1.2.5",
|
||||||
"jasny-bootstrap": "3.1.3",
|
"jasny-bootstrap": "3.1.3",
|
||||||
"jquery": "3.1.1",
|
"jquery": "3.1.1",
|
||||||
|
"localforage": "1.5.0",
|
||||||
"marked": "mattermost/marked#8f5902fff9bad793cd6c66e0c44002c9e79e1317",
|
"marked": "mattermost/marked#8f5902fff9bad793cd6c66e0c44002c9e79e1317",
|
||||||
"match-at": "0.1.0",
|
"match-at": "0.1.0",
|
||||||
|
"mattermost-redux": "mattermost/mattermost-redux#webapp-part2",
|
||||||
"object-assign": "4.1.1",
|
"object-assign": "4.1.1",
|
||||||
"pdfjs-dist": "1.7.363",
|
"pdfjs-dist": "1.7.363",
|
||||||
"perfect-scrollbar": "0.6.16",
|
"perfect-scrollbar": "0.6.16",
|
||||||
@@ -30,19 +32,26 @@
|
|||||||
"react-custom-scrollbars": "4.0.2",
|
"react-custom-scrollbars": "4.0.2",
|
||||||
"react-dom": "15.4.2",
|
"react-dom": "15.4.2",
|
||||||
"react-intl": "2.2.3",
|
"react-intl": "2.2.3",
|
||||||
|
"react-redux": "5.0.4",
|
||||||
"react-router": "2.8.1",
|
"react-router": "2.8.1",
|
||||||
"react-select": "1.0.0-rc.3",
|
"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",
|
"superagent": "3.5.0",
|
||||||
"twemoji": "2.2.5",
|
"twemoji": "2.2.5",
|
||||||
"velocity-animate": "1.4.3",
|
"velocity-animate": "1.4.3",
|
||||||
"webrtc-adapter": "3.2.0",
|
"webrtc-adapter": "3.2.0",
|
||||||
|
"whatwg-fetch": "2.0.3",
|
||||||
"xregexp": "3.1.1"
|
"xregexp": "3.1.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"babel-cli": "6.24.1",
|
||||||
"babel-core": "6.24.0",
|
"babel-core": "6.24.0",
|
||||||
"babel-eslint": "7.1.1",
|
"babel-eslint": "7.1.1",
|
||||||
"babel-jest": "19.0.0",
|
"babel-jest": "19.0.0",
|
||||||
"babel-loader": "6.4.0",
|
"babel-loader": "6.4.0",
|
||||||
|
"babel-plugin-module-resolver": "2.7.0",
|
||||||
"babel-plugin-transform-runtime": "6.23.0",
|
"babel-plugin-transform-runtime": "6.23.0",
|
||||||
"babel-polyfill": "6.23.0",
|
"babel-polyfill": "6.23.0",
|
||||||
"babel-preset-es2015": "6.24.0",
|
"babel-preset-es2015": "6.24.0",
|
||||||
@@ -73,9 +82,11 @@
|
|||||||
"raw-loader": "0.5.1",
|
"raw-loader": "0.5.1",
|
||||||
"react-addons-test-utils": "15.4.2",
|
"react-addons-test-utils": "15.4.2",
|
||||||
"react-dom": "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",
|
"sass-loader": "6.0.3",
|
||||||
"style-loader": "0.13.2",
|
"style-loader": "0.13.2",
|
||||||
"react-outside-event": "1.2.4",
|
|
||||||
"url-loader": "0.5.8",
|
"url-loader": "0.5.8",
|
||||||
"webpack": "2.2.1",
|
"webpack": "2.2.1",
|
||||||
"webpack-node-externals": "1.5.4"
|
"webpack-node-externals": "1.5.4"
|
||||||
|
|||||||
@@ -6,22 +6,28 @@ require('perfect-scrollbar/jquery')($);
|
|||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
|
import {Provider} from 'react-redux';
|
||||||
import {Router, browserHistory} from 'react-router/es6';
|
import {Router, browserHistory} from 'react-router/es6';
|
||||||
import PDFJS from 'pdfjs-dist';
|
import PDFJS from 'pdfjs-dist';
|
||||||
import * as GlobalActions from 'actions/global_actions.jsx';
|
|
||||||
import * as Websockets from 'actions/websocket_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 BrowserStore from 'stores/browser_store.jsx';
|
||||||
import ChannelStore from 'stores/channel_store.jsx';
|
import ChannelStore from 'stores/channel_store.jsx';
|
||||||
import UserStore from 'stores/user_store.jsx';
|
import UserStore from 'stores/user_store.jsx';
|
||||||
import * as I18n from 'i18n/i18n.jsx';
|
import * as I18n from 'i18n/i18n.jsx';
|
||||||
import * as AsyncClient from 'utils/async_client.jsx';
|
import * as AsyncClient from 'utils/async_client.jsx';
|
||||||
|
|
||||||
|
import {getClientConfig, getLicenseConfig, setUrl} from 'mattermost-redux/actions/general';
|
||||||
|
|
||||||
// Import our styles
|
// Import our styles
|
||||||
import 'bootstrap-colorpicker/dist/css/bootstrap-colorpicker.css';
|
import 'bootstrap-colorpicker/dist/css/bootstrap-colorpicker.css';
|
||||||
import 'google-fonts/google-fonts.css';
|
import 'google-fonts/google-fonts.css';
|
||||||
import 'sass/styles.scss';
|
import 'sass/styles.scss';
|
||||||
import 'katex/dist/katex.min.css';
|
import 'katex/dist/katex.min.css';
|
||||||
|
|
||||||
|
import store from 'stores/redux_store.jsx';
|
||||||
|
|
||||||
// Import the root of our routing tree
|
// Import the root of our routing tree
|
||||||
import rRoot from 'routes/route_root.jsx';
|
import rRoot from 'routes/route_root.jsx';
|
||||||
|
|
||||||
@@ -51,11 +57,26 @@ function preRenderSetup(callwhendone) {
|
|||||||
|
|
||||||
var d1 = $.Deferred(); //eslint-disable-line new-cap
|
var d1 = $.Deferred(); //eslint-disable-line new-cap
|
||||||
|
|
||||||
GlobalActions.emitInitialLoad(
|
setUrl(window.location.origin);
|
||||||
() => {
|
|
||||||
d1.resolve();
|
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
|
// Make sure the websockets close and reset version
|
||||||
$(window).on('beforeunload',
|
$(window).on('beforeunload',
|
||||||
@@ -86,10 +107,12 @@ function preRenderSetup(callwhendone) {
|
|||||||
|
|
||||||
function renderRootComponent() {
|
function renderRootComponent() {
|
||||||
ReactDOM.render((
|
ReactDOM.render((
|
||||||
<Router
|
<Provider store={store}>
|
||||||
history={browserHistory}
|
<Router
|
||||||
routes={rRoot}
|
history={browserHistory}
|
||||||
/>
|
routes={rRoot}
|
||||||
|
/>
|
||||||
|
</Provider>
|
||||||
),
|
),
|
||||||
document.getElementById('root'));
|
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';
|
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 {
|
class PreferenceStore extends EventEmitter {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
@@ -16,6 +20,23 @@ class PreferenceStore extends EventEmitter {
|
|||||||
this.dispatchToken = AppDispatcher.register(this.handleEventPayload);
|
this.dispatchToken = AppDispatcher.register(this.handleEventPayload);
|
||||||
|
|
||||||
this.preferences = new Map();
|
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);
|
this.setMaxListeners(600);
|
||||||
}
|
}
|
||||||
@@ -79,21 +100,24 @@ class PreferenceStore extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setPreference(category, name, value) {
|
setPreference(category, name, value) {
|
||||||
this.preferences.set(this.getKey(category, name), value);
|
store.dispatch({
|
||||||
|
type: PreferenceTypes.RECEIVED_PREFERENCES,
|
||||||
|
data: [{category, name, value}]
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
setPreferencesFromServer(newPreferences) {
|
setPreferencesFromServer(newPreferences) {
|
||||||
for (const preference of newPreferences) {
|
store.dispatch({
|
||||||
this.setPreference(preference.category, preference.name, preference.value);
|
type: PreferenceTypes.RECEIVED_PREFERENCES,
|
||||||
}
|
data: newPreferences
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
deletePreference(preference) {
|
deletePreference(preference) {
|
||||||
this.preferences.delete(this.getKey(preference.category, preference.name));
|
store.dispatch({
|
||||||
}
|
type: PreferenceTypes.DELETED_PREFERENCES,
|
||||||
|
data: [preference]
|
||||||
clear() {
|
});
|
||||||
this.preferences.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
emitChange(category) {
|
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 STATS_EVENT = 'stats';
|
||||||
const UNREAD_EVENT = 'unread';
|
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;
|
var Utils;
|
||||||
|
|
||||||
class TeamStoreClass extends EventEmitter {
|
class TeamStoreClass extends EventEmitter {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
this.clear();
|
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() {
|
clear() {
|
||||||
this.teams = {};
|
this.entities = {};
|
||||||
this.my_team_members = [];
|
|
||||||
this.members_in_team = {};
|
this.members_in_team = {};
|
||||||
this.members_not_in_team = {};
|
this.members_not_in_team = {};
|
||||||
this.stats = {};
|
this.stats = {};
|
||||||
@@ -91,7 +107,7 @@ class TeamStoreClass extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getAll() {
|
getAll() {
|
||||||
return this.teams;
|
return store.getState().entities.teams.teams;
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentId() {
|
getCurrentId() {
|
||||||
@@ -100,10 +116,14 @@ class TeamStoreClass extends EventEmitter {
|
|||||||
|
|
||||||
setCurrentId(id) {
|
setCurrentId(id) {
|
||||||
this.currentTeamId = id;
|
this.currentTeamId = id;
|
||||||
|
store.dispatch({
|
||||||
|
type: TeamTypes.SELECT_TEAM,
|
||||||
|
data: id
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrent() {
|
getCurrent() {
|
||||||
const team = this.teams[this.currentTeamId];
|
const team = this.getAll()[this.currentTeamId];
|
||||||
|
|
||||||
if (team) {
|
if (team) {
|
||||||
return team;
|
return team;
|
||||||
@@ -165,17 +185,21 @@ class TeamStoreClass extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
saveTeam(team) {
|
saveTeam(team) {
|
||||||
this.teams[team.id] = team;
|
this.saveTeams([team]);
|
||||||
}
|
}
|
||||||
|
|
||||||
saveTeams(teams) {
|
saveTeams(teams) {
|
||||||
this.teams = teams;
|
store.dispatch({
|
||||||
|
type: TeamTypes.RECEIVED_TEAMS_LIST,
|
||||||
|
data: teams
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
updateTeam(team) {
|
updateTeam(team) {
|
||||||
const t = JSON.parse(team);
|
const t = JSON.parse(team);
|
||||||
if (this.teams && this.teams[t.id]) {
|
const teams = this.getAll();
|
||||||
this.teams[t.id] = t;
|
if (teams && teams[t.id]) {
|
||||||
|
this.saveTeam(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.teamListings && this.teamListings[t.id]) {
|
if (this.teamListings && this.teamListings[t.id]) {
|
||||||
@@ -193,7 +217,7 @@ class TeamStoreClass extends EventEmitter {
|
|||||||
|
|
||||||
saveMyTeam(team) {
|
saveMyTeam(team) {
|
||||||
this.saveTeam(team);
|
this.saveTeam(team);
|
||||||
this.currentTeamId = team.id;
|
this.setCurrentId(team.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
saveStats(teamId, stats) {
|
saveStats(teamId, stats) {
|
||||||
@@ -201,20 +225,26 @@ class TeamStoreClass extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
saveMyTeamMembers(members) {
|
saveMyTeamMembers(members) {
|
||||||
this.my_team_members = members;
|
store.dispatch({
|
||||||
|
type: TeamTypes.RECEIVED_MY_TEAM_MEMBERS,
|
||||||
|
data: members
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
appendMyTeamMember(member) {
|
appendMyTeamMember(member) {
|
||||||
this.my_team_members.push(member);
|
const members = this.getMyTeamMembers();
|
||||||
|
members.push(member);
|
||||||
|
this.saveMyTeamMembers(members);
|
||||||
}
|
}
|
||||||
|
|
||||||
saveMyTeamMembersUnread(members) {
|
saveMyTeamMembersUnread(members) {
|
||||||
for (let i = 0; i < this.my_team_members.length; i++) {
|
const myMembers = this.getMyTeamMembers();
|
||||||
const team = this.my_team_members[i];
|
for (let i = 0; i < myMembers.length; i++) {
|
||||||
|
const team = myMembers[i];
|
||||||
const member = members.filter((m) => m.team_id === team.team_id)[0];
|
const member = members.filter((m) => m.team_id === team.team_id)[0];
|
||||||
|
|
||||||
if (member) {
|
if (member) {
|
||||||
this.my_team_members[i] = Object.assign({},
|
myMembers[i] = Object.assign({},
|
||||||
team,
|
team,
|
||||||
{
|
{
|
||||||
msg_count: member.msg_count,
|
msg_count: member.msg_count,
|
||||||
@@ -222,19 +252,23 @@ class TeamStoreClass extends EventEmitter {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.saveMyTeamMembers(myMembers);
|
||||||
}
|
}
|
||||||
|
|
||||||
removeMyTeamMember(teamId) {
|
removeMyTeamMember(teamId) {
|
||||||
for (let i = 0; i < this.my_team_members.length; i++) {
|
const myMembers = this.getMyTeamMembers();
|
||||||
if (this.my_team_members[i].team_id === teamId) {
|
for (let i = 0; i < myMembers.length; i++) {
|
||||||
this.my_team_members.splice(i, 1);
|
if (myMembers[i].team_id === teamId) {
|
||||||
|
myMembers.splice(i, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.emitChange();
|
|
||||||
|
this.saveMyTeamMembers(myMembers);
|
||||||
}
|
}
|
||||||
|
|
||||||
getMyTeamMembers() {
|
getMyTeamMembers() {
|
||||||
return this.my_team_members;
|
return Object.values(Selectors.getTeamMemberships(store.getState()));
|
||||||
}
|
}
|
||||||
|
|
||||||
saveMembersInTeam(teamId = this.getCurrentId(), members) {
|
saveMembersInTeam(teamId = this.getCurrentId(), members) {
|
||||||
@@ -320,19 +354,21 @@ class TeamStoreClass extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
updateUnreadCount(teamId, totalMsgCount, channelMember) {
|
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) {
|
if (member) {
|
||||||
|
member = Object.assign({}, member);
|
||||||
member.msg_count -= (totalMsgCount - channelMember.msg_count);
|
member.msg_count -= (totalMsgCount - channelMember.msg_count);
|
||||||
member.mention_count -= channelMember.mention_count;
|
member.mention_count -= channelMember.mention_count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
subtractUnread(teamId, msgs, mentions) {
|
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) {
|
if (member) {
|
||||||
const msgCount = member.msg_count - msgs;
|
const msgCount = member.msg_count - msgs;
|
||||||
const mentionCount = member.mention_count - mentions;
|
const mentionCount = member.mention_count - mentions;
|
||||||
|
|
||||||
|
member = Object.assign({}, member);
|
||||||
member.msg_count = (msgCount > 0) ? msgCount : 0;
|
member.msg_count = (msgCount > 0) ? msgCount : 0;
|
||||||
member.mention_count = (mentionCount > 0) ? mentionCount : 0;
|
member.mention_count = (mentionCount > 0) ? mentionCount : 0;
|
||||||
}
|
}
|
||||||
@@ -344,7 +380,7 @@ class TeamStoreClass extends EventEmitter {
|
|||||||
return;
|
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++;
|
member.msg_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -355,7 +391,7 @@ class TeamStoreClass extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (mentions.indexOf(UserStore.getCurrentId()) !== -1) {
|
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++;
|
member.mention_count++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,16 +1,12 @@
|
|||||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
import AppDispatcher from '../dispatcher/app_dispatcher.jsx';
|
|
||||||
import EventEmitter from 'events';
|
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 ChannelStore from 'stores/channel_store.jsx';
|
||||||
import TeamStore from 'stores/team_store.jsx';
|
import TeamStore from 'stores/team_store.jsx';
|
||||||
|
|
||||||
import Constants from 'utils/constants.jsx';
|
import Constants from 'utils/constants.jsx';
|
||||||
const ActionTypes = Constants.ActionTypes;
|
|
||||||
const UserStatuses = Constants.UserStatuses;
|
const UserStatuses = Constants.UserStatuses;
|
||||||
|
|
||||||
const CHANGE_EVENT_NOT_IN_CHANNEL = 'change_not_in_channel';
|
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_AUDITS = 'change_audits';
|
||||||
const CHANGE_EVENT_STATUSES = 'change_statuses';
|
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;
|
var Utils;
|
||||||
|
|
||||||
class UserStoreClass extends EventEmitter {
|
class UserStoreClass extends EventEmitter {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
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.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) {
|
emitChange(userId) {
|
||||||
@@ -178,49 +178,21 @@ class UserStoreClass extends EventEmitter {
|
|||||||
// General
|
// General
|
||||||
|
|
||||||
getCurrentUser() {
|
getCurrentUser() {
|
||||||
return this.getProfiles()[this.currentUserId];
|
return Selectors.getCurrentUser(store.getState());
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentId() {
|
getCurrentId() {
|
||||||
var user = this.getCurrentUser();
|
return Selectors.getCurrentUserId(store.getState());
|
||||||
|
|
||||||
if (user) {
|
|
||||||
return user.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// System-Wide Profiles
|
// 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() {
|
getProfiles() {
|
||||||
return this.profiles;
|
return Selectors.getUsers(store.getState());
|
||||||
}
|
}
|
||||||
|
|
||||||
getProfile(userId) {
|
getProfile(userId) {
|
||||||
if (this.profiles[userId]) {
|
return Selectors.getUser(store.getState(), userId);
|
||||||
return Object.assign({}, this.profiles[userId]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getProfileListForIds(userIds, skipCurrent = false, skipInactive = false) {
|
getProfileListForIds(userIds, skipCurrent = false, skipInactive = false) {
|
||||||
@@ -257,17 +229,7 @@ class UserStoreClass extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getProfilesUsernameMap() {
|
getProfilesUsernameMap() {
|
||||||
var profileUsernameMap = {};
|
return Selectors.getUsersByUsername(store.getState());
|
||||||
|
|
||||||
var profiles = this.getProfiles();
|
|
||||||
for (var key in profiles) {
|
|
||||||
if (profiles.hasOwnProperty(key)) {
|
|
||||||
var profile = profiles[key];
|
|
||||||
profileUsernameMap[profile.username] = profile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return profileUsernameMap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getActiveOnlyProfiles(skipCurrent) {
|
getActiveOnlyProfiles(skipCurrent) {
|
||||||
@@ -310,10 +272,11 @@ class UserStoreClass extends EventEmitter {
|
|||||||
getProfileList(skipCurrent = false, allowInactive = false) {
|
getProfileList(skipCurrent = false, allowInactive = false) {
|
||||||
const profiles = [];
|
const profiles = [];
|
||||||
const currentId = this.getCurrentId();
|
const currentId = this.getCurrentId();
|
||||||
|
const profileMap = this.getProfiles();
|
||||||
|
|
||||||
for (const id in this.profiles) {
|
for (const id in profileMap) {
|
||||||
if (this.profiles.hasOwnProperty(id)) {
|
if (profileMap.hasOwnProperty(id)) {
|
||||||
var profile = this.profiles[id];
|
var profile = profileMap[id];
|
||||||
|
|
||||||
if (skipCurrent && id === currentId) {
|
if (skipCurrent && id === currentId) {
|
||||||
continue;
|
continue;
|
||||||
@@ -339,103 +302,32 @@ class UserStoreClass extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
saveProfile(profile) {
|
saveProfile(profile) {
|
||||||
this.profiles[profile.id] = profile;
|
store.dispatch({
|
||||||
|
type: UserTypes.RECEIVED_PROFILE,
|
||||||
|
data: profile
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Team-Wide Profiles
|
// 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) {
|
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);
|
return this.getProfileListForIds(userIds, skipCurrent, skipInactive);
|
||||||
}
|
}
|
||||||
|
|
||||||
removeProfileFromTeam(teamId, userId) {
|
removeProfileFromTeam(teamId, userId) {
|
||||||
const userIds = this.profiles_in_team[teamId];
|
store.dispatch({
|
||||||
if (!userIds) {
|
type: UserTypes.RECEIVED_PROFILE_NOT_IN_TEAM,
|
||||||
return;
|
data: {user_id: userId},
|
||||||
}
|
id: teamId
|
||||||
|
});
|
||||||
const index = userIds.indexOf(userId);
|
|
||||||
if (index === -1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
userIds.splice(index, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not In Team Profiles
|
// 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) {
|
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 profiles = [];
|
||||||
const currentId = this.getCurrentId();
|
const currentId = this.getCurrentId();
|
||||||
|
|
||||||
@@ -460,178 +352,84 @@ class UserStoreClass extends EventEmitter {
|
|||||||
return profiles;
|
return profiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Channel-Wide Profiles
|
removeProfileNotInTeam(teamId, userId) {
|
||||||
|
store.dispatch({
|
||||||
saveProfilesInChannel(channelId = ChannelStore.getCurrentId(), profiles) {
|
type: UserTypes.RECEIVED_PROFILE_IN_TEAM,
|
||||||
const oldProfileList = this.profiles_in_channel[channelId] || [];
|
data: {user_id: userId},
|
||||||
const oldProfileMap = {};
|
id: teamId
|
||||||
for (let i = 0; i < oldProfileList.length; i++) {
|
|
||||||
oldProfileMap[oldProfileList[i]] = this.getProfile(oldProfileList[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const newProfileMap = Object.assign({}, oldProfileMap, profiles);
|
|
||||||
const newProfileList = Object.keys(newProfileMap);
|
|
||||||
|
|
||||||
newProfileList.sort((a, b) => {
|
|
||||||
const aProfile = newProfileMap[a];
|
|
||||||
const bProfile = newProfileMap[b];
|
|
||||||
|
|
||||||
if (aProfile.username < bProfile.username) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (aProfile.username > bProfile.username) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
this.profiles_in_channel[channelId] = newProfileList;
|
|
||||||
this.saveProfiles(profiles);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Channel-Wide Profiles
|
||||||
|
|
||||||
saveProfileInChannel(channelId = ChannelStore.getCurrentId(), profile) {
|
saveProfileInChannel(channelId = ChannelStore.getCurrentId(), profile) {
|
||||||
const profileMap = {};
|
store.dispatch({
|
||||||
profileMap[profile.id] = profile;
|
type: UserTypes.RECEIVED_PROFILE_IN_CHANNEL,
|
||||||
this.saveProfilesInChannel(channelId, profileMap);
|
data: {user_id: profile.id},
|
||||||
|
id: channelId
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
saveUserIdInChannel(channelId = ChannelStore.getCurrentId(), userId) {
|
saveUserIdInChannel(channelId = ChannelStore.getCurrentId(), userId) {
|
||||||
const profile = this.getProfile(userId);
|
store.dispatch({
|
||||||
|
type: UserTypes.RECEIVED_PROFILE_IN_CHANNEL,
|
||||||
// Must have profile or we can't sort the list
|
data: {user_id: userId},
|
||||||
if (!profile) {
|
id: channelId
|
||||||
return false;
|
});
|
||||||
}
|
|
||||||
|
|
||||||
this.saveProfileInChannel(channelId, profile);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
removeProfileInChannel(channelId, userId) {
|
removeProfileInChannel(channelId, userId) {
|
||||||
const userIds = this.profiles_in_channel[channelId];
|
store.dispatch({
|
||||||
if (!userIds) {
|
type: UserTypes.RECEIVED_PROFILE_NOT_IN_CHANNEL,
|
||||||
return;
|
data: {user_id: userId},
|
||||||
}
|
id: channelId
|
||||||
|
});
|
||||||
const index = userIds.indexOf(userId);
|
|
||||||
if (index === -1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
userIds.splice(index, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getProfileListInChannel(channelId = ChannelStore.getCurrentId(), skipCurrent = false) {
|
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);
|
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) {
|
saveProfileNotInChannel(channelId = ChannelStore.getCurrentId(), profile) {
|
||||||
const profileMap = {};
|
store.dispatch({
|
||||||
profileMap[profile.id] = profile;
|
type: UserTypes.RECEIVED_PROFILE_NOT_IN_CHANNEL,
|
||||||
this.saveProfilesNotInChannel(channelId, profileMap);
|
data: {user_id: profile.id},
|
||||||
|
id: channelId
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
removeProfileNotInChannel(channelId, userId) {
|
removeProfileNotInChannel(channelId, userId) {
|
||||||
const userIds = this.profiles_not_in_channel[channelId];
|
store.dispatch({
|
||||||
if (!userIds) {
|
type: UserTypes.RECEIVED_PROFILE_IN_CHANNEL,
|
||||||
return;
|
data: {user_id: userId},
|
||||||
}
|
id: channelId
|
||||||
|
});
|
||||||
const index = userIds.indexOf(userId);
|
|
||||||
if (index === -1) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
userIds.splice(index, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getProfileListNotInChannel(channelId = ChannelStore.getCurrentId(), skipInactive = false) {
|
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);
|
return this.getProfileListForIds(userIds, false, skipInactive);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Profiles without any teams
|
// 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) {
|
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);
|
return this.getProfileListForIds(userIds, skipCurrent, skipInactive);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Other
|
// Other
|
||||||
|
|
||||||
setSessions(sessions) {
|
|
||||||
this.sessions = sessions;
|
|
||||||
}
|
|
||||||
|
|
||||||
getSessions() {
|
getSessions() {
|
||||||
return this.sessions;
|
return store.getState().entities.users.mySessions;
|
||||||
}
|
|
||||||
|
|
||||||
setAudits(audits) {
|
|
||||||
this.audits = audits;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getAudits() {
|
getAudits() {
|
||||||
return this.audits;
|
return store.getState().entities.users.myAudits;
|
||||||
}
|
}
|
||||||
|
|
||||||
getCurrentMentionKeys() {
|
getCurrentMentionKeys() {
|
||||||
@@ -668,17 +466,16 @@ class UserStoreClass extends EventEmitter {
|
|||||||
return keys;
|
return keys;
|
||||||
}
|
}
|
||||||
|
|
||||||
setStatuses(statuses) {
|
|
||||||
this.statuses = Object.assign(this.statuses, statuses);
|
|
||||||
}
|
|
||||||
|
|
||||||
setStatus(userId, status) {
|
setStatus(userId, status) {
|
||||||
this.statuses[userId] = status;
|
const data = [{user_id: userId, status}];
|
||||||
this.emitStatusesChange();
|
store.dispatch({
|
||||||
|
type: UserTypes.RECEIVED_STATUSES,
|
||||||
|
data
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getStatuses() {
|
getStatuses() {
|
||||||
return this.statuses;
|
return store.getState().entities.users.statuses;
|
||||||
}
|
}
|
||||||
|
|
||||||
getStatus(id) {
|
getStatus(id) {
|
||||||
@@ -686,7 +483,7 @@ class UserStoreClass extends EventEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getNoAccounts() {
|
getNoAccounts() {
|
||||||
return this.noAccounts;
|
return global.window.mm_config.NoAccounts === 'true';
|
||||||
}
|
}
|
||||||
|
|
||||||
setNoAccounts(noAccounts) {
|
setNoAccounts(noAccounts) {
|
||||||
@@ -706,141 +503,9 @@ class UserStoreClass extends EventEmitter {
|
|||||||
|
|
||||||
return false;
|
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();
|
var UserStore = new UserStoreClass();
|
||||||
UserStore.setMaxListeners(600);
|
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};
|
export {UserStore as default};
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import TeamStore from 'stores/team_store.jsx';
|
|||||||
import ErrorStore from 'stores/error_store.jsx';
|
import ErrorStore from 'stores/error_store.jsx';
|
||||||
|
|
||||||
import * as GlobalActions from 'actions/global_actions.jsx';
|
import * as GlobalActions from 'actions/global_actions.jsx';
|
||||||
import {loadStatusesForProfilesMap} from 'actions/status_actions.jsx';
|
|
||||||
|
|
||||||
import AppDispatcher from 'dispatcher/app_dispatcher.jsx';
|
import AppDispatcher from 'dispatcher/app_dispatcher.jsx';
|
||||||
import Client from 'client/web_client.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() {
|
export function getLogs() {
|
||||||
if (isCallInProgress('getLogs')) {
|
if (isCallInProgress('getLogs')) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
// See License.txt for license information.
|
// See License.txt for license information.
|
||||||
|
|
||||||
import * as Utils from './utils.jsx';
|
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 EditChannelHeaderModal from 'components/edit_channel_header_modal.jsx';
|
||||||
import ToggleModalButton from 'components/toggle_modal_button.jsx';
|
import ToggleModalButton from 'components/toggle_modal_button.jsx';
|
||||||
import UserProfile from 'components/user_profile.jsx';
|
import UserProfile from 'components/user_profile.jsx';
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ if (NPM_TARGET === 'test') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var config = {
|
var config = {
|
||||||
entry: ['babel-polyfill', './root.jsx', 'root.html'],
|
entry: ['babel-polyfill', 'whatwg-fetch', './root.jsx', 'root.html'],
|
||||||
output: {
|
output: {
|
||||||
path: 'dist',
|
path: 'dist',
|
||||||
publicPath: '/static/',
|
publicPath: '/static/',
|
||||||
@@ -33,7 +33,7 @@ var config = {
|
|||||||
module: {
|
module: {
|
||||||
loaders: [
|
loaders: [
|
||||||
{
|
{
|
||||||
test: /\.jsx?$/,
|
test: /\.(js|jsx)?$/,
|
||||||
loader: 'babel-loader',
|
loader: 'babel-loader',
|
||||||
exclude: /(node_modules|non_npm_dependencies)/,
|
exclude: /(node_modules|non_npm_dependencies)/,
|
||||||
query: {
|
query: {
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user