Persist app state to localStorage

pull/841/head
Andrew Watkins 2017-02-02 11:54:56 -08:00
parent 6e95f46ce2
commit e9e6c0b7a3
3 changed files with 61 additions and 1 deletions

View File

@ -23,10 +23,17 @@ import 'src/style/chronograf.scss';
const defaultTimeRange = {upper: null, lower: 'now() - 15m'};
const lsTimeRange = window.localStorage.getItem('timeRange');
const persistedPanels = window.localStorage.getItem('panels');
const persistedQueryConfigs = window.localStorage.getItem('queryConfigs');
const parsedTimeRange = JSON.parse(lsTimeRange) || {};
const timeRange = Object.assign(defaultTimeRange, parsedTimeRange);
const store = configureStore({timeRange});
const store = configureStore({
timeRange,
panels: JSON.parse(persistedPanels),
queryConfigs: JSON.parse(persistedQueryConfigs),
});
const rootNode = document.getElementById('react-root');
let browserHistory;

View File

@ -5,6 +5,7 @@ import makeQueryExecuter from 'src/shared/middleware/queryExecuter';
import * as chronografReducers from 'src/data_explorer/reducers';
import * as sharedReducers from 'src/shared/reducers';
import rulesReducer from 'src/kapacitor/reducers/rules';
import persistStateEnhancer from './persistStateEnhancer';
const rootReducer = combineReducers({
...sharedReducers,
@ -16,6 +17,7 @@ const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
export default function configureStore(initialState) {
const createPersistentStore = composeEnhancers(
persistStateEnhancer(),
applyMiddleware(thunkMiddleware, makeQueryExecuter()),
)(createStore);

View File

@ -0,0 +1,51 @@
/**
* Redux store enhancer (https://github.com/reactjs/redux/blob/master/docs/Glossary.md)
* responsible for sending updates on data explorer state to a server to persist.
* It subscribes a listener function to the store -- meaning every time the store emits an update
* (after some state has changed), we'll have a chance to react.
*
* After the store emits an update, we'll queue a function to request a save in x number of
* seconds. The previous timer is cleared out as well, meaning we won't end up firing a ton of
* saves in a short period of time. Only after the store has been idle for x seconds will the save occur.
*/
const autoSaveTimer = (() => {
let timer;
return {
set(cb) {
const timeUntilSave = 300;
timer = setTimeout(cb, timeUntilSave);
},
clear() {
clearInterval(timer);
},
};
})();
export default function persistState() {
return (next) => (reducer, initialState, enhancer) => {
const store = next(reducer, initialState, enhancer);
store.subscribe(() => {
const state = {...store.getState()};
const {panels, queryConfigs, timeRange} = state;
window.localStorage.setItem('timeRange', JSON.stringify(timeRange));
window.localStorage.setItem('panels', JSON.stringify(panels));
window.localStorage.setItem('queryConfigs', JSON.stringify(queryConfigs));
autoSaveTimer.clear();
autoSaveTimer.set(() => {
try {
// save to localStorage
} catch (err) {
// console.error('Unable to save data explorer session: ', JSON.parse(response).error); // eslint-disable-line no-console
}
});
});
return store;
};
}