PLT-5589 Reload configuration when the server config changes (#301)

This commit is contained in:
enahum 2017-02-27 15:15:51 -03:00 committed by Harrison Healey
parent a36702f7d4
commit c1318fe834
13 changed files with 88 additions and 18 deletions

View file

@ -12,13 +12,14 @@ export function loadStorage() {
try {
const data = JSON.parse(await AsyncStorage.getItem('storage'));
const {token, url, currentTeamId, ...otherStorage} = data;
const {token, url, serverVersion, currentTeamId, ...otherStorage} = data;
const credentials = {token, url};
const currentChannelId = otherStorage[currentTeamId] ? otherStorage[currentTeamId].currentChannelId : '';
const actions = [
{type: GeneralTypes.RECEIVED_APP_CREDENTIALS, data: credentials},
{type: GeneralTypes.RECEIVED_SERVER_VERSION, data: serverVersion},
{type: TeamsTypes.SELECT_TEAM, data: currentTeamId},
{type: ChannelTypes.SELECT_CHANNEL, data: currentChannelId}
];

View file

@ -3,10 +3,11 @@
import {NavigationTypes} from 'app/constants';
import Routes from 'app/navigation/routes';
import {updateStorage} from 'app/actions/storage';
import Client from 'service/client';
import {getClientConfig, getLicenseConfig, setServerVersion} from 'service/actions/general';
import {loadMe} from 'service/actions/users';
import {getClientConfig, getLicenseConfig} from 'service/actions/general';
export function goToSelectServer() {
return async (dispatch, getState) => {
@ -23,13 +24,21 @@ export function setStoreFromLocalData(data) {
Client.setToken(data.token);
Client.setUrl(data.url);
await getClientConfig()(dispatch, getState);
await getLicenseConfig()(dispatch, getState);
return loadMe()(dispatch, getState);
};
}
export function loadConfigAndLicense(serverVersion) {
return async (dispatch, getState) => {
getClientConfig()(dispatch, getState);
getLicenseConfig()(dispatch, getState);
setServerVersion(serverVersion)(dispatch, getState);
await updateStorage(null, {serverVersion});
};
}
export default {
goToSelectServer,
loadConfigAndLicense,
setStoreFromLocalData
};

View file

@ -3,14 +3,17 @@
import React from 'react';
import {AppState} from 'react-native';
import {getTranslations} from 'service/i18n';
import {IntlProvider} from 'react-intl';
import {Constants} from 'service/constants';
import {getTranslations} from 'service/i18n';
import EventEmitter from 'service/utils/event_emitter';
export default class Root extends React.Component {
static propTypes = {
children: React.PropTypes.node,
locale: React.PropTypes.string.isRequired,
actions: React.PropTypes.shape({
loadConfigAndLicense: React.PropTypes.func.isRequired,
setAppState: React.PropTypes.func
}).isRequired
};
@ -25,16 +28,22 @@ export default class Root extends React.Component {
componentDidMount() {
AppState.addEventListener('change', this.handleAppStateChange);
EventEmitter.on(Constants.CONFIG_CHANGED, this.handleConfigChanged);
}
componentWillUnmount() {
AppState.removeEventListener('change', this.handleAppStateChange);
EventEmitter.off(Constants.CONFIG_CHANGED, this.handleConfigChanged);
}
handleAppStateChange(appState) {
this.props.actions.setAppState(appState === 'active');
}
handleConfigChanged = (serverVersion) => {
this.props.actions.loadConfigAndLicense(serverVersion);
};
render() {
const locale = this.props.locale;

View file

@ -6,6 +6,7 @@ import {connect} from 'react-redux';
import Config from 'assets/config.json';
import {loadConfigAndLicense} from 'app/actions/views/root';
import {setAppState} from 'service/actions/general';
import Root from './root';
@ -28,6 +29,7 @@ function mapStateToProps(state, ownProps) {
function mapDispatchToProps(dispatch) {
return {
actions: bindActionCreators({
loadConfigAndLicense,
setAppState
}, dispatch)
};

View file

@ -32,8 +32,6 @@ class Login extends Component {
handleSuccessfulLogin: React.PropTypes.func.isRequired,
checkMfa: React.PropTypes.func.isRequired,
login: React.PropTypes.func.isRequired,
getClientConfig: React.PropTypes.func.isRequired,
getLicenseConfig: React.PropTypes.func.isRequired,
goToMfa: React.PropTypes.func.isRequired,
goToLoadTeam: React.PropTypes.func.isRequired
}).isRequired,
@ -55,11 +53,6 @@ class Login extends Component {
};
}
componentWillMount() {
this.props.actions.getClientConfig();
this.props.actions.getLicenseConfig();
}
componentWillReceiveProps(nextProps) {
if (this.props.loginRequest.status === RequestStatus.STARTED && nextProps.loginRequest.status === RequestStatus.SUCCESS) {
this.props.actions.handleSuccessfulLogin().then(this.props.actions.goToLoadTeam);
@ -193,7 +186,7 @@ class Login extends Component {
};
}
return error.message;
}
};
loginRef = (ref) => {
this.loginId = ref;

View file

@ -5,7 +5,6 @@ import {bindActionCreators} from 'redux';
import navigationSceneConnect from '../navigationSceneConnect';
import {getClientConfig, getLicenseConfig} from 'service/actions/general';
import LoginActions from 'app/actions/views/login';
import {goToMfa, goToLoadTeam} from 'app/actions/navigation';
import {checkMfa, login} from 'service/actions/users';
@ -33,8 +32,6 @@ function mapDispatchToProps(dispatch) {
...LoginActions,
checkMfa,
login,
getClientConfig,
getLicenseConfig,
goToMfa,
goToLoadTeam
}, dispatch)

View file

@ -73,10 +73,17 @@ export function setAppState(state) {
};
}
export function setServerVersion(serverVersion) {
return async (dispatch, getState) => {
dispatch({type: GeneralTypes.RECEIVED_SERVER_VERSION, data: serverVersion}, getState);
};
}
export default {
getPing,
getClientConfig,
getLicenseConfig,
logClientError,
setAppState
setAppState,
setServerVersion
};

View file

@ -142,6 +142,9 @@ function handleEvent(msg, dispatch, getState) {
case WebsocketEvents.TYPING:
handleUserTypingEvent(msg, dispatch, getState);
break;
case WebsocketEvents.HELLO:
handleHelloEvent(msg);
break;
}
}
@ -358,6 +361,14 @@ function handleStatusChangedEvent(msg, dispatch, getState) {
}, getState);
}
function handleHelloEvent(msg) {
const serverVersion = msg.data.server_version;
if (Client.serverVersion !== serverVersion) {
Client.serverVersion = serverVersion;
EventEmitter.emit(Constants.CONFIG_CHANGED, serverVersion);
}
}
const typingUsers = {};
function handleUserTypingEvent(msg, dispatch, getState) {
const state = getState();

View file

@ -1,11 +1,15 @@
// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import EventEmitter from 'service/utils/event_emitter';
import {Constants} from 'service/constants';
const HEADER_AUTH = 'Authorization';
const HEADER_BEARER = 'BEARER';
const HEADER_CONTENT_TYPE = 'Content-Type';
const HEADER_REQUESTED_WITH = 'X-Requested-With';
const HEADER_TOKEN = 'Token';
const HEADER_X_VERSION_ID = 'X-Version-Id';
const CONTENT_TYPE_JSON = 'application/json';
@ -15,6 +19,7 @@ export default class Client {
this.token = '';
this.url = '';
this.urlVersion = '/api/v3';
this.serverVersion = '';
this.translations = {
connectionError: 'There appears to be a problem with your internet connection.',
@ -38,6 +43,10 @@ export default class Client {
this.token = token;
}
getServerVersion() {
return this.serverVersion;
}
getUrlVersion() {
return this.urlVersion;
}
@ -708,6 +717,14 @@ export default class Client {
data = await response.text();
}
if (headers.has(HEADER_X_VERSION_ID)) {
const serverVersion = headers.get(HEADER_X_VERSION_ID);
if (this.serverVersion !== serverVersion) {
this.serverVersion = serverVersion;
EventEmitter.emit(Constants.CONFIG_CHANGED, serverVersion);
}
}
if (response.ok) {
return {
response,

View file

@ -2,6 +2,8 @@
// See License.txt for license information.
const Constants = {
CONFIG_CHANGED: 'config_changed',
POST_CHUNK_SIZE: 60,
PROFILE_CHUNK_SIZE: 100,
CHANNELS_CHUNK_SIZE: 50,

View file

@ -12,6 +12,8 @@ const GeneralTypes = keyMirror({
PING_SUCCESS: null,
PING_FAILURE: null,
RECEIVED_SERVER_VERSION: null,
CLIENT_CONFIG_REQUEST: null,
CLIENT_CONFIG_SUCCESS: null,
CLIENT_CONFIG_FAILURE: null,

View file

@ -48,9 +48,21 @@ function credentials(state = {}, action) {
}
}
function serverVersion(state = '', action) {
switch (action.type) {
case GeneralTypes.RECEIVED_SERVER_VERSION:
return action.data;
case UsersTypes.LOGOUT_SUCCESS:
return '';
default:
return state;
}
}
export default combineReducers({
appState,
credentials,
config,
license
license,
serverVersion
});

View file

@ -75,4 +75,12 @@ describe('Actions.General', () => {
// Check a few basic fields since they may change over time
assert.notStrictEqual(licenseConfig.IsLicensed, undefined);
});
it('setServerVersion', async () => {
const version = '3.7.0';
await Actions.setServerVersion(version)(store.dispatch, store.getState);
const {serverVersion} = store.getState().entities.general;
assert.deepEqual(serverVersion, version);
});
});