Add and persist activePanel state
parent
01821ec5e3
commit
0fc2faa2a8
|
@ -4,8 +4,8 @@ export function createPanel() {
|
||||||
return {
|
return {
|
||||||
type: 'CREATE_PANEL',
|
type: 'CREATE_PANEL',
|
||||||
payload: {
|
payload: {
|
||||||
panelId: uuid.v4(), // for the default Panel
|
panelID: uuid.v4(), // for the default Panel
|
||||||
queryId: uuid.v4(), // for the default Query
|
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,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ const PanelBuilder = React.createClass({
|
||||||
propTypes: {
|
propTypes: {
|
||||||
width: string,
|
width: string,
|
||||||
actions: PropTypes.shape({
|
actions: PropTypes.shape({
|
||||||
|
activatePanel: func.isRequired,
|
||||||
createPanel: func.isRequired,
|
createPanel: func.isRequired,
|
||||||
deleteQuery: func.isRequired,
|
deleteQuery: func.isRequired,
|
||||||
addQuery: func.isRequired,
|
addQuery: func.isRequired,
|
||||||
|
@ -23,25 +24,23 @@ const PanelBuilder = React.createClass({
|
||||||
toggleTagAcceptance: func.isRequired,
|
toggleTagAcceptance: func.isRequired,
|
||||||
deletePanel: func.isRequired,
|
deletePanel: func.isRequired,
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
setActivePanel: func.isRequired,
|
|
||||||
setActiveQuery: func.isRequired,
|
setActiveQuery: func.isRequired,
|
||||||
activePanelID: string,
|
activePanelID: string,
|
||||||
activeQueryID: string,
|
activeQueryID: string,
|
||||||
},
|
},
|
||||||
|
|
||||||
handleCreateExploer() {
|
handleCreateExplorer() {
|
||||||
this.props.actions.createPanel();
|
this.props.actions.createPanel();
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {width, actions, setActivePanel, setActiveQuery, activePanelID, activeQueryID} = this.props;
|
const {width, actions, setActiveQuery, activePanelID, activeQueryID} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="panel-builder" style={{width}}>
|
<div className="panel-builder" style={{width}}>
|
||||||
<div className="btn btn-block btn-primary" onClick={this.handleCreateExploer}><span className="icon graphline"></span> Create Graph</div>
|
<div className="btn btn-block btn-primary" onClick={this.handleCreateExplorer}><span className="icon graphline"></span> Create Graph</div>
|
||||||
<PanelList
|
<PanelList
|
||||||
actions={actions}
|
actions={actions}
|
||||||
setActivePanel={setActivePanel}
|
|
||||||
setActiveQuery={setActiveQuery}
|
setActiveQuery={setActiveQuery}
|
||||||
activePanelID={activePanelID}
|
activePanelID={activePanelID}
|
||||||
activeQueryID={activeQueryID}
|
activeQueryID={activeQueryID}
|
||||||
|
|
|
@ -13,20 +13,20 @@ const PanelList = React.createClass({
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
panels: shape({}).isRequired,
|
panels: shape({}).isRequired,
|
||||||
queryConfigs: PropTypes.shape({}),
|
queryConfigs: PropTypes.shape({}),
|
||||||
actions: shape({}).isRequired,
|
actions: shape({
|
||||||
setActivePanel: func.isRequired,
|
activatePanel: func.isRequired,
|
||||||
|
deleteQuery: func.isRequired,
|
||||||
|
addQuery: func.isRequired,
|
||||||
|
}).isRequired,
|
||||||
setActiveQuery: func.isRequired,
|
setActiveQuery: func.isRequired,
|
||||||
activePanelID: string,
|
activePanelID: string,
|
||||||
activeQueryID: string,
|
activeQueryID: string,
|
||||||
},
|
},
|
||||||
|
|
||||||
handleTogglePanel(panel) {
|
handleTogglePanel(panel) {
|
||||||
// If the panel being toggled is currently active, it means we should
|
const panelID = panel.id === this.props.activePanelID ? null : panel.id;
|
||||||
// close everything by setting `activePanelID` to null.
|
this.props.actions.activatePanel(panelID);
|
||||||
const activePanelID = panel.id === this.props.activePanelID ?
|
|
||||||
null : panel.id;
|
|
||||||
|
|
||||||
this.props.setActivePanel(activePanelID);
|
|
||||||
// Reset the activeQueryID when toggling Exporations
|
// Reset the activeQueryID when toggling Exporations
|
||||||
this.props.setActiveQuery(null);
|
this.props.setActiveQuery(null);
|
||||||
},
|
},
|
||||||
|
|
|
@ -27,6 +27,7 @@ const DataExplorer = React.createClass({
|
||||||
upper: string,
|
upper: string,
|
||||||
lower: string,
|
lower: string,
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
|
activePanel: string,
|
||||||
setTimeRange: func.isRequired,
|
setTimeRange: func.isRequired,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -45,21 +46,16 @@ const DataExplorer = React.createClass({
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
return {
|
return {
|
||||||
activePanelID: null,
|
|
||||||
activeQueryID: null,
|
activeQueryID: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
handleSetActivePanel(id) {
|
|
||||||
this.setState({activePanelID: id});
|
|
||||||
},
|
|
||||||
|
|
||||||
handleSetActiveQuery(id) {
|
handleSetActiveQuery(id) {
|
||||||
this.setState({activeQueryID: id});
|
this.setState({activeQueryID: id});
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {timeRange, setTimeRange} = this.props;
|
const {timeRange, setTimeRange, activePanel} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="data-explorer">
|
<div className="data-explorer">
|
||||||
|
@ -70,14 +66,13 @@ const DataExplorer = React.createClass({
|
||||||
<ResizeContainer>
|
<ResizeContainer>
|
||||||
<PanelBuilder
|
<PanelBuilder
|
||||||
timeRange={timeRange}
|
timeRange={timeRange}
|
||||||
activePanelID={this.state.activePanelID}
|
activePanelID={activePanel}
|
||||||
activeQueryID={this.state.activeQueryID}
|
activeQueryID={this.state.activeQueryID}
|
||||||
setActiveQuery={this.handleSetActiveQuery}
|
setActiveQuery={this.handleSetActiveQuery}
|
||||||
setActivePanel={this.handleSetActivePanel}
|
|
||||||
/>
|
/>
|
||||||
<Visualizations
|
<Visualizations
|
||||||
timeRange={timeRange}
|
timeRange={timeRange}
|
||||||
activePanelID={this.state.activePanelID}
|
activePanelID={activePanel}
|
||||||
activeQueryID={this.state.activeQueryID}
|
activeQueryID={this.state.activeQueryID}
|
||||||
/>
|
/>
|
||||||
</ResizeContainer>
|
</ResizeContainer>
|
||||||
|
@ -87,8 +82,11 @@ const DataExplorer = React.createClass({
|
||||||
});
|
});
|
||||||
|
|
||||||
function mapStateToProps(state) {
|
function mapStateToProps(state) {
|
||||||
|
const {timeRange, dataExplorerUI} = state;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
timeRange: state.timeRange,
|
timeRange,
|
||||||
|
activePanel: dataExplorerUI.activePanel,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -1,9 +1,11 @@
|
||||||
import queryConfigs from './queryConfigs';
|
import queryConfigs from './queryConfigs';
|
||||||
import panels from './panels';
|
import panels from './panels';
|
||||||
import timeRange from './timeRange';
|
import timeRange from './timeRange';
|
||||||
|
import dataExplorerUI from './dataExplorerUI';
|
||||||
|
|
||||||
export {
|
export {
|
||||||
queryConfigs,
|
queryConfigs,
|
||||||
panels,
|
panels,
|
||||||
timeRange,
|
timeRange,
|
||||||
|
dataExplorerUI,
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,15 +3,11 @@ import update from 'react-addons-update';
|
||||||
export default function panels(state = {}, action) {
|
export default function panels(state = {}, action) {
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'CREATE_PANEL': {
|
case 'CREATE_PANEL': {
|
||||||
const {panelId, queryId} = action.payload;
|
const {panelID, queryID} = action.payload;
|
||||||
const panel = {
|
return {
|
||||||
id: panelId,
|
...state,
|
||||||
queryIds: [queryId],
|
[panelID]: {id: panelID, queryIds: [queryID]},
|
||||||
};
|
};
|
||||||
|
|
||||||
return update(state, {
|
|
||||||
[panelId]: {$set: panel},
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'RENAME_PANEL': {
|
case 'RENAME_PANEL': {
|
||||||
|
@ -50,5 +46,6 @@ export default function panels(state = {}, action) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,9 +49,9 @@ export default function queryConfigs(state = {}, action) {
|
||||||
case 'CREATE_PANEL':
|
case 'CREATE_PANEL':
|
||||||
case 'ADD_KAPACITOR_QUERY':
|
case 'ADD_KAPACITOR_QUERY':
|
||||||
case 'ADD_QUERY': {
|
case 'ADD_QUERY': {
|
||||||
const {queryId, options} = action.payload;
|
const {queryID, options} = action.payload;
|
||||||
const nextState = Object.assign({}, state, {
|
const nextState = Object.assign({}, state, {
|
||||||
[queryId]: Object.assign({}, defaultQueryConfig(queryId), options),
|
[queryID]: Object.assign({}, defaultQueryConfig(queryID), options),
|
||||||
});
|
});
|
||||||
|
|
||||||
return nextState;
|
return nextState;
|
||||||
|
|
|
@ -19,9 +19,14 @@ export const loadLocalStorage = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const saveToLocalStorage = ({panels, queryConfigs, timeRange}) => {
|
export const saveToLocalStorage = ({panels, queryConfigs, timeRange, dataExplorerUI}) => {
|
||||||
try {
|
try {
|
||||||
window.localStorage.setItem('state', JSON.stringify({panels, queryConfigs, timeRange}));
|
window.localStorage.setItem('state', JSON.stringify({
|
||||||
|
panels,
|
||||||
|
queryConfigs,
|
||||||
|
timeRange,
|
||||||
|
dataExplorerUI,
|
||||||
|
}));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('Unable to save data explorer: ', JSON.parse(err)); // eslint-disable-line no-console
|
console.error('Unable to save data explorer: ', JSON.parse(err)); // eslint-disable-line no-console
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,14 @@ import {createStore, applyMiddleware, compose} from 'redux';
|
||||||
import {combineReducers} from 'redux';
|
import {combineReducers} from 'redux';
|
||||||
import thunkMiddleware from 'redux-thunk';
|
import thunkMiddleware from 'redux-thunk';
|
||||||
import makeQueryExecuter from 'src/shared/middleware/queryExecuter';
|
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 * as sharedReducers from 'src/shared/reducers';
|
||||||
import rulesReducer from 'src/kapacitor/reducers/rules';
|
import rulesReducer from 'src/kapacitor/reducers/rules';
|
||||||
import persistStateEnhancer from './persistStateEnhancer';
|
import persistStateEnhancer from './persistStateEnhancer';
|
||||||
|
|
||||||
const rootReducer = combineReducers({
|
const rootReducer = combineReducers({
|
||||||
...sharedReducers,
|
...sharedReducers,
|
||||||
...chronografReducers,
|
...dataExplorerReducers,
|
||||||
rules: rulesReducer,
|
rules: rulesReducer,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -13,11 +13,11 @@ import {saveToLocalStorage} from '../localStorage';
|
||||||
export default function persistState() {
|
export default function persistState() {
|
||||||
return (next) => (reducer, initialState, enhancer) => {
|
return (next) => (reducer, initialState, enhancer) => {
|
||||||
const store = 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()});
|
saveToLocalStorage({...store.getState()});
|
||||||
}, debounceMs));
|
}, throttleMs));
|
||||||
|
|
||||||
return store;
|
return store;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue