diff --git a/project/static/js/app.jsx b/project/static/js/app.jsx index 36ca13669c..b20646513b 100644 --- a/project/static/js/app.jsx +++ b/project/static/js/app.jsx @@ -18,7 +18,7 @@ const StandardRouter = connect((state) => ({ pages }))(require('../MapStore2/web/client/components/app/StandardRouter')); -const appStore = require('../MapStore2/web/client/stores/StandardStore').bind(null, initialState, {}); +const appStore = require('../MapStore2/web/client/stores/StandardStore').bind(null, initialState, {}, {}, {}); const appConfig = { storeOpts, diff --git a/web/client/components/app/StandardApp.jsx b/web/client/components/app/StandardApp.jsx index 55458c874a..d93163cfe6 100644 --- a/web/client/components/app/StandardApp.jsx +++ b/web/client/components/app/StandardApp.jsx @@ -40,52 +40,65 @@ const StandardApp = React.createClass({ appComponent: () => }; }, + getInitialState() { + return { + store: null + }; + }, componentWillMount() { - const onInit = () => { + const onInit = (config) => { if (!global.Intl ) { require.ensure(['intl', 'intl/locale-data/jsonp/en.js', 'intl/locale-data/jsonp/it.js'], (require) => { global.Intl = require('intl'); require('intl/locale-data/jsonp/en.js'); require('intl/locale-data/jsonp/it.js'); - this.init(); + this.init(config); }); } else { - this.init(); + this.init(config); } }; - const opts = assign({}, this.props.storeOpts, { - onPersist: onInit - }); - this.store = this.props.appStore(this.props.pluginsDef.plugins, opts); - if (!opts.persist) { - onInit(); + + if (urlQuery.localConfig) { + ConfigUtils.setLocalConfigurationFile(urlQuery.localConfig + '.json'); } + ConfigUtils.loadConfiguration().then((config) => { + const opts = assign({}, this.props.storeOpts, { + onPersist: onInit.bind(null, config) + }, { + initialState: config.initialState || {defaultState: {}, mobile: {}} + }); + this.store = this.props.appStore(this.props.pluginsDef.plugins, opts); + this.setState({ + store: this.store + }); + + if (!opts.persist) { + onInit(config); + } + }); + }, render() { const {plugins, requires} = this.props.pluginsDef; const {pluginsDef, appStore, initialActions, appComponent, ...other} = this.props; const App = this.props.appComponent; - return ( - + return this.state.store ? ( + - ); + ) : null; }, - init() { + init(config) { this.store.dispatch(changeBrowserProperties(ConfigUtils.getBrowserProperties())); - if (urlQuery.localConfig) { - ConfigUtils.setLocalConfigurationFile(urlQuery.localConfig + '.json'); + this.store.dispatch(localConfigLoaded(config)); + const locale = LocaleUtils.getUserLocale(); + this.store.dispatch(loadLocale(null, locale)); + if (this.props.printingEnabled) { + this.store.dispatch(loadPrintCapabilities(ConfigUtils.getConfigProp('printUrl'))); } - ConfigUtils.loadConfiguration().then((config) => { - this.store.dispatch(localConfigLoaded(config)); - const locale = LocaleUtils.getUserLocale(); - this.store.dispatch(loadLocale(null, locale)); - if (this.props.printingEnabled) { - this.store.dispatch(loadPrintCapabilities(ConfigUtils.getConfigProp('printUrl'))); - } - this.props.initialActions.forEach((action) => { - this.store.dispatch(action()); - }); + this.props.initialActions.forEach((action) => { + this.store.dispatch(action()); }); } }); diff --git a/web/client/components/app/__tests__/StandardApp-test.jsx b/web/client/components/app/__tests__/StandardApp-test.jsx index bcbeb56b45..6024b4580b 100644 --- a/web/client/components/app/__tests__/StandardApp-test.jsx +++ b/web/client/components/app/__tests__/StandardApp-test.jsx @@ -51,19 +51,18 @@ describe('StandardApp', () => { expect(app).toExist(); }); - it('creates a default app with the given store creator', () => { + it('creates a default app with the given store creator', (done) => { let dispatched = 0; const store = () => ({ dispatch() { dispatched++; + done(); } }); const app = ReactDOM.render(, document.getElementById("container")); expect(app).toExist(); - - expect(dispatched > 0).toBe(true); }); it('creates a default app and runs the initial actions', (done) => { @@ -83,20 +82,49 @@ describe('StandardApp', () => { expect(app).toExist(); }); + it('creates a default app and reads initialState from localConfig', (done) => { + const store = (plugins, storeOpts) => { + expect(storeOpts.initialState.defaultState.test).toExist(); + done(); + return { + dispatch() { + } + }; + }; + + const storeOpts = { + initialState: { + defaultState: { + test: "test" + }, + mobile: {} + } + }; + const app = ReactDOM.render(, document.getElementById("container")); + expect(app).toExist(); + }); + it('creates a default app and renders the given component', () => { const store = () => ({ dispatch: () => {}, subscribe: () => {}, getState: () => ({}) }); - - - const app = ReactDOM.render(, document.getElementById("container")); - expect(app).toExist(); - - const dom = ReactDOM.findDOMNode(app); - - expect(dom.className).toBe('mycomponent'); + const oldLoad = ConfigUtils.loadConfiguration; + try { + ConfigUtils.loadConfiguration = () => ({ + then: (callback) => { + callback({}); + } + }); + const app = ReactDOM.render(, document.getElementById("container")); + expect(app).toExist(); + + const dom = ReactDOM.findDOMNode(app); + expect(dom.className).toBe('mycomponent'); + } finally { + ConfigUtils.loadConfiguration = oldLoad; + } }); it('creates a default app and configures plugins', () => { @@ -115,12 +143,21 @@ describe('StandardApp', () => { subscribe: () => {}, getState: () => ({}) }); + const oldLoad = ConfigUtils.loadConfiguration; + try { + ConfigUtils.loadConfiguration = () => ({ + then: (callback) => { + callback({}); + } + }); - const app = ReactDOM.render(, document.getElementById("container")); - expect(app).toExist(); - - const dom = ReactDOM.findDOMNode(app); + const app = ReactDOM.render(, document.getElementById("container")); + expect(app).toExist(); - expect(dom.getElementsByClassName('MyPlugin').length).toBe(1); + const dom = ReactDOM.findDOMNode(app); + expect(dom.getElementsByClassName('MyPlugin').length).toBe(1); + } finally { + ConfigUtils.loadConfiguration = oldLoad; + } }); }); diff --git a/web/client/stores/StandardStore.js b/web/client/stores/StandardStore.js index 3784ea63e9..605ecd55e2 100644 --- a/web/client/stores/StandardStore.js +++ b/web/client/stores/StandardStore.js @@ -26,7 +26,7 @@ const {createEpicMiddleware} = require('redux-observable'); const SecurityUtils = require('../utils/SecurityUtils'); const ListenerEnhancer = require('@carnesen/redux-add-action-listener-enhancer').default; -module.exports = (initialState = {defaultState: {}, mobile: {}}, appReducers = {}, appEpics = {}, plugins, storeOpts) => { +module.exports = (initialState = {defaultState: {}, mobile: {}}, appReducers = {}, appEpics = {}, plugins, storeOpts = {}) => { const allReducers = combineReducers(plugins, { ...appReducers, localConfig: require('../reducers/localConfig'), @@ -40,8 +40,9 @@ module.exports = (initialState = {defaultState: {}, mobile: {}}, appReducers = { layers: () => {return null; } }); const rootEpic = combineEpics(plugins, appEpics); - const defaultState = initialState.defaultState; - const mobileOverride = initialState.mobile; + const optsState = storeOpts.initialState || {defaultState: {}, mobile: {}}; + const defaultState = assign({}, initialState.defaultState, optsState.defaultState); + const mobileOverride = assign({}, initialState.mobile, optsState.mobile); const epicMiddleware = createEpicMiddleware(rootEpic); const rootReducer = (state, action) => { let mapState = createHistory(LayersUtils.splitMapAndLayers(mapConfig(state, action))); diff --git a/web/client/test-resources/localConfig.json b/web/client/test-resources/localConfig.json index 0967ef424b..cccb25b60f 100644 --- a/web/client/test-resources/localConfig.json +++ b/web/client/test-resources/localConfig.json @@ -1 +1,8 @@ -{} +{ + "initialState": { + "defaultState": { + "test": "test" + }, + "mobile": {} + } +}