Merge remote-tracking branch 'origin/de-organize' into de-organize

pull/10616/head
Alex P 2017-02-09 13:52:43 -08:00
commit d6cf66e91c
10 changed files with 109 additions and 77 deletions

View File

@ -7,28 +7,36 @@ import QueryTabItem from './QueryTabItem';
import SimpleDropdown from 'src/shared/components/SimpleDropdown';
import * as viewActions from '../actions/view';
const {
arrayOf,
func,
shape,
string,
} = PropTypes;
const QueryBuilder = React.createClass({
propTypes: {
queries: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
timeRange: PropTypes.shape({
upper: PropTypes.string,
lower: PropTypes.string,
queries: arrayOf(shape({})).isRequired,
timeRange: shape({
upper: string,
lower: string,
}).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,
actions: shape({
chooseNamespace: func.isRequired,
chooseMeasurement: func.isRequired,
chooseTag: func.isRequired,
groupByTag: func.isRequired,
addQuery: func.isRequired,
deleteQuery: func.isRequired,
toggleField: func.isRequired,
groupByTime: func.isRequired,
toggleTagAcceptance: func.isRequired,
applyFuncsToField: func.isRequired,
}).isRequired,
setActiveQuery: PropTypes.func.isRequired,
activeQueryID: PropTypes.string,
height: string,
top: string,
setActiveQuery: func.isRequired,
activeQueryID: string,
},
handleSetActiveQuery(query) {
@ -56,8 +64,9 @@ const QueryBuilder = React.createClass({
},
render() {
const {height, top} = this.props;
return (
<div className="query-builder">
<div className="query-builder" style={{height, top}}>
{this.renderQueryTabList()}
{this.renderQueryEditor()}
</div>

View File

@ -6,15 +6,23 @@ import LineGraph from 'shared/components/LineGraph';
import MultiTable from './MultiTable';
const RefreshingLineGraph = AutoRefresh(LineGraph);
const {
arrayOf,
number,
shape,
string,
} = PropTypes;
const Visualization = React.createClass({
propTypes: {
timeRange: PropTypes.shape({
upper: PropTypes.string,
lower: PropTypes.string,
timeRange: shape({
upper: string,
lower: string,
}).isRequired,
queryConfigs: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
name: PropTypes.string,
activeQueryIndex: PropTypes.number,
queryConfigs: arrayOf(shape({})).isRequired,
name: string,
activeQueryIndex: number,
height: string,
},
contextTypes: {
@ -36,7 +44,7 @@ const Visualization = React.createClass({
},
render() {
const {queryConfigs, timeRange, activeQueryIndex} = this.props;
const {queryConfigs, timeRange, activeQueryIndex, height} = this.props;
const {source} = this.context;
const proxyLink = source.links.proxy;
@ -52,7 +60,7 @@ const Visualization = React.createClass({
const isInDataExplorer = true;
return (
<div className={classNames("graph", {active: true})}>
<div className={classNames("graph", {active: true})} style={{height}}>
<div className="graph-heading">
<div className="graph-title">
{name || "Graph"}

View File

@ -3,6 +3,7 @@ import {connect} from 'react-redux';
import QueryBuilder from '../components/QueryBuilder';
import Visualization from '../components/Visualization';
import Header from '../containers/Header';
import ResizeContainer from 'src/shared/components/ResizeContainer';
import {
setTimeRange as setTimeRangeAction,
@ -64,7 +65,7 @@ const DataExplorer = React.createClass({
actions={{setTimeRange}}
timeRange={timeRange}
/>
<div className="page-contents">
<ResizeContainer>
<Visualization
timeRange={timeRange}
queryConfigs={queries}
@ -77,7 +78,7 @@ const DataExplorer = React.createClass({
setActiveQuery={this.handleSetActiveQuery}
activeQueryID={activeQueryID}
/>
</div>
</ResizeContainer>
</div>
);
},

View File

@ -9,8 +9,8 @@ const ResizeContainer = React.createClass({
getInitialState() {
return {
leftWidth: '34%',
rightWidth: '66%',
topHeight: '60%',
bottomHeight: '40%',
isDragging: false,
};
},
@ -32,40 +32,40 @@ const ResizeContainer = React.createClass({
return;
}
const appWidth = parseInt(getComputedStyle(this.refs.resizeContainer).width, 10);
// handleOffSet moves the resize handle as many pixels as the side bar is taking up.
const handleOffSet = window.innerWidth - appWidth;
const appHeight = parseInt(getComputedStyle(this.refs.resizeContainer).height, 10);
// headingOffset moves the resize handle as many pixels as the page-heading is taking up.
const headingOffset = window.innerHeight - appHeight;
const turnToPercent = 100;
const newLeftPanelPercent = Math.ceil(((e.pageX - handleOffSet) / (appWidth)) * turnToPercent);
const newRightPanelPercent = (turnToPercent - newLeftPanelPercent);
const newTopPanelPercent = Math.ceil(((e.pageY - headingOffset) / (appHeight)) * turnToPercent);
const newBottomPanelPercent = (turnToPercent - newTopPanelPercent);
// Don't trigger a resize unless the change in size is greater than minResizePercentage
const minResizePercentage = 0.5;
if (Math.abs(newLeftPanelPercent - parseFloat(this.state.leftWidth)) < minResizePercentage) {
if (Math.abs(newTopPanelPercent - parseFloat(this.state.topHeight)) < minResizePercentage) {
return;
}
// Don't trigger a resize if the new sizes are too small
const minLeftPanelWidth = 371;
const minRightPanelWidth = 389;
if (((newLeftPanelPercent / turnToPercent) * appWidth) < minLeftPanelWidth || ((newRightPanelPercent / turnToPercent) * appWidth) < minRightPanelWidth) {
const minTopPanelHeight = 300;
const minBottomPanelHeight = 250;
if (((newTopPanelPercent / turnToPercent) * appHeight) < minTopPanelHeight || ((newBottomPanelPercent / turnToPercent) * appHeight) < minBottomPanelHeight) {
return;
}
this.setState({leftWidth: `${(newLeftPanelPercent)}%`, rightWidth: `${(newRightPanelPercent)}%`});
this.setState({topHeight: `${(newTopPanelPercent)}%`, bottomHeight: `${(newBottomPanelPercent)}%`});
},
render() {
const {leftWidth, rightWidth, isDragging} = this.state;
const left = React.cloneElement(this.props.children[0], {width: leftWidth});
const right = React.cloneElement(this.props.children[1], {width: rightWidth});
const handle = <ResizeHandle isDragging={isDragging} onHandleStartDrag={this.handleStartDrag} />;
const {topHeight, bottomHeight, isDragging} = this.state;
const top = React.cloneElement(this.props.children[0], {height: topHeight});
const bottom = React.cloneElement(this.props.children[1], {height: bottomHeight, top: topHeight});
const handle = <ResizeHandle isDragging={isDragging} onHandleStartDrag={this.handleStartDrag} top={topHeight} />;
return (
<div className="resize-container page-contents" onMouseLeave={this.handleMouseLeave} onMouseUp={this.handleStopDrag} onMouseMove={this.handleDrag} ref="resizeContainer" >
{left}
{top}
{handle}
{right}
{bottom}
</div>
);
},

View File

@ -1,15 +1,24 @@
import React from 'react';
import cx from 'classnames';
const {func, bool} = React.PropTypes;
const {func, bool, string} = React.PropTypes;
const ResizeHandle = React.createClass({
propTypes: {
onHandleStartDrag: func.isRequired,
isDragging: bool.isRequired,
top: string,
},
render() {
return <div className={cx("resizer__handle", {dragging: this.props.isDragging})} ref="resizer" onMouseDown={this.props.onHandleStartDrag} />;
const {isDragging, onHandleStartDrag, top} = this.props;
return (
<div
className={cx("resizer__handle", {dragging: isDragging})}
onMouseDown={onHandleStartDrag}
style={{top}}
/>
);
},
});

View File

@ -10,12 +10,12 @@ $resizer-color-hover: $g8-storm;
$resizer-color-active: $c-pool;
.resizer__handle {
top: 0;
top: 60%;
left: 0;
width: $resizer-click-area;
margin-left: -$resizer-click-area/2;
margin-right: -$resizer-click-area/2;
height: 100%;
height: $resizer-click-area;
margin-top: -$resizer-click-area/2;
margin-bottom: -$resizer-click-area/2;
width: 100%;
z-index: 2;
user-select: none;
-webkit-user-select: none;
@ -31,7 +31,7 @@ $resizer-color-active: $c-pool;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%) rotate(90deg);
transform: translate(-50%,-50%);
width: 130px;
height: $resizer-handle-width;
line-height: $resizer-handle-width;
@ -48,18 +48,18 @@ $resizer-color-active: $c-pool;
content: '';
display: block;
position: absolute;
top: 0;
left: 50%;
transform: translateX(-50%);
height: 100%;
width: $resizer-line-width;
top: 50%;
left: 0;
transform: translateY(-50%);
width: 100%;
height: $resizer-line-width;
background-color: $resizer-color;
box-shadow: 0 0 0 transparent;
transition:
background-color 0.19s ease;
}
&:hover {
cursor: ew-resize;
cursor: ns-resize;
&:before {
background-color: $resizer-color-hover;
@ -85,4 +85,4 @@ $resizer-color-active: $c-pool;
display: flex;
flex-direction: row;
align-items: stretch;
}
}

View File

@ -25,6 +25,16 @@
}
}
$query-editor-gutter: 16px;
$query-editor-tab-inactive: $g2-kevlar;
$query-editor-tab-active: $g3-castle;
$query-editor-height: 250px;
$graph-bg-color: $g3-castle;
$graph-active-color: $g4-onyx;
$graph-radius: 4px;
$de-vertical-margin: 16px;
$dygraphs-legend-offset: 32px;
$de-graph-heading-height: 44px;
// DE Specific components
@import 'data-explorer/query-builder';

View File

@ -2,10 +2,8 @@
position: absolute;
width: calc(100% - #{($explorer-page-padding * 2)});
left: $explorer-page-padding;
height: calc(40% - 16px);
height: 40%;
top: 60%;
background-color: $g3-castle;
border-radius: $radius;
border: 0;
display: flex;
align-items: stretch;
@ -16,6 +14,8 @@
.query-builder--tabs {
display: flex;
width: 250px;
margin-top: $de-vertical-margin;
height: calc(100% - #{($de-vertical-margin * 2)});
flex-direction: column;
align-items: stretch;
@include gradient-v($g3-castle,$g1-raven);
@ -144,6 +144,8 @@
$query-builder--column-heading-height: 60px;
.query-builder--tab-contents {
width: 100%;
margin-top: $de-vertical-margin;
height: calc(100% - #{($de-vertical-margin * 2)});
background-color: $g4-onyx;
border-radius: 0 $radius $radius 0;
overflow: hidden;

View File

@ -5,10 +5,6 @@
Abbreviated as "qeditor"
*/
$query-editor-gutter: 16px;
$query-editor-tab-inactive: $g2-kevlar;
$query-editor-tab-active: $g3-castle;
$query-editor-height: 250px;
.query-builder--query-preview {
position: relative;

View File

@ -1,23 +1,19 @@
$graph-bg-color: $g3-castle;
$graph-active-color: $g4-onyx;
$graph-radius: 4px;
$de-vertical-margin: 16px;
$dygraphs-legend-offset: 32px;
.graph {
position: absolute;
width: calc(100% - #{($explorer-page-padding * 2)});
left: $explorer-page-padding;
top: $de-vertical-margin;
top: 0;
height: 60%;
}
.graph-heading {
position: relative;
top: $de-vertical-margin;
background-color: $graph-bg-color;
border-radius: $graph-radius $graph-radius 0 0;
display: flex;
align-items: center;
justify-content: space-between;
height: 44px;
height: $de-graph-heading-height;
padding: 0 16px;
transition:
background-color 0.25s ease;
@ -48,7 +44,8 @@ $dygraphs-legend-offset: 32px;
background-color 0.25s ease;
}
.data-explorer .graph-container {
height: calc(100% - 44px - 32px);
top: $de-vertical-margin;
height: calc(100% - #{$de-graph-heading-height} - #{($de-vertical-margin * 2)});
padding: 0;
& > div {