diff --git a/resources/frontend_client/app/css/query_builder.css b/resources/frontend_client/app/css/query_builder.css index 868c88fb78bb8ddffcb9d4bd41ad7b813f6ec657..95f5362819b0bc1cefd2fb978dcb2d88d61193f5 100644 --- a/resources/frontend_client/app/css/query_builder.css +++ b/resources/frontend_client/app/css/query_builder.css @@ -246,23 +246,47 @@ border: 1px solid #e0e0e0; } +/* for medium breakpoint only expand if data reference is not shown */ +@media screen and (--breakpoint-min-md) { + .GuiBuilder { + font-size: 1.0em; + } +} + +/* un-expanded (default) */ .GuiBuilder-row { border-bottom: 1px solid #e0e0e0; } - .GuiBuilder-row:last-child { - border-bottom: none; + border-bottom-color: transparent; +} +.GuiBuilder-data { + border-right: 1px solid #e0e0e0; +} +.GuiBuilder-filtered-by { + border-right: 1px solid transparent; +} +.GuiBuilder-sort-limit { + border-left: 1px solid #e0e0e0; +} + +/* expanded */ +.GuiBuilder.GuiBuilder--expand { + flex-direction: row; +} +.GuiBuilder.GuiBuilder--expand .GuiBuilder-row:last-child { + border-right-color: transparent; + border-bottom-color: #e0e0e0; +} +.GuiBuilder.GuiBuilder--expand .GuiBuilder-filtered-by { + border-right-color: #e0e0e0; } + .GuiBuilder-section { position: relative; min-height: 48px; min-width: 120px; - border-right: 1px solid #e0e0e0; -} - -.GuiBuilder-section:last-child { - border-right: none; } .GuiBuilder-section-label { @@ -274,38 +298,6 @@ padding-right: 10px; } -/* for medium breakpoint only expand if data reference is not shown */ -@media screen and (--breakpoint-min-md) { - .GuiBuilder { - font-size: 1.0em; - } - .QueryBuilder:not(.QueryBuilder--showDataReference) .GuiBuilder { - flex-direction: row; - } - .QueryBuilder:not(.QueryBuilder--showDataReference) .GuiBuilder-row:last-child { - border-right: none; - border-bottom: 1px solid #e0e0e0; - } - .QueryBuilder:not(.QueryBuilder--showDataReference) .GuiBuilder-section:last-child { - border-right: 1px solid #e0e0e0; - } -} - -/* for large breakpoint always expand */ -@media screen and (--breakpoint-min-lg) { - .GuiBuilder { - font-size: 1.1em; - flex-direction: row; - } - .GuiBuilder-row:last-child { - border-right: none; - border-bottom: 1px solid #e0e0e0; - } - .GuiBuilder-section:last-child { - border-right: 1px solid #e0e0e0; - } -} - .QueryOption { color: color(var(--base-grey) shade(20%)); font-weight: 700; diff --git a/resources/frontend_client/app/query_builder/GuiQueryEditor.react.js b/resources/frontend_client/app/query_builder/GuiQueryEditor.react.js index 69430bb3e5f8c81ac3b69b4599b72d6ec5bb72f0..6afe6fd9d60c213cf96341fcf9955b6dc96cf9e6 100644 --- a/resources/frontend_client/app/query_builder/GuiQueryEditor.react.js +++ b/resources/frontend_client/app/query_builder/GuiQueryEditor.react.js @@ -27,6 +27,12 @@ export default React.createClass({ toggleExpandCollapseFn: React.PropTypes.func.isRequired }, + getInitialState: function() { + return { + expanded: true + }; + }, + setQuery: function(dataset_query) { this.props.setQueryFn(dataset_query); }, @@ -367,6 +373,7 @@ export default React.createClass({ var isInitiallyOpen = !this.props.query.database || !this.props.query.query.source_table; return ( <DataSelector + ref="dataSection" className="arrow-right" includeTables={true} query={this.props.query} @@ -381,7 +388,7 @@ export default React.createClass({ renderFilterSection: function() { return ( - <div className="GuiBuilder-section GuiBuilder-filtered-by flex align-center"> + <div className="GuiBuilder-section GuiBuilder-filtered-by flex align-center" ref="filterSection"> <span className="GuiBuilder-section-label Query-label">Filtered by</span> {this.renderFilters()} </div> @@ -390,7 +397,7 @@ export default React.createClass({ renderViewSection: function() { return ( - <div className="GuiBuilder-section GuiBuilder-view flex-full flex align-center px1"> + <div className="GuiBuilder-section GuiBuilder-view flex align-center px1" ref="viewSection"> <span className="GuiBuilder-section-label Query-label">View</span> {this.renderAggregation()} {this.renderBreakouts()} @@ -416,7 +423,7 @@ export default React.createClass({ } return ( - <div className="GuiBuilder-section GuiBuilder-sort-limit flex align-center"> + <div className="GuiBuilder-section GuiBuilder-sort-limit flex align-center" ref="sortLimitSection"> <PopoverWithTrigger className="PopoverBody PopoverBody--withArrow" tetherOptions={tetherOptions} @@ -434,22 +441,34 @@ export default React.createClass({ ); }, + componentDidUpdate: function() { + // HACK: magic number "5" accounts for the borders between the sections? + let contentWidth = ["data", "filter", "view", "sortLimit"].reduce((acc, ref) => acc + React.findDOMNode(this.refs[`${ref}Section`]).offsetWidth, 0) + 5; + let guiBuilderWidth = React.findDOMNode(this.refs.guiBuilder).offsetWidth; + + let expanded = (contentWidth < guiBuilderWidth); + if (this.state.expanded !== expanded) { + this.setState({ expanded }); + } + }, + render: function() { var classes = cx({ 'GuiBuilder': true, - 'GuiBuilder--narrow': this.props.isShowingDataReference, + 'GuiBuilder--expand': this.state.expanded, 'rounded': true, 'shadowed': true - }) + }); return ( <div className="wrapper"> - <div className={classes}> + <div className={classes} ref="guiBuilder"> <div className="GuiBuilder-row flex"> {this.renderDataSection()} {this.renderFilterSection()} </div> <div className="GuiBuilder-row flex flex-full"> {this.renderViewSection()} + <div className="flex-full"></div> {this.renderSortLimitSection()} </div> </div>