commit 7abe44ef73ecffe19f33629a736f7e1e3505515b Author: Felix Edel Date: Mon Sep 28 08:15:03 2020 +0200 Configure redux for development This enables the redux developer tools for the browser. To make use of this, one must also install the Redux DevTools extension which is available for various browsers. The extension visualize all state transitions in the redux store and also allows changing them manually to see the effects. Additionally, this change makes use of the third-party library called "redux-immutable-state-invariant", which throws exception in development mode whenever a state is mutated directly within an action or reducer. Change-Id: I8a8588cd7f5f1b17b247d9700a492e5c1e27f040 diff --git a/web/.eslintrc b/web/.eslintrc index 6afc1d2..4527f2e 100644 --- a/web/.eslintrc +++ b/web/.eslintrc @@ -23,3 +23,4 @@ env: jest/globals: true browser: true es6: true + node: true diff --git a/web/package.json b/web/package.json index 693f892..872f094 100644 --- a/web/package.json +++ b/web/package.json @@ -28,6 +28,7 @@ "react-scripts": "3.4.1", "react-select": "3.1.0", "redux": "^4.0.5", + "redux-immutable-state-invariant": "^2.1.0", "redux-thunk": "^2.3.0", "sockette": "^2.0.0", "swagger-ui": "^3.20.1", diff --git a/web/src/App.test.jsx b/web/src/App.test.jsx index ced7ac0..60c40d4 100644 --- a/web/src/App.test.jsx +++ b/web/src/App.test.jsx @@ -19,7 +19,7 @@ import { Link, BrowserRouter as Router } from 'react-router-dom' import { Provider } from 'react-redux' import { fetchInfoIfNeeded } from './actions/info' -import store from './store' +import configureStore from './store' import App from './App' import TenantsPage from './pages/Tenants' import StatusPage from './pages/Status' @@ -31,6 +31,7 @@ api.fetchStatus = jest.fn() api.fetchConfigErrors = jest.fn() api.fetchConfigErrors.mockImplementation(() => Promise.resolve({data: []})) +const store = configureStore() it('renders without crashing', () => { const div = document.createElement('div') diff --git a/web/src/api.js b/web/src/api.js index 619da33..df49278 100644 --- a/web/src/api.js +++ b/web/src/api.js @@ -1,4 +1,3 @@ -/* global process */ // Copyright 2018 Red Hat, Inc // // Licensed under the Apache License, Version 2.0 (the "License"); you may diff --git a/web/src/containers/status/ChangePanel.test.jsx b/web/src/containers/status/ChangePanel.test.jsx index d432c01..76a3051 100644 --- a/web/src/containers/status/ChangePanel.test.jsx +++ b/web/src/containers/status/ChangePanel.test.jsx @@ -18,7 +18,7 @@ import { Link, BrowserRouter as Router } from 'react-router-dom' import { Provider } from 'react-redux' import { setTenantAction } from '../../actions/tenant' -import store from '../../store' +import configureStore from '../../store' import ChangePanel from './ChangePanel' @@ -31,6 +31,8 @@ const fakeChange = { }] } +const store = configureStore() + it('change panel render multi tenant links', () => { store.dispatch(setTenantAction('tenant-one', false)) const application = ReactTestUtils.renderIntoDocument( diff --git a/web/src/index.js b/web/src/index.js index 549e60c..c0a1772 100644 --- a/web/src/index.js +++ b/web/src/index.js @@ -37,7 +37,7 @@ import './pf4-migration.css' import { getHomepageUrl } from './api' import registerServiceWorker from './registerServiceWorker' import { fetchInfoIfNeeded } from './actions/info' -import store from './store' +import configureStore from './store' import App from './App' // Importing our custom css file after the App allows us to also overwrite the @@ -45,6 +45,8 @@ import App from './App' // is imported within the App). import './index.css' +const store = configureStore() + // Load info endpoint store.dispatch(fetchInfoIfNeeded()) diff --git a/web/src/registerServiceWorker.js b/web/src/registerServiceWorker.js index 483e5d5..e6c8545 100644 --- a/web/src/registerServiceWorker.js +++ b/web/src/registerServiceWorker.js @@ -1,4 +1,3 @@ -/* global process */ // In production, we register a service worker to serve assets from local cache. // This lets the app load faster on subsequent visits in production, and gives diff --git a/web/src/store.dev.js b/web/src/store.dev.js new file mode 100644 index 0000000..2c0f16a --- /dev/null +++ b/web/src/store.dev.js @@ -0,0 +1,39 @@ +// Copyright 2020 BMW Group +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +import { applyMiddleware, compose, createStore } from 'redux' +import appReducer from './reducers' +import reduxImmutableStateInvariant from 'redux-immutable-state-invariant' +import thunk from 'redux-thunk' + +export default function configureStore(initialState) { + // Add support for Redux devtools + const composeEnhancers = + window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose + return createStore( + appReducer, + initialState, + // Warn us if we accidentially mutate state directly in the Redux store + // (only during development). + composeEnhancers( + applyMiddleware( + thunk, + // TODO (felix): Re-enable the status.status path once we know how to + // solve the weird state mutations that are done somewhere deep within + // the logic of the status page (or its child components). + reduxImmutableStateInvariant({ ignore: ['status.status'] }) + ) + ) + ) +} diff --git a/web/src/store.js b/web/src/store.js index ec1b844..783b590 100644 --- a/web/src/store.js +++ b/web/src/store.js @@ -12,11 +12,9 @@ // License for the specific language governing permissions and limitations // under the License. -import { applyMiddleware, createStore } from 'redux' -import thunk from 'redux-thunk' - -import appReducers from './reducers' - -const store = createStore(appReducers, applyMiddleware(thunk)) - -export default store \ No newline at end of file +// Use CommonJS require so we can dynamically import during build-time. +if (process.env.NODE_ENV === 'production') { + module.exports = require('./store.prod') +} else { + module.exports = require('./store.dev') +} diff --git a/web/src/store.prod.js b/web/src/store.prod.js new file mode 100644 index 0000000..4915ba6 --- /dev/null +++ b/web/src/store.prod.js @@ -0,0 +1,21 @@ +// Copyright 2020 BMW Group +// +// Licensed under the Apache License, Version 2.0 (the "License"); you may +// not use this file except in compliance with the License. You may obtain +// a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +// License for the specific language governing permissions and limitations +// under the License. + +import { applyMiddleware, createStore } from 'redux' +import appReducer from './reducers' +import thunk from 'redux-thunk' + +export default function configureStore(initialState) { + return createStore(appReducer, initialState, applyMiddleware(thunk)) +} diff --git a/web/yarn.lock b/web/yarn.lock index 9d70c3f..d8d20c7 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -7305,7 +7305,7 @@ into-stream@^5.0.0: from2 "^2.3.0" p-is-promise "^3.0.0" -invariant@^2.0.0, invariant@^2.2.0, invariant@^2.2.1, invariant@^2.2.2, invariant@^2.2.4: +invariant@^2.0.0, invariant@^2.1.0, invariant@^2.2.0, invariant@^2.2.1, invariant@^2.2.2, invariant@^2.2.4: version "2.2.4" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6" integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA== @@ -12450,6 +12450,14 @@ redeyed@~2.1.0: dependencies: esprima "~4.0.0" +redux-immutable-state-invariant@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/redux-immutable-state-invariant/-/redux-immutable-state-invariant-2.1.0.tgz#308fd3cc7415a0e7f11f51ec997b6379c7055ce1" + integrity sha512-3czbDKs35FwiBRsx/3KabUk5zSOoTXC+cgVofGkpBNv3jQcqIe5JrHcF5AmVt7B/4hyJ8MijBIpCJ8cife6yJg== + dependencies: + invariant "^2.1.0" + json-stringify-safe "^5.0.1" + redux-immutable@3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/redux-immutable/-/redux-immutable-3.1.0.tgz#cafbd686e0711261119b9c28960935dc47a49d0a"