Remove concept of Panels
parent
3a7ed1a32f
commit
51b641b2c3
|
@ -1,11 +0,0 @@
|
||||||
import reducer from 'src/data_explorer/reducers/dataExplorerUI';
|
|
||||||
import {activatePanel} from 'src/data_explorer/actions/view';
|
|
||||||
|
|
||||||
describe('DataExplorer.Reducers.UI', () => {
|
|
||||||
it('can set the active panel', () => {
|
|
||||||
const activePanel = 123;
|
|
||||||
const actual = reducer({}, activatePanel(activePanel));
|
|
||||||
|
|
||||||
expect(actual).to.deep.equal({activePanel});
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,34 +0,0 @@
|
||||||
import reducer from 'src/data_explorer/reducers/panels';
|
|
||||||
import {deletePanel} from 'src/data_explorer/actions/view';
|
|
||||||
|
|
||||||
const fakeAddPanelAction = (panelID, queryID) => {
|
|
||||||
return {
|
|
||||||
type: 'CREATE_PANEL',
|
|
||||||
payload: {panelID, queryID},
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
describe('Chronograf.Reducers.Panel', () => {
|
|
||||||
let state;
|
|
||||||
const panelID = 123;
|
|
||||||
const queryID = 456;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
state = reducer({}, fakeAddPanelAction(panelID, queryID));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can add a panel', () => {
|
|
||||||
const actual = state[panelID];
|
|
||||||
expect(actual).to.deep.equal({
|
|
||||||
id: panelID,
|
|
||||||
queryIds: [queryID],
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can delete a panel', () => {
|
|
||||||
const nextState = reducer(state, deletePanel(panelID));
|
|
||||||
|
|
||||||
const actual = nextState[panelID];
|
|
||||||
expect(actual).to.equal(undefined);
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,35 +1,6 @@
|
||||||
import uuid from 'node-uuid';
|
import uuid from 'node-uuid';
|
||||||
|
|
||||||
export function createPanel() {
|
export function addQuery(options = {}) {
|
||||||
return {
|
|
||||||
type: 'CREATE_PANEL',
|
|
||||||
payload: {
|
|
||||||
panelID: uuid.v4(), // for the default Panel
|
|
||||||
queryID: uuid.v4(), // for the default Query
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function renamePanel(panelId, name) {
|
|
||||||
return {
|
|
||||||
type: 'RENAME_PANEL',
|
|
||||||
payload: {
|
|
||||||
panelId,
|
|
||||||
name,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function deletePanel(panelId) {
|
|
||||||
return {
|
|
||||||
type: 'DELETE_PANEL',
|
|
||||||
payload: {
|
|
||||||
panelId,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function addQuery(panelId, options) {
|
|
||||||
return {
|
return {
|
||||||
type: 'ADD_QUERY',
|
type: 'ADD_QUERY',
|
||||||
payload: {
|
payload: {
|
||||||
|
@ -157,12 +128,3 @@ export function updateRawQuery(queryID, text) {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function activatePanel(panelID) {
|
|
||||||
return {
|
|
||||||
type: 'ACTIVATE_PANEL',
|
|
||||||
payload: {
|
|
||||||
panelID,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,183 +0,0 @@
|
||||||
import React, {PropTypes} from 'react';
|
|
||||||
import classNames from 'classnames';
|
|
||||||
import QueryEditor from './QueryEditor';
|
|
||||||
import QueryTabItem from './QueryTabItem';
|
|
||||||
import RenamePanelModal from './RenamePanelModal';
|
|
||||||
import SimpleDropdown from 'src/shared/components/SimpleDropdown';
|
|
||||||
|
|
||||||
const Panel = React.createClass({
|
|
||||||
propTypes: {
|
|
||||||
panel: PropTypes.shape({
|
|
||||||
id: PropTypes.string.isRequired,
|
|
||||||
}).isRequired,
|
|
||||||
queries: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
|
|
||||||
timeRange: PropTypes.shape({
|
|
||||||
upper: PropTypes.string,
|
|
||||||
lower: PropTypes.string,
|
|
||||||
}).isRequired,
|
|
||||||
isExpanded: PropTypes.bool.isRequired,
|
|
||||||
onTogglePanel: PropTypes.func.isRequired,
|
|
||||||
actions: PropTypes.shape({
|
|
||||||
chooseNamespace: PropTypes.func.isRequired,
|
|
||||||
chooseMeasurement: PropTypes.func.isRequired,
|
|
||||||
chooseTag: PropTypes.func.isRequired,
|
|
||||||
groupByTag: PropTypes.func.isRequired,
|
|
||||||
addQuery: PropTypes.func.isRequired,
|
|
||||||
deleteQuery: PropTypes.func.isRequired,
|
|
||||||
toggleField: PropTypes.func.isRequired,
|
|
||||||
groupByTime: PropTypes.func.isRequired,
|
|
||||||
toggleTagAcceptance: PropTypes.func.isRequired,
|
|
||||||
applyFuncsToField: PropTypes.func.isRequired,
|
|
||||||
deletePanel: PropTypes.func.isRequired,
|
|
||||||
renamePanel: PropTypes.func.isRequired,
|
|
||||||
}).isRequired,
|
|
||||||
setActiveQuery: PropTypes.func.isRequired,
|
|
||||||
activeQueryID: PropTypes.string,
|
|
||||||
},
|
|
||||||
|
|
||||||
handleSetActiveQuery(query) {
|
|
||||||
this.props.setActiveQuery(query.id);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleAddQuery() {
|
|
||||||
this.props.actions.addQuery();
|
|
||||||
},
|
|
||||||
|
|
||||||
handleAddRawQuery() {
|
|
||||||
this.props.actions.addQuery({rawText: `SELECT "fields" from "db"."rp"."measurement"`});
|
|
||||||
},
|
|
||||||
|
|
||||||
handleDeleteQuery(query) {
|
|
||||||
this.props.actions.deleteQuery(query.id);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleSelectPanel() {
|
|
||||||
this.props.onTogglePanel(this.props.panel);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleDeletePanel(e) {
|
|
||||||
e.stopPropagation();
|
|
||||||
this.props.actions.deletePanel(this.props.panel.id);
|
|
||||||
},
|
|
||||||
|
|
||||||
getActiveQuery() {
|
|
||||||
const {queries, activeQueryID} = this.props;
|
|
||||||
const activeQuery = queries.find((query) => query.id === activeQueryID);
|
|
||||||
const defaultQuery = queries[0];
|
|
||||||
|
|
||||||
return activeQuery || defaultQuery;
|
|
||||||
},
|
|
||||||
|
|
||||||
openRenamePanelModal(e) {
|
|
||||||
e.stopPropagation();
|
|
||||||
$(`#renamePanelModal-${this.props.panel.id}`).modal('show'); // eslint-disable-line no-undef
|
|
||||||
},
|
|
||||||
|
|
||||||
handleRename(newName) {
|
|
||||||
this.props.actions.renamePanel(this.props.panel.id, newName);
|
|
||||||
},
|
|
||||||
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {panel, isExpanded} = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={classNames('panel', {active: isExpanded})}>
|
|
||||||
<div className="panel--header" onClick={this.handleSelectPanel}>
|
|
||||||
<div className="panel--name">
|
|
||||||
<span className="icon caret-right"></span>
|
|
||||||
{panel.name || "Graph"}
|
|
||||||
</div>
|
|
||||||
<div className="panel--actions">
|
|
||||||
{/* <div title="Export Queries to Dashboard" className="panel--action"><span className="icon export"></span></div> */}
|
|
||||||
<div title="Rename Graph" className="panel--action" onClick={this.openRenamePanelModal}><span className="icon pencil"></span></div>
|
|
||||||
<div title="Delete Graph" className="panel--action" onClick={this.handleDeletePanel}><span className="icon trash"></span></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{this.renderQueryTabList()}
|
|
||||||
{this.renderQueryEditor()}
|
|
||||||
<RenamePanelModal panel={panel} onConfirm={this.handleRename} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
renderQueryEditor() {
|
|
||||||
if (!this.props.isExpanded) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const {timeRange, actions} = this.props;
|
|
||||||
const query = this.getActiveQuery();
|
|
||||||
|
|
||||||
if (!query) {
|
|
||||||
return (
|
|
||||||
<div className="qeditor--empty">
|
|
||||||
<h5>This Graph has no Queries</h5>
|
|
||||||
<br/>
|
|
||||||
<div className="btn btn-primary" role="button" onClick={this.handleAddQuery}>Add a Query</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<QueryEditor
|
|
||||||
timeRange={timeRange}
|
|
||||||
query={this.getActiveQuery()}
|
|
||||||
actions={actions}
|
|
||||||
onAddQuery={this.handleAddQuery}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
renderQueryTabList() {
|
|
||||||
const {isExpanded, queries} = this.props;
|
|
||||||
if (!isExpanded) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<div className="panel--tabs">
|
|
||||||
{queries.map((q) => {
|
|
||||||
let queryTabText;
|
|
||||||
if (q.rawText) {
|
|
||||||
queryTabText = 'InfluxQL';
|
|
||||||
} else {
|
|
||||||
queryTabText = (q.measurement && q.fields.length !== 0) ? `${q.measurement}.${q.fields[0].field}` : 'Query';
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<QueryTabItem
|
|
||||||
isActive={this.getActiveQuery().id === q.id}
|
|
||||||
key={q.id}
|
|
||||||
query={q}
|
|
||||||
onSelect={this.handleSetActiveQuery}
|
|
||||||
onDelete={this.handleDeleteQuery}
|
|
||||||
queryTabText={queryTabText}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
|
|
||||||
{this.renderAddQuery()}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
onChoose(item) {
|
|
||||||
switch (item.text) {
|
|
||||||
case 'Query Builder':
|
|
||||||
this.handleAddQuery();
|
|
||||||
break;
|
|
||||||
case 'InfluxQL':
|
|
||||||
this.handleAddRawQuery();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
renderAddQuery() {
|
|
||||||
return (
|
|
||||||
<SimpleDropdown onChoose={this.onChoose} items={[{text: 'Query Builder'}, {text: 'InfluxQL'}]} className="panel--tab-new">
|
|
||||||
<span className="icon plus"></span>
|
|
||||||
</SimpleDropdown>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default Panel;
|
|
|
@ -1,63 +0,0 @@
|
||||||
import React, {PropTypes} from 'react';
|
|
||||||
import {connect} from 'react-redux';
|
|
||||||
import {bindActionCreators} from 'redux';
|
|
||||||
import PanelList from './PanelList';
|
|
||||||
import * as viewActions from '../actions/view';
|
|
||||||
|
|
||||||
const {string, func} = PropTypes;
|
|
||||||
const PanelBuilder = React.createClass({
|
|
||||||
propTypes: {
|
|
||||||
width: string,
|
|
||||||
actions: PropTypes.shape({
|
|
||||||
activatePanel: func.isRequired,
|
|
||||||
createPanel: func.isRequired,
|
|
||||||
deleteQuery: func.isRequired,
|
|
||||||
addQuery: func.isRequired,
|
|
||||||
editRawText: func.isRequired,
|
|
||||||
chooseNamespace: func.isRequired,
|
|
||||||
chooseMeasurement: func.isRequired,
|
|
||||||
toggleField: func.isRequired,
|
|
||||||
groupByTime: func.isRequired,
|
|
||||||
applyFuncsToField: func.isRequired,
|
|
||||||
chooseTag: func.isRequired,
|
|
||||||
groupByTag: func.isRequired,
|
|
||||||
toggleTagAcceptance: func.isRequired,
|
|
||||||
deletePanel: func.isRequired,
|
|
||||||
}).isRequired,
|
|
||||||
setActiveQuery: func.isRequired,
|
|
||||||
activePanelID: string,
|
|
||||||
activeQueryID: string,
|
|
||||||
},
|
|
||||||
|
|
||||||
handleCreateExplorer() {
|
|
||||||
this.props.actions.createPanel();
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {width, actions, setActiveQuery, activePanelID, activeQueryID} = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="panel-builder" style={{width}}>
|
|
||||||
<div className="btn btn-block btn-primary" onClick={this.handleCreateExplorer}><span className="icon graphline"></span> Create Graph</div>
|
|
||||||
<PanelList
|
|
||||||
actions={actions}
|
|
||||||
setActiveQuery={setActiveQuery}
|
|
||||||
activePanelID={activePanelID}
|
|
||||||
activeQueryID={activeQueryID}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
function mapStateToProps() {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapDispatchToProps(dispatch) {
|
|
||||||
return {
|
|
||||||
actions: bindActionCreators(viewActions, dispatch),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps, mapDispatchToProps)(PanelBuilder);
|
|
|
@ -1,76 +0,0 @@
|
||||||
import React, {PropTypes} from 'react';
|
|
||||||
import {connect} from 'react-redux';
|
|
||||||
import _ from 'lodash';
|
|
||||||
|
|
||||||
import Panel from './Panel';
|
|
||||||
|
|
||||||
const {func, string, shape} = PropTypes;
|
|
||||||
const PanelList = React.createClass({
|
|
||||||
propTypes: {
|
|
||||||
timeRange: shape({
|
|
||||||
upper: string,
|
|
||||||
lower: string,
|
|
||||||
}).isRequired,
|
|
||||||
panels: shape({}).isRequired,
|
|
||||||
queryConfigs: PropTypes.shape({}),
|
|
||||||
actions: shape({
|
|
||||||
activatePanel: func.isRequired,
|
|
||||||
deleteQuery: func.isRequired,
|
|
||||||
addQuery: func.isRequired,
|
|
||||||
}).isRequired,
|
|
||||||
setActiveQuery: func.isRequired,
|
|
||||||
activePanelID: string,
|
|
||||||
activeQueryID: string,
|
|
||||||
},
|
|
||||||
|
|
||||||
handleTogglePanel(panel) {
|
|
||||||
const panelID = panel.id === this.props.activePanelID ? null : panel.id;
|
|
||||||
this.props.actions.activatePanel(panelID);
|
|
||||||
|
|
||||||
// Reset the activeQueryID when toggling Exporations
|
|
||||||
this.props.setActiveQuery(null);
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {actions, panels, timeRange, queryConfigs, setActiveQuery, activeQueryID, activePanelID} = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
{Object.keys(panels).map((panelID) => {
|
|
||||||
const panel = panels[panelID];
|
|
||||||
const queries = panel.queryIds.map((configId) => queryConfigs[configId]);
|
|
||||||
const deleteQueryFromPanel = _.partial(actions.deleteQuery, panelID);
|
|
||||||
const addQueryToPanel = _.partial(actions.addQuery, panelID);
|
|
||||||
const allActions = Object.assign({}, actions, {
|
|
||||||
addQuery: addQueryToPanel,
|
|
||||||
deleteQuery: deleteQueryFromPanel,
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Panel
|
|
||||||
key={panelID}
|
|
||||||
panel={panel}
|
|
||||||
queries={queries}
|
|
||||||
timeRange={timeRange}
|
|
||||||
onTogglePanel={this.handleTogglePanel}
|
|
||||||
setActiveQuery={setActiveQuery}
|
|
||||||
isExpanded={panelID === activePanelID}
|
|
||||||
actions={allActions}
|
|
||||||
activeQueryID={activeQueryID}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
function mapStateToProps(state) {
|
|
||||||
return {
|
|
||||||
timeRange: state.timeRange,
|
|
||||||
panels: state.panels,
|
|
||||||
queryConfigs: state.queryConfigs,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps)(PanelList);
|
|
|
@ -26,8 +26,6 @@ const QueryBuilder = React.createClass({
|
||||||
groupByTime: PropTypes.func.isRequired,
|
groupByTime: PropTypes.func.isRequired,
|
||||||
toggleTagAcceptance: PropTypes.func.isRequired,
|
toggleTagAcceptance: PropTypes.func.isRequired,
|
||||||
applyFuncsToField: PropTypes.func.isRequired,
|
applyFuncsToField: PropTypes.func.isRequired,
|
||||||
deletePanel: PropTypes.func.isRequired,
|
|
||||||
renamePanel: PropTypes.func.isRequired,
|
|
||||||
}).isRequired,
|
}).isRequired,
|
||||||
setActiveQuery: PropTypes.func.isRequired,
|
setActiveQuery: PropTypes.func.isRequired,
|
||||||
activeQueryID: PropTypes.string,
|
activeQueryID: PropTypes.string,
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
import React, {PropTypes} from 'react';
|
|
||||||
|
|
||||||
const RenamePanelModal = React.createClass({
|
|
||||||
propTypes: {
|
|
||||||
onConfirm: PropTypes.func.isRequired,
|
|
||||||
panel: PropTypes.shape({
|
|
||||||
id: PropTypes.string.isRequired,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
|
|
||||||
getInitialState() {
|
|
||||||
return {error: null};
|
|
||||||
},
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
this.refs.name.focus();
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {panel} = this.props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="modal fade in" id={`renamePanelModal-${panel.id}`} tabIndex="-1" role="dialog">
|
|
||||||
<div className="modal-dialog">
|
|
||||||
<div className="modal-content">
|
|
||||||
<div className="modal-header">
|
|
||||||
<button type="button" className="close" data-dismiss="modal" aria-label="Close">
|
|
||||||
<span aria-hidden="true">×</span>
|
|
||||||
</button>
|
|
||||||
<h4 className="modal-title">Rename Panel</h4>
|
|
||||||
</div>
|
|
||||||
<div className="modal-body">
|
|
||||||
{this.state.error ?
|
|
||||||
<div className="alert alert-danger" role="alert">{this.state.error}</div>
|
|
||||||
: null}
|
|
||||||
<div className="form-grid padding-top">
|
|
||||||
<div className="form-group col-md-8 col-md-offset-2">
|
|
||||||
<input ref="name" name="renameExplorer" type="text" placeholder={panel.name} className="form-control input-lg" id="renameExplorer" required={true} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="modal-footer">
|
|
||||||
<button className="btn btn-info" data-dismiss="modal">Cancel</button>
|
|
||||||
<button onClick={this.handleConfirm} className="btn btn-success">Rename</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleConfirm() {
|
|
||||||
const name = this.refs.name.value;
|
|
||||||
|
|
||||||
if (name === '') {
|
|
||||||
this.setState({error: "Name can't be blank"});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$(`#renamePanelModal-${this.props.panel.id}`).modal('hide'); // eslint-disable-line no-undef
|
|
||||||
this.refs.name.value = '';
|
|
||||||
this.setState({error: null});
|
|
||||||
this.props.onConfirm(name);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default RenamePanelModal;
|
|
|
@ -52,7 +52,7 @@ const Visualization = React.createClass({
|
||||||
const isInDataExplorer = true;
|
const isInDataExplorer = true;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={(p) => this.panel = p} className={classNames("graph", {active: true})}>
|
<div className={classNames("graph", {active: true})}>
|
||||||
<div className="graph-heading">
|
<div className="graph-heading">
|
||||||
<div className="graph-title">
|
<div className="graph-title">
|
||||||
{name || "Graph"}
|
{name || "Graph"}
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
import React, {PropTypes} from 'react';
|
|
||||||
import {connect} from 'react-redux';
|
|
||||||
import Visualization from './Visualization';
|
|
||||||
|
|
||||||
const {shape, string} = PropTypes;
|
|
||||||
|
|
||||||
const Visualizations = React.createClass({
|
|
||||||
propTypes: {
|
|
||||||
timeRange: shape({
|
|
||||||
upper: string,
|
|
||||||
lower: string,
|
|
||||||
}).isRequired,
|
|
||||||
panels: shape({}).isRequired,
|
|
||||||
queryConfigs: shape({}).isRequired,
|
|
||||||
width: string,
|
|
||||||
activePanelID: string,
|
|
||||||
activeQueryID: string,
|
|
||||||
},
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {panels, queryConfigs, timeRange, width, activePanelID} = this.props;
|
|
||||||
|
|
||||||
const visualizations = Object.keys(panels).map((panelID) => {
|
|
||||||
const panel = panels[panelID];
|
|
||||||
const queries = panel.queryIds.map((id) => queryConfigs[id]);
|
|
||||||
const isActive = panelID === activePanelID;
|
|
||||||
|
|
||||||
return <Visualization activeQueryIndex={this.getActiveQueryIndex(panelID)} name={panel.name} key={panelID} queryConfigs={queries} timeRange={timeRange} isActive={isActive} />;
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="panels" style={{width}}>
|
|
||||||
{visualizations}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
getActiveQueryIndex(panelID) {
|
|
||||||
const {activeQueryID, activePanelID, panels} = this.props;
|
|
||||||
const isPanelActive = panelID === activePanelID;
|
|
||||||
|
|
||||||
if (!isPanelActive) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (activeQueryID === null) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return panels[panelID].queryIds.indexOf(activeQueryID);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
function mapStateToProps(state) {
|
|
||||||
return {
|
|
||||||
panels: state.panels,
|
|
||||||
queryConfigs: state.queryConfigs,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default connect(mapStateToProps)(Visualizations);
|
|
|
@ -84,12 +84,11 @@ const DataExplorer = React.createClass({
|
||||||
});
|
});
|
||||||
|
|
||||||
function mapStateToProps(state) {
|
function mapStateToProps(state) {
|
||||||
const {timeRange, queryConfigs, dataExplorerUI} = state;
|
const {timeRange, queryConfigs} = state;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
timeRange,
|
timeRange,
|
||||||
queryConfigs,
|
queryConfigs,
|
||||||
activePanel: dataExplorerUI.activePanel,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
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,11 +1,7 @@
|
||||||
import queryConfigs from './queryConfigs';
|
import queryConfigs from './queryConfigs';
|
||||||
import panels from './panels';
|
|
||||||
import timeRange from './timeRange';
|
import timeRange from './timeRange';
|
||||||
import dataExplorerUI from './dataExplorerUI';
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
queryConfigs,
|
queryConfigs,
|
||||||
panels,
|
|
||||||
timeRange,
|
timeRange,
|
||||||
dataExplorerUI,
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,33 +0,0 @@
|
||||||
import update from 'react-addons-update';
|
|
||||||
|
|
||||||
export default function panels(state = {}, action) {
|
|
||||||
switch (action.type) {
|
|
||||||
case 'CREATE_PANEL': {
|
|
||||||
const {panelID, queryID} = action.payload;
|
|
||||||
return {
|
|
||||||
...state,
|
|
||||||
[panelID]: {id: panelID, queryIds: [queryID]},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'RENAME_PANEL': {
|
|
||||||
const {panelId, name} = action.payload;
|
|
||||||
return update(state, {
|
|
||||||
[panelId]: {
|
|
||||||
name: {$set: name},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'DELETE_PANEL': {
|
|
||||||
const {panelId} = action.payload;
|
|
||||||
return update(state, {$apply: (p) => {
|
|
||||||
const panelsCopy = Object.assign({}, p);
|
|
||||||
delete panelsCopy[panelId];
|
|
||||||
return panelsCopy;
|
|
||||||
}});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return state;
|
|
||||||
}
|
|
|
@ -46,7 +46,6 @@ export default function queryConfigs(state = {}, action) {
|
||||||
return nextState;
|
return nextState;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
|
|
@ -19,13 +19,11 @@ export const loadLocalStorage = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const saveToLocalStorage = ({panels, queryConfigs, timeRange, dataExplorerUI}) => {
|
export const saveToLocalStorage = ({queryConfigs, timeRange}) => {
|
||||||
try {
|
try {
|
||||||
window.localStorage.setItem('state', JSON.stringify({
|
window.localStorage.setItem('state', JSON.stringify({
|
||||||
panels,
|
|
||||||
queryConfigs,
|
queryConfigs,
|
||||||
timeRange,
|
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
|
||||||
|
|
|
@ -29,7 +29,6 @@
|
||||||
// DE Specific components
|
// DE Specific components
|
||||||
@import 'data-explorer/query-builder';
|
@import 'data-explorer/query-builder';
|
||||||
@import 'data-explorer/page-header';
|
@import 'data-explorer/page-header';
|
||||||
@import 'data-explorer/panel-builder';
|
|
||||||
@import 'data-explorer/query-editor';
|
@import 'data-explorer/query-editor';
|
||||||
@import 'data-explorer/raw-text';
|
@import 'data-explorer/raw-text';
|
||||||
@import 'data-explorer/tag-list';
|
@import 'data-explorer/tag-list';
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
.panel-builder {
|
|
||||||
width: 399px;
|
|
||||||
overflow-x: hidden;
|
|
||||||
background: $g1-raven;
|
|
||||||
padding: $explorer-page-padding;
|
|
||||||
@include gradient-v($g2-kevlar,$g0-obsidian);
|
|
||||||
|
|
||||||
&::-webkit-scrollbar {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
> .btn {
|
|
||||||
margin-bottom: 6px;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue