From 8c796f8c289388d8a2ded51a808992c8ace56055 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Fri, 2 Nov 2018 15:38:33 +0100 Subject: [PATCH] fix(front): show an error if db is not responding --- conf/devConfig.js | 1 - package.json | 1 + src/client/actions/db.js | 7 +- src/client/actions/main.js | 15 +++ src/client/components/App.js | 198 +++++++++++++++++-------------- src/client/components/Sidebar.js | 53 +++++---- src/client/index.js | 3 + src/client/reducers/main.js | 16 +++ src/client/store.js | 6 +- src/server/server.js | 27 +++-- webpack.config.js | 13 +- 11 files changed, 200 insertions(+), 140 deletions(-) create mode 100644 src/client/actions/main.js create mode 100644 src/client/reducers/main.js diff --git a/conf/devConfig.js b/conf/devConfig.js index 174bf619..b738cd68 100644 --- a/conf/devConfig.js +++ b/conf/devConfig.js @@ -11,7 +11,6 @@ module.exports = { password: 'admin', // Already administrator from global configuration superAdministrators: ['admin@a.com', 'a@a.com'], - autoCreateDatabase: true, sessionSigned: true, allowedOrigins: ['http://localhost:8080'] }; diff --git a/package.json b/package.json index b6313ea5..7978fe97 100644 --- a/package.json +++ b/package.json @@ -97,6 +97,7 @@ "devDependencies": { "@babel/cli": "^7.1.2", "@babel/core": "^7.1.2", + "@babel/plugin-proposal-object-rest-spread": "^7.0.0", "@babel/plugin-transform-async-to-generator": "^7.1.0", "@babel/preset-env": "^7.1.0", "@babel/preset-react": "^7.0.0", diff --git a/src/client/actions/db.js b/src/client/actions/db.js index 031f0b88..fa7e7011 100644 --- a/src/client/actions/db.js +++ b/src/client/actions/db.js @@ -118,11 +118,12 @@ export function setLdapGroupProperties(groupName, properties) { }; } -function doUpdateGroupProperties(groupUrl, setPropUrl, properties) { - return apiFetchJSON(setPropUrl, { +async function doUpdateGroupProperties(groupUrl, setPropUrl, properties) { + await apiFetchJSON(setPropUrl, { method: 'PUT', body: JSON.stringify(properties) - }).then(() => apiFetchJSON(groupUrl)); + }); + return apiFetchJSON(groupUrl); } export function syncLdapGroup(groupName) { diff --git a/src/client/actions/main.js b/src/client/actions/main.js new file mode 100644 index 00000000..4813c375 --- /dev/null +++ b/src/client/actions/main.js @@ -0,0 +1,15 @@ +import { apiFetchJSON } from '../api'; + +export const ROC_ONLINE = 'ROC_ONLINE'; + +export function getRocStatus() { + return async (dispatch) => { + try { + const result = await apiFetchJSON('auth/session'); + dispatch({ type: ROC_ONLINE, payload: !!result.ok }); + } catch (e) { + dispatch({ type: ROC_ONLINE, payload: false }); + } + setTimeout(() => dispatch(getRocStatus()), 10000); + }; +} diff --git a/src/client/components/App.js b/src/client/components/App.js index 8a21f832..5245d80e 100644 --- a/src/client/components/App.js +++ b/src/client/components/App.js @@ -18,112 +18,126 @@ import DatabaseAdministration from './DatabaseAdministration'; import GroupMemberships from './GroupMemberships'; import Allowed from './Allowed'; -const App = (props) => ( - -
-
- -
- + -
-
- - ( - +
+ {rocOnline ? ( + + ( + + )} /> - )} - /> - { - return ( - { + return ( + + + + ); + }} + /> + + { + return ( + + + ; + + ); + }} + /> + { + if (props.loggedIn) { + return ; + } else { + return ; } - > - - - ); - }} - /> - - { - return ( - - - ; - - ); - }} - /> - { - if (props.loggedIn) { - return ; - } else { - return ; - } - }} - /> - - - - + }} + /> + + + + + ) : rocOnline === false ? ( +
Could not connect to the database...
+ ) : null} +
-
-
-); + + ); +}; App.propTypes = { loggedIn: PropTypes.bool.isRequired }; export default connect((state) => ({ + rocOnline: state.main.rocOnline, loggedUser: state.login.username, loggedIn: !!state.login.username, loginProvider: state.login.provider, diff --git a/src/client/components/Sidebar.js b/src/client/components/Sidebar.js index 27b0dece..92d98e1a 100644 --- a/src/client/components/Sidebar.js +++ b/src/client/components/Sidebar.js @@ -4,6 +4,7 @@ import { Link } from 'react-router-dom'; import SidebarLink from './SidebarLink'; export default function Sidebar({ + rocOnline, loggedIn, loginProvider, isAdmin, @@ -18,33 +19,35 @@ export default function Sidebar({ rest-on-couch - + )} ); diff --git a/src/client/index.js b/src/client/index.js index b05bd624..b11c591d 100644 --- a/src/client/index.js +++ b/src/client/index.js @@ -4,6 +4,9 @@ import { Provider } from 'react-redux'; import store from './store'; import App from './components/App'; +import { getRocStatus } from './actions/main'; + +store.dispatch(getRocStatus()); render( diff --git a/src/client/reducers/main.js b/src/client/reducers/main.js new file mode 100644 index 00000000..0e4e0fbb --- /dev/null +++ b/src/client/reducers/main.js @@ -0,0 +1,16 @@ +import { ROC_ONLINE } from '../actions/main'; + +const initialState = { + rocOnline: null +}; + +const mainReducer = (state = initialState, action) => { + switch (action.type) { + case ROC_ONLINE: + return { ...state, rocOnline: action.payload }; + default: + return state; + } +}; + +export default mainReducer; diff --git a/src/client/store.js b/src/client/store.js index f82899bb..cf7f2783 100644 --- a/src/client/store.js +++ b/src/client/store.js @@ -5,6 +5,7 @@ import { persistStore, persistCombineReducers } from 'redux-persist'; import storage from 'redux-persist/lib/storage'; import DbManager from './dbManager'; +import mainReducer from './reducers/main'; import dbReducer from './reducers/db'; import dbNameReducer from './reducers/dbName'; import loginReducer from './reducers/login'; @@ -24,6 +25,7 @@ const rootReducer = persistCombineReducers( throttle: 1000 }, { + main: mainReducer, db: dbReducer, dbName: dbNameReducer, login: loginReducer @@ -46,8 +48,8 @@ export const dbManager = new DbManager(store); function onRehydrated() { function getParameterByName(name) { - var match = RegExp(`[?&]${name}=([^&]*)`).exec(window.location.search); - return match && decodeURIComponent(match[1].replace(/\+/g, ' ')); + const url = new URL(window.location.href); + return url.searchParams.get(name); } // If url has a database name, we override the persisted database name diff --git a/src/server/server.js b/src/server/server.js index 0c756c20..f0aabf23 100644 --- a/src/server/server.js +++ b/src/server/server.js @@ -147,18 +147,21 @@ app.use(api.routes()); module.exports.start = function () { if (_started) return _started; _started = new Promise(function (resolve, reject) { - initCouch().then(() => { - http.createServer(app.callback()).listen(config.port, function () { - debug.warn(`running on localhost: ${config.port}`); - resolve(app); - }); - }, (e) => { - reject(e); - process.nextTick(() => { - debug.error('initialization failed'); - throw e; - }); - }); + initCouch().then( + () => { + http.createServer(app.callback()).listen(config.port, function () { + debug.warn(`running on localhost: ${config.port}`); + resolve(app); + }); + }, + (e) => { + reject(e); + process.nextTick(() => { + debug.error('initialization failed'); + throw e; + }); + } + ); }); return _started; }; diff --git a/webpack.config.js b/webpack.config.js index be8ac8be..192f2642 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -6,7 +6,10 @@ const isProduction = process.env.NODE_ENV === 'production'; const TerserPlugin = require('terser-webpack-plugin'); const babelConfig = { - plugins: ['@babel/transform-async-to-generator'], + plugins: [ + '@babel/proposal-object-rest-spread', + '@babel/transform-async-to-generator' + ], presets: ['@babel/react'] }; const entry = ['whatwg-fetch', './src/client/index.js']; @@ -29,10 +32,10 @@ if (isProduction) { entry.unshift('regenerator-runtime/runtime'); optimization = { minimizer: [ - new TerserPlugin({ - parallel: true, - sourceMap: true - }) + new TerserPlugin({ + parallel: true, + sourceMap: true + }) ] }; }