Add and persist activePanel state

pull/841/head
Andrew Watkins 2017-02-06 11:32:23 -08:00
parent 01821ec5e3
commit 0fc2faa2a8
11 changed files with 62 additions and 41 deletions

View File

@ -4,8 +4,8 @@ export function createPanel() {
return {
type: 'CREATE_PANEL',
payload: {
panelId: uuid.v4(), // for the default Panel
queryId: uuid.v4(), // for the default Query
panelID: uuid.v4(), // for the default Panel
queryID: uuid.v4(), // for the default Query
},
};
}
@ -159,3 +159,12 @@ export function updateRawQuery(queryID, text) {
},
};
}
export function activatePanel(panelID) {
return {
type: 'ACTIVATE_PANEL',
payload: {
panelID,
},
};
}

View File

@ -9,6 +9,7 @@ const PanelBuilder = React.createClass({
propTypes: {
width: string,
actions: PropTypes.shape({
activatePanel: func.isRequired,
createPanel: func.isRequired,
deleteQuery: func.isRequired,
addQuery: func.isRequired,
@ -23,25 +24,23 @@ const PanelBuilder = React.createClass({
toggleTagAcceptance: func.isRequired,
deletePanel: func.isRequired,
}).isRequired,
setActivePanel: func.isRequired,
setActiveQuery: func.isRequired,
activePanelID: string,
activeQueryID: string,
},
handleCreateExploer() {
handleCreateExplorer() {
this.props.actions.createPanel();
},
render() {
const {width, actions, setActivePanel, setActiveQuery, activePanelID, activeQueryID} = this.props;
const {width, actions, setActiveQuery, activePanelID, activeQueryID} = this.props;
return (
<div className="panel-builder" style={{width}}>
<div className="btn btn-block btn-primary" onClick={this.handleCreateExploer}><span className="icon graphline"></span>&nbsp;&nbsp;Create Graph</div>
<div className="btn btn-block btn-primary" onClick={this.handleCreateExplorer}><span className="icon graphline"></span>&nbsp;&nbsp;Create Graph</div>
<PanelList
actions={actions}
setActivePanel={setActivePanel}
setActiveQuery={setActiveQuery}
activePanelID={activePanelID}
activeQueryID={activeQueryID}

View File

@ -13,20 +13,20 @@ const PanelList = React.createClass({
}).isRequired,
panels: shape({}).isRequired,
queryConfigs: PropTypes.shape({}),
actions: shape({}).isRequired,
setActivePanel: func.isRequired,
actions: shape({
activatePanel: func.isRequired,
deleteQuery: func.isRequired,
addQuery: func.isRequired,
}).isRequired,
setActiveQuery: func.isRequired,
activePanelID: string,
activeQueryID: string,
},
handleTogglePanel(panel) {
// If the panel being toggled is currently active, it means we should
// close everything by setting `activePanelID` to null.
const activePanelID = panel.id === this.props.activePanelID ?
null : panel.id;
const panelID = panel.id === this.props.activePanelID ? null : panel.id;
this.props.actions.activatePanel(panelID);
this.props.setActivePanel(activePanelID);
// Reset the activeQueryID when toggling Exporations
this.props.setActiveQuery(null);
},

View File

@ -27,6 +27,7 @@ const DataExplorer = React.createClass({
upper: string,
lower: string,
}).isRequired,
activePanel: string,
setTimeRange: func.isRequired,
},
@ -45,21 +46,16 @@ const DataExplorer = React.createClass({
getInitialState() {
return {
activePanelID: null,
activeQueryID: null,
};
},
handleSetActivePanel(id) {
this.setState({activePanelID: id});
},
handleSetActiveQuery(id) {
this.setState({activeQueryID: id});
},
render() {
const {timeRange, setTimeRange} = this.props;
const {timeRange, setTimeRange, activePanel} = this.props;
return (
<div className="data-explorer">
@ -70,14 +66,13 @@ const DataExplorer = React.createClass({
<ResizeContainer>
<PanelBuilder
timeRange={timeRange}
activePanelID={this.state.activePanelID}
activePanelID={activePanel}
activeQueryID={this.state.activeQueryID}
setActiveQuery={this.handleSetActiveQuery}
setActivePanel={this.handleSetActivePanel}
/>
<Visualizations
timeRange={timeRange}
activePanelID={this.state.activePanelID}
activePanelID={activePanel}
activeQueryID={this.state.activeQueryID}
/>
</ResizeContainer>
@ -87,8 +82,11 @@ const DataExplorer = React.createClass({
});
function mapStateToProps(state) {
const {timeRange, dataExplorerUI} = state;
return {
timeRange: state.timeRange,
timeRange,
activePanel: dataExplorerUI.activePanel,
};
}

View File

@ -0,0 +1,11 @@
export default function dataExplorerUI(state = {}, action) {
switch (action.type) {
case 'ACTIVATE_PANEL':
case 'CREATE_PANEL': {
const {panelID} = action.payload;
return {...state, activePanel: panelID};
}
}
return state;
}

View File

@ -1,9 +1,11 @@
import queryConfigs from './queryConfigs';
import panels from './panels';
import timeRange from './timeRange';
import dataExplorerUI from './dataExplorerUI';
export {
queryConfigs,
panels,
timeRange,
dataExplorerUI,
};

View File

@ -3,15 +3,11 @@ import update from 'react-addons-update';
export default function panels(state = {}, action) {
switch (action.type) {
case 'CREATE_PANEL': {
const {panelId, queryId} = action.payload;
const panel = {
id: panelId,
queryIds: [queryId],
const {panelID, queryID} = action.payload;
return {
...state,
[panelID]: {id: panelID, queryIds: [queryID]},
};
return update(state, {
[panelId]: {$set: panel},
});
}
case 'RENAME_PANEL': {
@ -50,5 +46,6 @@ export default function panels(state = {}, action) {
});
}
}
return state;
}

View File

@ -49,9 +49,9 @@ export default function queryConfigs(state = {}, action) {
case 'CREATE_PANEL':
case 'ADD_KAPACITOR_QUERY':
case 'ADD_QUERY': {
const {queryId, options} = action.payload;
const {queryID, options} = action.payload;
const nextState = Object.assign({}, state, {
[queryId]: Object.assign({}, defaultQueryConfig(queryId), options),
[queryID]: Object.assign({}, defaultQueryConfig(queryID), options),
});
return nextState;

View File

@ -19,9 +19,14 @@ export const loadLocalStorage = () => {
}
};
export const saveToLocalStorage = ({panels, queryConfigs, timeRange}) => {
export const saveToLocalStorage = ({panels, queryConfigs, timeRange, dataExplorerUI}) => {
try {
window.localStorage.setItem('state', JSON.stringify({panels, queryConfigs, timeRange}));
window.localStorage.setItem('state', JSON.stringify({
panels,
queryConfigs,
timeRange,
dataExplorerUI,
}));
} catch (err) {
console.error('Unable to save data explorer: ', JSON.parse(err)); // eslint-disable-line no-console
}

View File

@ -2,14 +2,14 @@ import {createStore, applyMiddleware, compose} from 'redux';
import {combineReducers} from 'redux';
import thunkMiddleware from 'redux-thunk';
import makeQueryExecuter from 'src/shared/middleware/queryExecuter';
import * as chronografReducers from 'src/data_explorer/reducers';
import * as dataExplorerReducers 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,
...chronografReducers,
...dataExplorerReducers,
rules: rulesReducer,
});

View File

@ -13,11 +13,11 @@ import {saveToLocalStorage} from '../localStorage';
export default function persistState() {
return (next) => (reducer, initialState, enhancer) => {
const store = next(reducer, initialState, enhancer);
const debounceMs = 1000;
const throttleMs = 1000;
store.subscribe(_.debounce(() => {
store.subscribe(_.throttle(() => {
saveToLocalStorage({...store.getState()});
}, debounceMs));
}, throttleMs));
return store;
};