From b1b1948ee0859f91443a5b95a8238f2f790e1ea4 Mon Sep 17 00:00:00 2001 From: deniz kusefoglu Date: Thu, 18 Jan 2018 17:51:55 -0800 Subject: [PATCH 01/36] WIP persistent legend with onClick setVisibility --- ui/src/shared/components/Dygraph.js | 2 + ui/src/shared/components/LineGraph.js | 2 +- ui/src/shared/components/PersistentLegend.js | 42 ++++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 ui/src/shared/components/PersistentLegend.js diff --git a/ui/src/shared/components/Dygraph.js b/ui/src/shared/components/Dygraph.js index f776987a64..18937b82ef 100644 --- a/ui/src/shared/components/Dygraph.js +++ b/ui/src/shared/components/Dygraph.js @@ -6,6 +6,7 @@ import NanoDate from 'nano-date' import Dygraphs from 'src/external/dygraph' import DygraphLegend from 'src/shared/components/DygraphLegend' +import PersistentLegend from 'src/shared/components/PersistentLegend' import Annotations from 'src/shared/components/Annotations' import getRange, {getStackedRange} from 'shared/parsing/getRangeForDygraph' @@ -315,6 +316,7 @@ export default class Dygraph extends Component { className="dygraph-child-container" style={{...this.props.containerStyle, zIndex: '2'}} /> + ) } diff --git a/ui/src/shared/components/LineGraph.js b/ui/src/shared/components/LineGraph.js index a64feff7a4..1c1c33b19d 100644 --- a/ui/src/shared/components/LineGraph.js +++ b/ui/src/shared/components/LineGraph.js @@ -86,7 +86,7 @@ class LineGraph extends Component { const containerStyle = { width: 'calc(100% - 32px)', - height: 'calc(100% - 16px)', + height: 'calc(100% - 46px)', position: 'absolute', top: '8px', } diff --git a/ui/src/shared/components/PersistentLegend.js b/ui/src/shared/components/PersistentLegend.js new file mode 100644 index 0000000000..fbae383a0e --- /dev/null +++ b/ui/src/shared/components/PersistentLegend.js @@ -0,0 +1,42 @@ +import React, {PropTypes, Component} from 'react' +import _ from 'lodash' +import uuid from 'node-uuid' + +const style = { + position: 'absolute', + width: 'calc(100% - 32px)', + bottom: '8px', + left: '16px', + height: '30px', +} + +class PersistentLegend extends Component { + constructor(props) { + super(props) + } + handleClick = i => () => { + const visibilities = this.props.dygraph.visibility() + this.props.dygraph.setVisibility(i, !visibilities[i]) + } + + render() { + const labels = this.props.dygraph + ? _.drop(this.props.dygraph.getLabels()) + : [] + return ( +
+ {_.map(labels, (v, i) => +
+ {v} +
+ )} +
+ ) + } +} + +const {func} = PropTypes + +PersistentLegend.propTypes = {dygraph: shape({})} + +export default PersistentLegend From 9a0053c2b0d69a67a459548ccb822604a4fc4f9a Mon Sep 17 00:00:00 2001 From: deniz kusefoglu Date: Fri, 26 Jan 2018 12:41:20 -0800 Subject: [PATCH 02/36] Add missing proptype --- ui/src/shared/components/PersistentLegend.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/shared/components/PersistentLegend.js b/ui/src/shared/components/PersistentLegend.js index fbae383a0e..2a6f28917c 100644 --- a/ui/src/shared/components/PersistentLegend.js +++ b/ui/src/shared/components/PersistentLegend.js @@ -35,7 +35,7 @@ class PersistentLegend extends Component { } } -const {func} = PropTypes +const {func, shape} = PropTypes PersistentLegend.propTypes = {dygraph: shape({})} From 52acdc8c2dd9437e3404358e7eaad2248b3268fd Mon Sep 17 00:00:00 2001 From: Alex P Date: Fri, 26 Jan 2018 12:43:26 -0800 Subject: [PATCH 03/36] Can't escape the funk --- ui/src/shared/components/PersistentLegend.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/shared/components/PersistentLegend.js b/ui/src/shared/components/PersistentLegend.js index 2a6f28917c..cd6aca6788 100644 --- a/ui/src/shared/components/PersistentLegend.js +++ b/ui/src/shared/components/PersistentLegend.js @@ -35,7 +35,7 @@ class PersistentLegend extends Component { } } -const {func, shape} = PropTypes +const {shape} = PropTypes PersistentLegend.propTypes = {dygraph: shape({})} From 7ebc29566a629f121415b01ebfe9eba2172397bc Mon Sep 17 00:00:00 2001 From: Alex P Date: Fri, 26 Jan 2018 13:02:50 -0800 Subject: [PATCH 04/36] Introduce stylesheet and styles for persistent legend WIP --- ui/src/shared/components/PersistentLegend.js | 12 ++++++---- ui/src/style/chronograf.scss | 1 + .../style/components/persistent-legend.scss | 22 +++++++++++++++++++ 3 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 ui/src/style/components/persistent-legend.scss diff --git a/ui/src/shared/components/PersistentLegend.js b/ui/src/shared/components/PersistentLegend.js index cd6aca6788..39324dfb7e 100644 --- a/ui/src/shared/components/PersistentLegend.js +++ b/ui/src/shared/components/PersistentLegend.js @@ -20,13 +20,17 @@ class PersistentLegend extends Component { } render() { - const labels = this.props.dygraph - ? _.drop(this.props.dygraph.getLabels()) - : [] + const {dygraph} = this.props + const labels = dygraph ? _.drop(dygraph.getLabels()) : [] + return (
{_.map(labels, (v, i) => -
+
{v}
)} diff --git a/ui/src/style/chronograf.scss b/ui/src/style/chronograf.scss index 72483285e5..6b56e71b58 100644 --- a/ui/src/style/chronograf.scss +++ b/ui/src/style/chronograf.scss @@ -47,6 +47,7 @@ @import 'components/page-header-dropdown'; @import 'components/page-header-editable'; @import 'components/page-spinner'; +@import 'components/persistent-legend'; @import 'components/query-maker'; @import 'components/react-tooltips'; @import 'components/redacted-input'; diff --git a/ui/src/style/components/persistent-legend.scss b/ui/src/style/components/persistent-legend.scss new file mode 100644 index 0000000000..3f51c2a2bc --- /dev/null +++ b/ui/src/style/components/persistent-legend.scss @@ -0,0 +1,22 @@ +/* + Persistent Legend + ------------------------------------------------------------------------------ + Seen in a dashboard cell, below the graph + NOTE: Styles for the parent are stored in Javascript, in PersistentLegend.js +*/ + +.persistent-legend { + display: flex; + align-items: center; +} + +.persistent-legend--item { + height: 28px; + line-height: 28px; + background-color: $g3-castle; + border-radius: 3px; + transition: + background-color 0.25s ease, + color 0.25s ease; + color: $g11-sidewalk; +} From a0b50352d2b7f342f327eefdb28b41f0c067db31 Mon Sep 17 00:00:00 2001 From: deniz kusefoglu Date: Thu, 18 Jan 2018 17:51:55 -0800 Subject: [PATCH 05/36] WIP persistent legend with onClick setVisibility --- ui/src/shared/components/Dygraph.js | 2 + ui/src/shared/components/LineGraph.js | 2 +- ui/src/shared/components/PersistentLegend.js | 42 ++++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 ui/src/shared/components/PersistentLegend.js diff --git a/ui/src/shared/components/Dygraph.js b/ui/src/shared/components/Dygraph.js index f776987a64..18937b82ef 100644 --- a/ui/src/shared/components/Dygraph.js +++ b/ui/src/shared/components/Dygraph.js @@ -6,6 +6,7 @@ import NanoDate from 'nano-date' import Dygraphs from 'src/external/dygraph' import DygraphLegend from 'src/shared/components/DygraphLegend' +import PersistentLegend from 'src/shared/components/PersistentLegend' import Annotations from 'src/shared/components/Annotations' import getRange, {getStackedRange} from 'shared/parsing/getRangeForDygraph' @@ -315,6 +316,7 @@ export default class Dygraph extends Component { className="dygraph-child-container" style={{...this.props.containerStyle, zIndex: '2'}} /> +
) } diff --git a/ui/src/shared/components/LineGraph.js b/ui/src/shared/components/LineGraph.js index a64feff7a4..1c1c33b19d 100644 --- a/ui/src/shared/components/LineGraph.js +++ b/ui/src/shared/components/LineGraph.js @@ -86,7 +86,7 @@ class LineGraph extends Component { const containerStyle = { width: 'calc(100% - 32px)', - height: 'calc(100% - 16px)', + height: 'calc(100% - 46px)', position: 'absolute', top: '8px', } diff --git a/ui/src/shared/components/PersistentLegend.js b/ui/src/shared/components/PersistentLegend.js new file mode 100644 index 0000000000..fbae383a0e --- /dev/null +++ b/ui/src/shared/components/PersistentLegend.js @@ -0,0 +1,42 @@ +import React, {PropTypes, Component} from 'react' +import _ from 'lodash' +import uuid from 'node-uuid' + +const style = { + position: 'absolute', + width: 'calc(100% - 32px)', + bottom: '8px', + left: '16px', + height: '30px', +} + +class PersistentLegend extends Component { + constructor(props) { + super(props) + } + handleClick = i => () => { + const visibilities = this.props.dygraph.visibility() + this.props.dygraph.setVisibility(i, !visibilities[i]) + } + + render() { + const labels = this.props.dygraph + ? _.drop(this.props.dygraph.getLabels()) + : [] + return ( +
+ {_.map(labels, (v, i) => +
+ {v} +
+ )} +
+ ) + } +} + +const {func} = PropTypes + +PersistentLegend.propTypes = {dygraph: shape({})} + +export default PersistentLegend From 4f1a1ea57e2dcd0e8cf648fb58b42e191f411837 Mon Sep 17 00:00:00 2001 From: deniz kusefoglu Date: Fri, 26 Jan 2018 12:41:20 -0800 Subject: [PATCH 06/36] Add missing proptype --- ui/src/shared/components/PersistentLegend.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/shared/components/PersistentLegend.js b/ui/src/shared/components/PersistentLegend.js index fbae383a0e..2a6f28917c 100644 --- a/ui/src/shared/components/PersistentLegend.js +++ b/ui/src/shared/components/PersistentLegend.js @@ -35,7 +35,7 @@ class PersistentLegend extends Component { } } -const {func} = PropTypes +const {func, shape} = PropTypes PersistentLegend.propTypes = {dygraph: shape({})} From 152e49a7b2cfc686a06fa0a4e836d58811f888a9 Mon Sep 17 00:00:00 2001 From: Alex P Date: Fri, 26 Jan 2018 12:43:26 -0800 Subject: [PATCH 07/36] Can't escape the funk --- ui/src/shared/components/PersistentLegend.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/shared/components/PersistentLegend.js b/ui/src/shared/components/PersistentLegend.js index 2a6f28917c..cd6aca6788 100644 --- a/ui/src/shared/components/PersistentLegend.js +++ b/ui/src/shared/components/PersistentLegend.js @@ -35,7 +35,7 @@ class PersistentLegend extends Component { } } -const {func, shape} = PropTypes +const {shape} = PropTypes PersistentLegend.propTypes = {dygraph: shape({})} From 4e24376a31a90f51df3449ad0b3e85e97ef95134 Mon Sep 17 00:00:00 2001 From: Alex P Date: Fri, 26 Jan 2018 13:02:50 -0800 Subject: [PATCH 08/36] Introduce stylesheet and styles for persistent legend WIP --- ui/src/shared/components/PersistentLegend.js | 12 ++++++---- ui/src/style/chronograf.scss | 1 + .../style/components/persistent-legend.scss | 22 +++++++++++++++++++ 3 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 ui/src/style/components/persistent-legend.scss diff --git a/ui/src/shared/components/PersistentLegend.js b/ui/src/shared/components/PersistentLegend.js index cd6aca6788..39324dfb7e 100644 --- a/ui/src/shared/components/PersistentLegend.js +++ b/ui/src/shared/components/PersistentLegend.js @@ -20,13 +20,17 @@ class PersistentLegend extends Component { } render() { - const labels = this.props.dygraph - ? _.drop(this.props.dygraph.getLabels()) - : [] + const {dygraph} = this.props + const labels = dygraph ? _.drop(dygraph.getLabels()) : [] + return (
{_.map(labels, (v, i) => -
+
{v}
)} diff --git a/ui/src/style/chronograf.scss b/ui/src/style/chronograf.scss index 72483285e5..6b56e71b58 100644 --- a/ui/src/style/chronograf.scss +++ b/ui/src/style/chronograf.scss @@ -47,6 +47,7 @@ @import 'components/page-header-dropdown'; @import 'components/page-header-editable'; @import 'components/page-spinner'; +@import 'components/persistent-legend'; @import 'components/query-maker'; @import 'components/react-tooltips'; @import 'components/redacted-input'; diff --git a/ui/src/style/components/persistent-legend.scss b/ui/src/style/components/persistent-legend.scss new file mode 100644 index 0000000000..3f51c2a2bc --- /dev/null +++ b/ui/src/style/components/persistent-legend.scss @@ -0,0 +1,22 @@ +/* + Persistent Legend + ------------------------------------------------------------------------------ + Seen in a dashboard cell, below the graph + NOTE: Styles for the parent are stored in Javascript, in PersistentLegend.js +*/ + +.persistent-legend { + display: flex; + align-items: center; +} + +.persistent-legend--item { + height: 28px; + line-height: 28px; + background-color: $g3-castle; + border-radius: 3px; + transition: + background-color 0.25s ease, + color 0.25s ease; + color: $g11-sidewalk; +} From 13c83f8985c57e3662ff1e3350bb251141212f67 Mon Sep 17 00:00:00 2001 From: Alex P Date: Fri, 26 Jan 2018 14:41:23 -0800 Subject: [PATCH 09/36] WIP polish appearance of toggleable persistent legends --- ui/src/shared/components/PersistentLegend.js | 21 +++++++++++-- .../style/components/persistent-legend.scss | 30 +++++++++++++++---- 2 files changed, 44 insertions(+), 7 deletions(-) diff --git a/ui/src/shared/components/PersistentLegend.js b/ui/src/shared/components/PersistentLegend.js index 39324dfb7e..5b9313a0c4 100644 --- a/ui/src/shared/components/PersistentLegend.js +++ b/ui/src/shared/components/PersistentLegend.js @@ -10,24 +10,41 @@ const style = { height: '30px', } +const persistentLegendItemClassname = (visibilities, i) => { + if (visibilities.length) { + return `persistent-legend--item${visibilities[i] ? '' : ' disabled'}` + } + + return 'persistent-legend--item' +} + class PersistentLegend extends Component { constructor(props) { super(props) + + this.state = { + visibilities: [], + } } + handleClick = i => () => { const visibilities = this.props.dygraph.visibility() - this.props.dygraph.setVisibility(i, !visibilities[i]) + visibilities[i] = !visibilities[i] + + this.props.dygraph.setVisibility(visibilities) + this.setState({visibilities}) } render() { const {dygraph} = this.props + const {visibilities} = this.state const labels = dygraph ? _.drop(dygraph.getLabels()) : [] return (
{_.map(labels, (v, i) =>
diff --git a/ui/src/style/components/persistent-legend.scss b/ui/src/style/components/persistent-legend.scss index 3f51c2a2bc..060a6880a0 100644 --- a/ui/src/style/components/persistent-legend.scss +++ b/ui/src/style/components/persistent-legend.scss @@ -7,16 +7,36 @@ .persistent-legend { display: flex; - align-items: center; + align-items: flex-end; } .persistent-legend--item { - height: 28px; - line-height: 28px; - background-color: $g3-castle; + height: 22px; + line-height: 22px; + background-color: $g4-onyx; border-radius: 3px; transition: background-color 0.25s ease, color 0.25s ease; - color: $g11-sidewalk; + color: $g13-mist; + font-size: 12px; + font-weight: 600; + padding: 0 7px; + margin-right: 2px; + + &:hover { + cursor: pointer; + color: $g20-white; + background-color: $g6-smoke; + } + &.disabled { + background-color: $g1-raven; + color: $g9-mountain; + font-style: italic; + + &:hover { + background-color: $g2-kevlar; + color: $g13-mist; + } + } } From 886735230531d3def543b36a85b55306a1bea288 Mon Sep 17 00:00:00 2001 From: Alex P Date: Fri, 26 Jan 2018 14:41:45 -0800 Subject: [PATCH 10/36] Remove measurement from persistent legend labels to conserve space --- ui/src/shared/components/PersistentLegend.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ui/src/shared/components/PersistentLegend.js b/ui/src/shared/components/PersistentLegend.js index 5b9313a0c4..18e0b11063 100644 --- a/ui/src/shared/components/PersistentLegend.js +++ b/ui/src/shared/components/PersistentLegend.js @@ -10,6 +10,11 @@ const style = { height: '30px', } +const removeMeasurement = (label = '') => { + const [measurement] = label.match(/^(.*)[.]/g) || [''] + return label.replace(measurement, '') +} + const persistentLegendItemClassname = (visibilities, i) => { if (visibilities.length) { return `persistent-legend--item${visibilities[i] ? '' : ' disabled'}` @@ -48,7 +53,7 @@ class PersistentLegend extends Component { key={uuid.v4()} onClick={this.handleClick(i)} > - {v} + {removeMeasurement(v)}
)}
@@ -58,6 +63,6 @@ class PersistentLegend extends Component { const {shape} = PropTypes -PersistentLegend.propTypes = {dygraph: shape({})} +PersistentLegend.propTypes = {sharedLegend: shape({}), dygraph: shape({})} export default PersistentLegend From 99d11bd4c7a63886b06c5d5ac4ed96909deb18ed Mon Sep 17 00:00:00 2001 From: Alex P Date: Fri, 26 Jan 2018 15:17:08 -0800 Subject: [PATCH 11/36] Render dots next to each persistent legend item --- ui/src/shared/components/PersistentLegend.js | 10 +++++- .../style/components/persistent-legend.scss | 34 ++++++++++++++++--- 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/ui/src/shared/components/PersistentLegend.js b/ui/src/shared/components/PersistentLegend.js index 18e0b11063..76b78e9db3 100644 --- a/ui/src/shared/components/PersistentLegend.js +++ b/ui/src/shared/components/PersistentLegend.js @@ -20,6 +20,7 @@ const persistentLegendItemClassname = (visibilities, i) => { return `persistent-legend--item${visibilities[i] ? '' : ' disabled'}` } + // all series are visible to match expected initial state return 'persistent-legend--item' } @@ -45,6 +46,7 @@ class PersistentLegend extends Component { const {visibilities} = this.state const labels = dygraph ? _.drop(dygraph.getLabels()) : [] + /* Add style={{color: seriesColor}} to
& below */ return (
{_.map(labels, (v, i) => @@ -53,7 +55,13 @@ class PersistentLegend extends Component { key={uuid.v4()} onClick={this.handleClick(i)} > - {removeMeasurement(v)} +
+ + {removeMeasurement(v)} +
)}
diff --git a/ui/src/style/components/persistent-legend.scss b/ui/src/style/components/persistent-legend.scss index 060a6880a0..49cfc7dce8 100644 --- a/ui/src/style/components/persistent-legend.scss +++ b/ui/src/style/components/persistent-legend.scss @@ -9,7 +9,15 @@ display: flex; align-items: flex-end; } - +.persistent-legend--dot { + display: inline-block; + vertical-align: middle; + margin-right: 4px; + width: 8px; + height: 8px; + border-radius: 50%; + background-color: $g20-white; +} .persistent-legend--item { height: 22px; line-height: 22px; @@ -18,25 +26,41 @@ transition: background-color 0.25s ease, color 0.25s ease; - color: $g13-mist; + color: $g20-white; font-size: 12px; font-weight: 600; padding: 0 7px; margin-right: 2px; + span, + .persistent-legend--dot { + opacity: 0.8; + transition: opacity 0.25s ease; + } + &:hover { cursor: pointer; - color: $g20-white; background-color: $g6-smoke; + + span, + .persistent-legend--dot {opacity: 1;} } &.disabled { background-color: $g1-raven; - color: $g9-mountain; font-style: italic; + span, + .persistent-legend--dot { + opacity: 0.35; + } + &:hover { background-color: $g2-kevlar; - color: $g13-mist; + + span, + .persistent-legend--dot { + opacity: 0.65; + } } } } From 8e82c78fa36baad44ab4e48376f298e1542b9043 Mon Sep 17 00:00:00 2001 From: deniz kusefoglu Date: Mon, 29 Jan 2018 11:35:24 -0800 Subject: [PATCH 12/36] Add series colors to persistent legend --- ui/src/shared/components/PersistentLegend.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/ui/src/shared/components/PersistentLegend.js b/ui/src/shared/components/PersistentLegend.js index 76b78e9db3..93f6d6ddd7 100644 --- a/ui/src/shared/components/PersistentLegend.js +++ b/ui/src/shared/components/PersistentLegend.js @@ -44,7 +44,13 @@ class PersistentLegend extends Component { render() { const {dygraph} = this.props const {visibilities} = this.state + const labels = dygraph ? _.drop(dygraph.getLabels()) : [] + const colors = dygraph + ? _.map(labels, l => { + return dygraph.attributes_.series_[l].options.color + }) + : [] /* Add style={{color: seriesColor}} to
& below */ return ( @@ -57,9 +63,9 @@ class PersistentLegend extends Component { >
- + {removeMeasurement(v)}
From 92c49235682a53908848145089a6d317d060a0e6 Mon Sep 17 00:00:00 2001 From: deniz kusefoglu Date: Mon, 29 Jan 2018 14:40:48 -0800 Subject: [PATCH 13/36] Add shift and meta key onclick behavior to persistent legend --- ui/src/shared/components/PersistentLegend.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/ui/src/shared/components/PersistentLegend.js b/ui/src/shared/components/PersistentLegend.js index 93f6d6ddd7..b0c2b7e2b4 100644 --- a/ui/src/shared/components/PersistentLegend.js +++ b/ui/src/shared/components/PersistentLegend.js @@ -33,12 +33,17 @@ class PersistentLegend extends Component { } } - handleClick = i => () => { + handleClick = i => e => { const visibilities = this.props.dygraph.visibility() - visibilities[i] = !visibilities[i] + const selected = + this.state.selected || _.fill(Array(visibilities.length), false) - this.props.dygraph.setVisibility(visibilities) - this.setState({visibilities}) + if (e.shiftKey || e.metaKey) { + visibilities[i] = !visibilities[i] + this.props.dygraph.setVisibility(visibilities) + this.setState({visibilities}) + return + } } render() { From 630f5051e72134625646e679bde21e37fb35c67e Mon Sep 17 00:00:00 2001 From: deniz kusefoglu Date: Mon, 29 Jan 2018 15:02:16 -0800 Subject: [PATCH 14/36] Add regular click behavior to persistent legend --- ui/src/shared/components/PersistentLegend.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/ui/src/shared/components/PersistentLegend.js b/ui/src/shared/components/PersistentLegend.js index b0c2b7e2b4..520d02c723 100644 --- a/ui/src/shared/components/PersistentLegend.js +++ b/ui/src/shared/components/PersistentLegend.js @@ -35,8 +35,6 @@ class PersistentLegend extends Component { handleClick = i => e => { const visibilities = this.props.dygraph.visibility() - const selected = - this.state.selected || _.fill(Array(visibilities.length), false) if (e.shiftKey || e.metaKey) { visibilities[i] = !visibilities[i] @@ -44,6 +42,14 @@ class PersistentLegend extends Component { this.setState({visibilities}) return } + + const newVisibilities = visibilities[i] + ? _.map(visibilities, v => !v) + : _.map(visibilities, v => false) + newVisibilities[i] = true + + this.props.dygraph.setVisibility(newVisibilities) + this.setState({visibilities: newVisibilities}) } render() { @@ -57,7 +63,6 @@ class PersistentLegend extends Component { }) : [] - /* Add style={{color: seriesColor}} to
& below */ return (
{_.map(labels, (v, i) => From 8c5b5e16d5fe15586e97582a97b1bb356e657dfd Mon Sep 17 00:00:00 2001 From: deniz kusefoglu Date: Mon, 29 Jan 2018 15:12:17 -0800 Subject: [PATCH 15/36] Fix linter error --- ui/src/shared/components/PersistentLegend.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/shared/components/PersistentLegend.js b/ui/src/shared/components/PersistentLegend.js index 520d02c723..d3006a387c 100644 --- a/ui/src/shared/components/PersistentLegend.js +++ b/ui/src/shared/components/PersistentLegend.js @@ -45,7 +45,7 @@ class PersistentLegend extends Component { const newVisibilities = visibilities[i] ? _.map(visibilities, v => !v) - : _.map(visibilities, v => false) + : _.map(visibilities, () => false) newVisibilities[i] = true this.props.dygraph.setVisibility(newVisibilities) From 929c84ce2563816413d20b38a95b0b03a58a0a07 Mon Sep 17 00:00:00 2001 From: deniz kusefoglu Date: Mon, 29 Jan 2018 16:35:00 -0800 Subject: [PATCH 16/36] Add ability to Toggle the visibility of the static legend. --- ui/src/shared/components/Dygraph.js | 4 +++- ui/src/shared/components/Layout.js | 11 +++++++++++ ui/src/shared/components/LayoutCell.js | 10 +++++++++- ui/src/shared/components/LayoutCellMenu.js | 6 ++++++ ui/src/shared/components/LineGraph.js | 3 +++ ui/src/shared/components/RefreshingGraph.js | 5 ++++- 6 files changed, 36 insertions(+), 3 deletions(-) diff --git a/ui/src/shared/components/Dygraph.js b/ui/src/shared/components/Dygraph.js index 18937b82ef..73034fc2de 100644 --- a/ui/src/shared/components/Dygraph.js +++ b/ui/src/shared/components/Dygraph.js @@ -297,6 +297,7 @@ export default class Dygraph extends Component { render() { const {isHidden} = this.state + const {showStaticLegend} = this.props return (
@@ -316,7 +317,7 @@ export default class Dygraph extends Component { className="dygraph-child-container" style={{...this.props.containerStyle, zIndex: '2'}} /> - + {showStaticLegend ? : null}
) } @@ -362,6 +363,7 @@ Dygraph.propTypes = { containerStyle: shape({}), isGraphFilled: bool, isBarGraph: bool, + showStaticLegend: bool, overrideLineColors: array, dygraphSeries: shape({}).isRequired, ruleValues: shape({ diff --git a/ui/src/shared/components/Layout.js b/ui/src/shared/components/Layout.js index 0306013e24..0428818637 100644 --- a/ui/src/shared/components/Layout.js +++ b/ui/src/shared/components/Layout.js @@ -18,18 +18,25 @@ const getSource = (cell, source, sources, defaultSource) => { class LayoutState extends Component { state = { celldata: [], + showStaticLegend: false, } grabDataForDownload = celldata => { this.setState({celldata}) } + toggleShowStaticLegend = () => { + const showStaticLegend = !this.state.showStaticLegend + this.setState({showStaticLegend}) + } + render() { return ( ) } @@ -53,8 +60,10 @@ const Layout = ( onDeleteCell, synchronizer, resizeCoords, + showStaticLegend, onCancelEditCell, onStopAddAnnotation, + toggleShowStaticLegend, onSummonOverlayTechnologies, grabDataForDownload, }, @@ -67,6 +76,7 @@ const Layout = ( onEditCell={onEditCell} onDeleteCell={onDeleteCell} onCancelEditCell={onCancelEditCell} + toggleShowStaticLegend={toggleShowStaticLegend} onSummonOverlayTechnologies={onSummonOverlayTechnologies} > {cell.isWidget @@ -83,6 +93,7 @@ const Layout = ( autoRefresh={autoRefresh} synchronizer={synchronizer} manualRefresh={manualRefresh} + showStaticLegend={showStaticLegend} onStopAddAnnotation={onStopAddAnnotation} grabDataForDownload={grabDataForDownload} resizeCoords={resizeCoords} diff --git a/ui/src/shared/components/LayoutCell.js b/ui/src/shared/components/LayoutCell.js index f87780c87b..b4b524ec38 100644 --- a/ui/src/shared/components/LayoutCell.js +++ b/ui/src/shared/components/LayoutCell.js @@ -30,7 +30,13 @@ class LayoutCell extends Component { } render() { - const {cell, children, isEditable, celldata} = this.props + const { + cell, + children, + isEditable, + celldata, + toggleShowStaticLegend, + } = this.props const queries = _.get(cell, ['queries'], []) @@ -45,6 +51,7 @@ class LayoutCell extends Component { onDelete={this.handleDeleteCell} onEdit={this.handleSummonOverlay} onCSVDownload={this.handleCSVDownload} + toggleShowStaticLegend={toggleShowStaticLegend} /> @@ -82,6 +89,7 @@ LayoutCell.propTypes = { onSummonOverlayTechnologies: func, isEditable: bool, onCancelEditCell: func, + toggleShowStaticLegend: func, celldata: arrayOf(shape()), } diff --git a/ui/src/shared/components/LayoutCellMenu.js b/ui/src/shared/components/LayoutCellMenu.js index 4ab8dc328e..0f4ee001aa 100644 --- a/ui/src/shared/components/LayoutCellMenu.js +++ b/ui/src/shared/components/LayoutCellMenu.js @@ -35,6 +35,7 @@ class LayoutCellMenu extends Component { isEditable, dataExists, onCSVDownload, + toggleShowStaticLegend, onStartAddingAnnotation, onStartEditingAnnotation, onDismissEditingAnnotation, @@ -66,6 +67,10 @@ class LayoutCellMenu extends Component { text: 'Edit Annotations', action: onStartEditingAnnotation, }, + { + text: 'Show Legend', + action: toggleShowStaticLegend, + }, ]} informParent={this.handleToggleSubMenu} /> @@ -110,6 +115,7 @@ LayoutCellMenu.propTypes = { dataExists: bool, onCSVDownload: func, queries: arrayOf(shape()), + toggleShowStaticLegend: func.isRequired, onStartAddingAnnotation: func.isRequired, onStartEditingAnnotation: func.isRequired, onDismissEditingAnnotation: func.isRequired, diff --git a/ui/src/shared/components/LineGraph.js b/ui/src/shared/components/LineGraph.js index 1c1c33b19d..44d3d98747 100644 --- a/ui/src/shared/components/LineGraph.js +++ b/ui/src/shared/components/LineGraph.js @@ -53,6 +53,7 @@ class LineGraph extends Component { isGraphFilled, showSingleStat, displayOptions, + showStaticLegend, underlayCallback, overrideLineColors, isFetchingInitially, @@ -111,6 +112,7 @@ class LineGraph extends Component { setResolution={setResolution} overrideLineColors={lineColors} containerStyle={containerStyle} + showStaticLegend={showStaticLegend} isGraphFilled={showSingleStat ? false : isGraphFilled} /> {showSingleStat @@ -158,6 +160,7 @@ LineGraph.propTypes = { underlayCallback: func, isGraphFilled: bool, isBarGraph: bool, + showStaticLegend: bool, overrideLineColors: array, showSingleStat: bool, displayOptions: shape({ diff --git a/ui/src/shared/components/RefreshingGraph.js b/ui/src/shared/components/RefreshingGraph.js index 05b7917de3..464631d757 100644 --- a/ui/src/shared/components/RefreshingGraph.js +++ b/ui/src/shared/components/RefreshingGraph.js @@ -22,6 +22,7 @@ const RefreshingGraph = ({ cellHeight, autoRefresh, resizerTopHeight, + showStaticLegend, manualRefresh, // when changed, re-mounts the component synchronizer, resizeCoords, @@ -85,6 +86,7 @@ const RefreshingGraph = ({ isBarGraph={type === 'bar'} synchronizer={synchronizer} resizeCoords={resizeCoords} + showStaticLegend={showStaticLegend} displayOptions={displayOptions} editQueryStatus={editQueryStatus} grabDataForDownload={grabDataForDownload} @@ -93,7 +95,7 @@ const RefreshingGraph = ({ ) } -const {arrayOf, func, number, shape, string} = PropTypes +const {arrayOf, func, number, shape, string, bool} = PropTypes RefreshingGraph.propTypes = { timeRange: shape({ @@ -109,6 +111,7 @@ RefreshingGraph.propTypes = { axes: shape(), queries: arrayOf(shape()).isRequired, editQueryStatus: func, + showStaticLegend: bool, onZoom: func, resizeCoords: shape(), grabDataForDownload: func, From ca945cf6275dd74086d26c5e6942f82f60c61234 Mon Sep 17 00:00:00 2001 From: deniz kusefoglu Date: Mon, 29 Jan 2018 17:44:46 -0800 Subject: [PATCH 17/36] Rename Persistent Legend to Static Legend --- ui/src/shared/components/Dygraph.js | 4 ++-- .../{PersistentLegend.js => StaticLegend.js} | 18 +++++++------- ui/src/style/chronograf.scss | 2 +- ...sistent-legend.scss => static-legend.scss} | 24 +++++++++---------- 4 files changed, 24 insertions(+), 24 deletions(-) rename ui/src/shared/components/{PersistentLegend.js => StaticLegend.js} (78%) rename ui/src/style/components/{persistent-legend.scss => static-legend.scss} (70%) diff --git a/ui/src/shared/components/Dygraph.js b/ui/src/shared/components/Dygraph.js index 73034fc2de..a68061c783 100644 --- a/ui/src/shared/components/Dygraph.js +++ b/ui/src/shared/components/Dygraph.js @@ -6,7 +6,7 @@ import NanoDate from 'nano-date' import Dygraphs from 'src/external/dygraph' import DygraphLegend from 'src/shared/components/DygraphLegend' -import PersistentLegend from 'src/shared/components/PersistentLegend' +import StaticLegend from 'src/shared/components/StaticLegend' import Annotations from 'src/shared/components/Annotations' import getRange, {getStackedRange} from 'shared/parsing/getRangeForDygraph' @@ -317,7 +317,7 @@ export default class Dygraph extends Component { className="dygraph-child-container" style={{...this.props.containerStyle, zIndex: '2'}} /> - {showStaticLegend ? : null} + {showStaticLegend ? : null}
) } diff --git a/ui/src/shared/components/PersistentLegend.js b/ui/src/shared/components/StaticLegend.js similarity index 78% rename from ui/src/shared/components/PersistentLegend.js rename to ui/src/shared/components/StaticLegend.js index d3006a387c..8c15d62341 100644 --- a/ui/src/shared/components/PersistentLegend.js +++ b/ui/src/shared/components/StaticLegend.js @@ -15,16 +15,16 @@ const removeMeasurement = (label = '') => { return label.replace(measurement, '') } -const persistentLegendItemClassname = (visibilities, i) => { +const staticLegendItemClassname = (visibilities, i) => { if (visibilities.length) { - return `persistent-legend--item${visibilities[i] ? '' : ' disabled'}` + return `static-legend--item${visibilities[i] ? '' : ' disabled'}` } // all series are visible to match expected initial state - return 'persistent-legend--item' + return 'static-legend--item' } -class PersistentLegend extends Component { +class StaticLegend extends Component { constructor(props) { super(props) @@ -64,15 +64,15 @@ class PersistentLegend extends Component { : [] return ( -
+
{_.map(labels, (v, i) =>
@@ -87,6 +87,6 @@ class PersistentLegend extends Component { const {shape} = PropTypes -PersistentLegend.propTypes = {sharedLegend: shape({}), dygraph: shape({})} +StaticLegend.propTypes = {sharedLegend: shape({}), dygraph: shape({})} -export default PersistentLegend +export default StaticLegend diff --git a/ui/src/style/chronograf.scss b/ui/src/style/chronograf.scss index 6b56e71b58..605bc86223 100644 --- a/ui/src/style/chronograf.scss +++ b/ui/src/style/chronograf.scss @@ -47,7 +47,7 @@ @import 'components/page-header-dropdown'; @import 'components/page-header-editable'; @import 'components/page-spinner'; -@import 'components/persistent-legend'; +@import 'components/static-legend'; @import 'components/query-maker'; @import 'components/react-tooltips'; @import 'components/redacted-input'; diff --git a/ui/src/style/components/persistent-legend.scss b/ui/src/style/components/static-legend.scss similarity index 70% rename from ui/src/style/components/persistent-legend.scss rename to ui/src/style/components/static-legend.scss index 49cfc7dce8..ca7f59d400 100644 --- a/ui/src/style/components/persistent-legend.scss +++ b/ui/src/style/components/static-legend.scss @@ -1,15 +1,15 @@ /* - Persistent Legend + static Legend ------------------------------------------------------------------------------ Seen in a dashboard cell, below the graph - NOTE: Styles for the parent are stored in Javascript, in PersistentLegend.js + NOTE: Styles for the parent are stored in Javascript, in staticLegend.js */ -.persistent-legend { +.static-legend { display: flex; align-items: flex-end; } -.persistent-legend--dot { +.static-legend--dot { display: inline-block; vertical-align: middle; margin-right: 4px; @@ -18,14 +18,12 @@ border-radius: 50%; background-color: $g20-white; } -.persistent-legend--item { +.static-legend--item { height: 22px; line-height: 22px; background-color: $g4-onyx; border-radius: 3px; - transition: - background-color 0.25s ease, - color 0.25s ease; + transition: background-color 0.25s ease, color 0.25s ease; color: $g20-white; font-size: 12px; font-weight: 600; @@ -33,7 +31,7 @@ margin-right: 2px; span, - .persistent-legend--dot { + .static-legend--dot { opacity: 0.8; transition: opacity 0.25s ease; } @@ -43,14 +41,16 @@ background-color: $g6-smoke; span, - .persistent-legend--dot {opacity: 1;} + .static-legend--dot { + opacity: 1; + } } &.disabled { background-color: $g1-raven; font-style: italic; span, - .persistent-legend--dot { + .static-legend--dot { opacity: 0.35; } @@ -58,7 +58,7 @@ background-color: $g2-kevlar; span, - .persistent-legend--dot { + .static-legend--dot { opacity: 0.65; } } From 2f4b1fdfbef4c388fbc4265ffd65764f9005a636 Mon Sep 17 00:00:00 2001 From: Alex P Date: Tue, 30 Jan 2018 14:31:12 -0800 Subject: [PATCH 18/36] Prevent static legend items from text wrapping --- ui/src/style/components/static-legend.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/src/style/components/static-legend.scss b/ui/src/style/components/static-legend.scss index ca7f59d400..636921e5eb 100644 --- a/ui/src/style/components/static-legend.scss +++ b/ui/src/style/components/static-legend.scss @@ -21,6 +21,7 @@ .static-legend--item { height: 22px; line-height: 22px; + white-space: nowrap; background-color: $g4-onyx; border-radius: 3px; transition: background-color 0.25s ease, color 0.25s ease; From 81be8ddfcbac2f3de9d21f0624c95c84915947b2 Mon Sep 17 00:00:00 2001 From: Alex P Date: Tue, 30 Jan 2018 15:49:56 -0800 Subject: [PATCH 19/36] Allow static legend to grow as necessary Also resizing the annotations and dygraph containers to fit --- ui/src/shared/annotations/styles.js | 48 +++++++++++++++----- ui/src/shared/components/Annotation.js | 13 ++++-- ui/src/shared/components/AnnotationWindow.js | 7 +-- ui/src/shared/components/Annotations.js | 13 +++++- ui/src/shared/components/Dygraph.js | 34 ++++++++++++-- ui/src/shared/components/LineGraph.js | 2 +- ui/src/shared/components/NewAnnotation.js | 12 +++-- ui/src/shared/components/StaticLegend.js | 27 +++++++++-- ui/src/style/components/static-legend.scss | 3 +- 9 files changed, 126 insertions(+), 33 deletions(-) diff --git a/ui/src/shared/annotations/styles.js b/ui/src/shared/annotations/styles.js index 256697976e..82a952ed44 100644 --- a/ui/src/shared/annotations/styles.js +++ b/ui/src/shared/annotations/styles.js @@ -154,7 +154,13 @@ export const tooltipFormStyle = { export const tooltipInputButton = {marginLeft: '2px'} export const tooltipInput = {flex: '1 0 0'} -export const annotationStyle = ({time}, dygraph, isMouseOver, isDragging) => { +export const annotationStyle = ( + {time}, + dygraph, + isMouseOver, + isDragging, + staticLegendHeight +) => { // TODO: export and test this function const [startX, endX] = dygraph.xAxisRange() let visibility = 'visible' @@ -167,6 +173,10 @@ export const annotationStyle = ({time}, dygraph, isMouseOver, isDragging) => { const left = `${dygraph.toDomXCoord(time) + containerLeftPadding}px` const width = 2 + const height = staticLegendHeight + ? `calc(100% - ${staticLegendHeight + 36}px)` + : 'calc(100% - 36px)' + return { left, position: 'absolute', @@ -174,7 +184,7 @@ export const annotationStyle = ({time}, dygraph, isMouseOver, isDragging) => { backgroundColor: `rgb(${isDragging ? annotationDragColor : annotationColor})`, - height: 'calc(100% - 36px)', + height, width: `${width}px`, transition: 'background-color 0.25s ease', transform: `translateX(-${width / 2}px)`, // translate should always be half with width to horizontally center the annotation pole @@ -184,7 +194,11 @@ export const annotationStyle = ({time}, dygraph, isMouseOver, isDragging) => { } } -export const annotationWindowStyle = (annotation, dygraph) => { +export const annotationWindowStyle = ( + annotation, + dygraph, + staticLegendHeight +) => { // TODO: export and test this function const [startX, endX] = dygraph.xAxisRange() const containerLeftPadding = 16 @@ -216,12 +230,16 @@ export const annotationWindowStyle = (annotation, dygraph) => { const gradientStartColor = `rgba(${annotationColor},0.15)` const gradientEndColor = `rgba(${annotationColor},0)` + const height = staticLegendHeight + ? `calc(100% - ${staticLegendHeight + 36}px)` + : 'calc(100% - 36px)' + return { left, position: 'absolute', top: '8px', background: `linear-gradient(to bottom, ${gradientStartColor} 0%,${gradientEndColor} 100%)`, - height: 'calc(100% - 36px)', + height, borderTop: `2px dotted rgba(${annotationColor},0.35)`, width, zIndex: zIndexWindow, @@ -230,14 +248,20 @@ export const annotationWindowStyle = (annotation, dygraph) => { } // Styles for new Annotations -export const newAnnotationContainer = { - position: 'absolute', - zIndex: '9999', - top: '8px', - left: '16px', - width: 'calc(100% - 32px)', - height: 'calc(100% - 16px)', - cursor: 'pointer', +export const newAnnotationContainer = staticLegendHeight => { + const style = { + position: 'absolute', + zIndex: '9999', + top: '8px', + left: '16px', + width: 'calc(100% - 32px)', + height: 'calc(100% - 16px)', + cursor: 'pointer', + } + + return staticLegendHeight + ? {...style, height: `calc(100% - ${16 + staticLegendHeight}px)`} + : style } export const newAnnotationCrosshairStyle = left => { const width = 2 diff --git a/ui/src/shared/components/Annotation.js b/ui/src/shared/components/Annotation.js index f65f538da6..321a107839 100644 --- a/ui/src/shared/components/Annotation.js +++ b/ui/src/shared/components/Annotation.js @@ -139,7 +139,7 @@ class Annotation extends Component { } render() { - const {dygraph, annotation, mode} = this.props + const {dygraph, annotation, mode, staticLegendHeight} = this.props const {isDragging, isMouseOver} = this.state const humanTime = `${new Date(+annotation.time)}` @@ -154,7 +154,13 @@ class Annotation extends Component { return (
@@ -187,7 +193,7 @@ class Annotation extends Component { } } -const {arrayOf, func, shape, string} = PropTypes +const {arrayOf, func, number, shape, string} = PropTypes Annotation.propTypes = { mode: string, @@ -200,6 +206,7 @@ Annotation.propTypes = { dygraph: shape({}).isRequired, onUpdateAnnotation: func.isRequired, onDeleteAnnotation: func.isRequired, + staticLegendHeight: number, } export default Annotation diff --git a/ui/src/shared/components/AnnotationWindow.js b/ui/src/shared/components/AnnotationWindow.js index 073034d1f3..c7ab670f37 100644 --- a/ui/src/shared/components/AnnotationWindow.js +++ b/ui/src/shared/components/AnnotationWindow.js @@ -2,13 +2,13 @@ import React, {PropTypes} from 'react' import {annotationWindowStyle} from 'src/shared/annotations/styles' -const AnnotationWindow = ({annotation, dygraph}) => +const AnnotationWindow = ({annotation, dygraph, staticLegendHeight}) =>
-const {shape, string} = PropTypes +const {number, shape, string} = PropTypes AnnotationWindow.propTypes = { annotation: shape({ @@ -16,6 +16,7 @@ AnnotationWindow.propTypes = { duration: string.isRequired, }).isRequired, dygraph: shape({}).isRequired, + staticLegendHeight: number, } export default AnnotationWindow diff --git a/ui/src/shared/components/Annotations.js b/ui/src/shared/components/Annotations.js index 7f5d6d1fd0..91aad7ccc5 100644 --- a/ui/src/shared/components/Annotations.js +++ b/ui/src/shared/components/Annotations.js @@ -40,6 +40,7 @@ class Annotations extends Component { handleAddingAnnotationSuccess, handleMouseEnterTempAnnotation, handleMouseLeaveTempAnnotation, + staticLegendHeight, } = this.props if (!dygraph) { @@ -65,6 +66,7 @@ class Annotations extends Component { isTempHovering={isTempHovering} onMouseEnterTempAnnotation={handleMouseEnterTempAnnotation} onMouseLeaveTempAnnotation={handleMouseLeaveTempAnnotation} + staticLegendHeight={staticLegendHeight} />} {annotations.map(a => )} {annotations.map((a, i) => { return a.duration - ? + ? : null })}
@@ -87,7 +95,7 @@ class Annotations extends Component { } } -const {arrayOf, bool, func, shape, string} = PropTypes +const {arrayOf, bool, func, number, shape, string} = PropTypes Annotations.propTypes = { annotations: arrayOf(shape({})), @@ -101,6 +109,7 @@ Annotations.propTypes = { handleAddingAnnotationSuccess: func.isRequired, handleMouseEnterTempAnnotation: func.isRequired, handleMouseLeaveTempAnnotation: func.isRequired, + staticLegendHeight: number, } const mapStateToProps = ({ diff --git a/ui/src/shared/components/Dygraph.js b/ui/src/shared/components/Dygraph.js index a68061c783..df08d9a779 100644 --- a/ui/src/shared/components/Dygraph.js +++ b/ui/src/shared/components/Dygraph.js @@ -31,6 +31,7 @@ export default class Dygraph extends Component { this.state = { isSynced: false, isHidden: true, + staticLegendHeight: null, } } @@ -295,13 +296,31 @@ export default class Dygraph extends Component { handleAnnotationsRef = ref => (this.annotationsRef = ref) + handleReceiveStaticLegendHeight = staticLegendHeight => { + this.setState({staticLegendHeight}) + } + render() { - const {isHidden} = this.state + const {isHidden, staticLegendHeight} = this.state const {showStaticLegend} = this.props + let dygraphStyle = {...this.props.containerStyle, zIndex: '2'} + if (showStaticLegend) { + const cellVerticalPadding = 16 + + dygraphStyle = { + ...this.props.containerStyle, + zIndex: '2', + height: `calc(100% - ${staticLegendHeight + cellVerticalPadding}px)`, + } + } + return (
- + {this.dygraph && - {showStaticLegend ? : null} + {showStaticLegend + ? + : null}
) } diff --git a/ui/src/shared/components/LineGraph.js b/ui/src/shared/components/LineGraph.js index 44d3d98747..d05d04003c 100644 --- a/ui/src/shared/components/LineGraph.js +++ b/ui/src/shared/components/LineGraph.js @@ -87,7 +87,7 @@ class LineGraph extends Component { const containerStyle = { width: 'calc(100% - 32px)', - height: 'calc(100% - 46px)', + height: 'calc(100% - 16px)', position: 'absolute', top: '8px', } diff --git a/ui/src/shared/components/NewAnnotation.js b/ui/src/shared/components/NewAnnotation.js index 28c1b221c7..c6a55c521d 100644 --- a/ui/src/shared/components/NewAnnotation.js +++ b/ui/src/shared/components/NewAnnotation.js @@ -107,7 +107,12 @@ class NewAnnotation extends Component { } render() { - const {dygraph, isTempHovering, tempAnnotation: {time}} = this.props + const { + dygraph, + isTempHovering, + tempAnnotation: {time}, + staticLegendHeight, + } = this.props const {isMouseOver, mouseAction} = this.state const timestamp = `${new Date(+time)}` @@ -126,7 +131,7 @@ class NewAnnotation extends Component { onMouseLeave={this.handleMouseLeave} onMouseUp={this.handleMouseUp} onMouseDown={this.handleMouseDown} - style={newAnnotationContainer} + style={newAnnotationContainer(staticLegendHeight)} > {isDragging &&
{ @@ -33,6 +33,15 @@ class StaticLegend extends Component { } } + componentDidUpdate = () => { + const {height} = this.staticLegendRef.getBoundingClientRect() + this.props.handleReceiveStaticLegendHeight(height) + } + + componentWillUnmount = () => { + this.props.handleReceiveStaticLegendHeight(null) + } + handleClick = i => e => { const visibilities = this.props.dygraph.visibility() @@ -64,7 +73,13 @@ class StaticLegend extends Component { : [] return ( -
+
{ + this.staticLegendRef = s + }} + > {_.map(labels, (v, i) =>
Date: Tue, 30 Jan 2018 16:00:36 -0800 Subject: [PATCH 20/36] Mention keyboard/mouse interactions in helper component Good UX brahhhh --- ui/src/shared/components/GraphTips.js | 2 +- ui/src/style/components/react-tooltips.scss | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/src/shared/components/GraphTips.js b/ui/src/shared/components/GraphTips.js index 6d5adf19c6..9701895594 100644 --- a/ui/src/shared/components/GraphTips.js +++ b/ui/src/shared/components/GraphTips.js @@ -4,7 +4,7 @@ import ReactTooltip from 'react-tooltip' const GraphTips = React.createClass({ render() { const graphTipsText = - '

Graph Tips:

Click + Drag Zoom in (X or Y)
Shift + Click Pan Graph Window
Double Click Reset Graph Window

' + '

Graph Tips:

Click + Drag Zoom in (X or Y)
Shift + Click Pan Graph Window
Double Click Reset Graph Window

Static Legend Tips:

ClickFocus on single Series
Shift + Click Show/Hide single Series

' return (
Date: Thu, 1 Feb 2018 10:21:04 -0800 Subject: [PATCH 21/36] Set a maximum height for the static legend with overflow --- ui/src/style/components/static-legend.scss | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ui/src/style/components/static-legend.scss b/ui/src/style/components/static-legend.scss index 809ff3f752..44ec9a1af0 100644 --- a/ui/src/style/components/static-legend.scss +++ b/ui/src/style/components/static-legend.scss @@ -9,6 +9,9 @@ display: flex; align-items: flex-end; flex-wrap: wrap; + max-height: 50%; + overflow: auto; + @include custom-scrollbar($g3-castle,$g6-smoke); } .static-legend--dot { display: inline-block; From 51f04fdfce08c5e654b5d582b8c57d0eecf91463 Mon Sep 17 00:00:00 2001 From: Alex P Date: Thu, 1 Feb 2018 11:25:08 -0800 Subject: [PATCH 22/36] Improve appearance of display options on smaller screens --- ui/src/dashboards/components/Tabber.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/dashboards/components/Tabber.js b/ui/src/dashboards/components/Tabber.js index 99bfb88bd5..9fc95f1ac0 100644 --- a/ui/src/dashboards/components/Tabber.js +++ b/ui/src/dashboards/components/Tabber.js @@ -2,7 +2,7 @@ import React, {PropTypes} from 'react' import QuestionMarkTooltip from 'src/shared/components/QuestionMarkTooltip' export const Tabber = ({labelText, children, tipID, tipContent}) => -
+
) } -const {arrayOf, func, shape, string} = PropTypes +const {arrayOf, bool, func, shape, string} = PropTypes AxesOptions.defaultProps = { axes: { @@ -144,6 +158,8 @@ AxesOptions.propTypes = { defaultYLabel: string, }), }).isRequired, + onToggleStaticLegend: func.isRequired, + showStaticLegend: bool, } export default AxesOptions diff --git a/ui/src/dashboards/components/CellEditorOverlay.js b/ui/src/dashboards/components/CellEditorOverlay.js index c3bdb55a1c..08f5d08b19 100644 --- a/ui/src/dashboards/components/CellEditorOverlay.js +++ b/ui/src/dashboards/components/CellEditorOverlay.js @@ -60,6 +60,7 @@ class CellEditorOverlay extends Component { axes, colorSingleStatText: colorsTypeContainsText, colors: validateColors(colors, type, colorsTypeContainsText), + showStaticLegend: false, } } @@ -370,6 +371,10 @@ class CellEditorOverlay extends Component { }) } + handleToggleStaticLegend = newState => () => { + this.setState({showStaticLegend: newState}) + } + handleSetQuerySource = source => { const queriesWorkingDraft = this.state.queriesWorkingDraft.map(q => ({ ..._.cloneDeep(q), @@ -460,6 +465,7 @@ class CellEditorOverlay extends Component { isDisplayOptionsTabActive, queriesWorkingDraft, colorSingleStatText, + showStaticLegend, } = this.state const queryActions = { @@ -491,6 +497,7 @@ class CellEditorOverlay extends Component { queryConfigs={queriesWorkingDraft} editQueryStatus={editQueryStatus} onCellRename={this.handleCellRename} + showStaticLegend={showStaticLegend} /> ) } @@ -141,6 +145,8 @@ DisplayOptions.propTypes = { queryConfigs: arrayOf(shape()).isRequired, colorSingleStatText: bool.isRequired, onToggleSingleStatText: func.isRequired, + onToggleStaticLegend: func.isRequired, + showStaticLegend: bool, } export default DisplayOptions diff --git a/ui/src/dashboards/components/Visualization.js b/ui/src/dashboards/components/Visualization.js index 2d6764d708..ec1b57a814 100644 --- a/ui/src/dashboards/components/Visualization.js +++ b/ui/src/dashboards/components/Visualization.js @@ -16,6 +16,7 @@ const DashVisualization = ( queryConfigs, editQueryStatus, resizerTopHeight, + showStaticLegend, }, {source: {links: {proxy}}} ) => @@ -31,11 +32,12 @@ const DashVisualization = ( autoRefresh={autoRefresh} editQueryStatus={editQueryStatus} resizerTopHeight={resizerTopHeight} + showStaticLegend={showStaticLegend} />
-const {arrayOf, func, number, shape, string} = PropTypes +const {arrayOf, bool, func, number, shape, string} = PropTypes DashVisualization.defaultProps = { name: '', @@ -69,6 +71,7 @@ DashVisualization.propTypes = { value: string.isRequired, }).isRequired ), + showStaticLegend: bool, } DashVisualization.contextTypes = { From 5ea8aa4cdd5ae5eb08f93556869d88280e805e20 Mon Sep 17 00:00:00 2001 From: Alex P Date: Thu, 1 Feb 2018 13:11:17 -0800 Subject: [PATCH 24/36] WIP Prepare for incoming legend key on cell @goller is going to add a legend key to cell with a specific shape --- ui/src/dashboards/components/AxesOptions.js | 11 +++++----- .../components/CellEditorOverlay.js | 21 +++++++++++++------ .../dashboards/components/DisplayOptions.js | 6 +++--- ui/src/dashboards/components/Visualization.js | 8 +++---- ui/src/dashboards/constants/index.js | 3 +++ ui/src/shared/components/Dygraph.js | 12 +++++++---- ui/src/shared/components/LineGraph.js | 6 +++--- ui/src/shared/components/RefreshingGraph.js | 8 +++---- 8 files changed, 46 insertions(+), 29 deletions(-) diff --git a/ui/src/dashboards/components/AxesOptions.js b/ui/src/dashboards/components/AxesOptions.js index 6fc10d197d..0bfde61eb6 100644 --- a/ui/src/dashboards/components/AxesOptions.js +++ b/ui/src/dashboards/components/AxesOptions.js @@ -7,6 +7,7 @@ import FancyScrollbar from 'shared/components/FancyScrollbar' import {DISPLAY_OPTIONS, TOOLTIP_CONTENT} from 'src/dashboards/constants' import {GRAPH_TYPES} from 'src/dashboards/graphics/graph' +import {STATIC_LEGEND_SHOW, STATIC_LEGEND_HIDE} from 'src/dashboards/constants' const {LINEAR, LOG, BASE_2, BASE_10} = DISPLAY_OPTIONS const getInputMin = scale => (scale === LOG ? '0' : null) @@ -20,7 +21,7 @@ const AxesOptions = ({ onSetYAxisBoundMin, onSetYAxisBoundMax, selectedGraphType, - showStaticLegend, + staticLegend, onToggleStaticLegend, }) => { const [min, max] = bounds @@ -113,12 +114,12 @@ const AxesOptions = ({ @@ -128,7 +129,7 @@ const AxesOptions = ({ ) } -const {arrayOf, bool, func, shape, string} = PropTypes +const {arrayOf, func, shape, string} = PropTypes AxesOptions.defaultProps = { axes: { @@ -159,7 +160,7 @@ AxesOptions.propTypes = { }), }).isRequired, onToggleStaticLegend: func.isRequired, - showStaticLegend: bool, + staticLegend: shape({}).isRequired, } export default AxesOptions diff --git a/ui/src/dashboards/components/CellEditorOverlay.js b/ui/src/dashboards/components/CellEditorOverlay.js index 08f5d08b19..9c87295e40 100644 --- a/ui/src/dashboards/components/CellEditorOverlay.js +++ b/ui/src/dashboards/components/CellEditorOverlay.js @@ -18,6 +18,8 @@ import {getQueryConfig} from 'shared/apis' import { removeUnselectedTemplateValues, TYPE_QUERY_CONFIG, + STATIC_LEGEND_SHOW, + STATIC_LEGEND_HIDE, } from 'src/dashboards/constants' import {OVERLAY_TECHNOLOGY} from 'shared/constants/classNames' import {MINIMUM_HEIGHTS, INITIAL_HEIGHTS} from 'src/data_explorer/constants' @@ -33,11 +35,15 @@ import { validateColors, } from 'src/dashboards/constants/gaugeColors' +const FAKE_LEGEND_OPTS = { + type: null, + orient: 'bottom', +} class CellEditorOverlay extends Component { constructor(props) { super(props) - const {cell: {name, type, queries, axes, colors}, sources} = props + const {cell: {name, type, queries, axes, colors, legend}, sources} = props let source = _.get(queries, ['0', 'source'], null) source = sources.find(s => s.links.self === source) || props.source @@ -60,7 +66,7 @@ class CellEditorOverlay extends Component { axes, colorSingleStatText: colorsTypeContainsText, colors: validateColors(colors, type, colorsTypeContainsText), - showStaticLegend: false, + staticLegend: legend || FAKE_LEGEND_OPTS, } } @@ -372,7 +378,10 @@ class CellEditorOverlay extends Component { } handleToggleStaticLegend = newState => () => { - this.setState({showStaticLegend: newState}) + const type = newState ? STATIC_LEGEND_SHOW : STATIC_LEGEND_HIDE + const staticLegend = {...this.state.staticLegend, type} + + this.setState({staticLegend}) } handleSetQuerySource = source => { @@ -465,7 +474,7 @@ class CellEditorOverlay extends Component { isDisplayOptionsTabActive, queriesWorkingDraft, colorSingleStatText, - showStaticLegend, + staticLegend, } = this.state const queryActions = { @@ -497,7 +506,7 @@ class CellEditorOverlay extends Component { queryConfigs={queriesWorkingDraft} editQueryStatus={editQueryStatus} onCellRename={this.handleCellRename} - showStaticLegend={showStaticLegend} + staticLegend={staticLegend} /> ) } @@ -146,7 +146,7 @@ DisplayOptions.propTypes = { colorSingleStatText: bool.isRequired, onToggleSingleStatText: func.isRequired, onToggleStaticLegend: func.isRequired, - showStaticLegend: bool, + staticLegend: shape({}).isRequired, } export default DisplayOptions diff --git a/ui/src/dashboards/components/Visualization.js b/ui/src/dashboards/components/Visualization.js index ec1b57a814..4f54f14f25 100644 --- a/ui/src/dashboards/components/Visualization.js +++ b/ui/src/dashboards/components/Visualization.js @@ -16,7 +16,7 @@ const DashVisualization = ( queryConfigs, editQueryStatus, resizerTopHeight, - showStaticLegend, + staticLegend, }, {source: {links: {proxy}}} ) => @@ -32,12 +32,12 @@ const DashVisualization = ( autoRefresh={autoRefresh} editQueryStatus={editQueryStatus} resizerTopHeight={resizerTopHeight} - showStaticLegend={showStaticLegend} + staticLegend={staticLegend} />
-const {arrayOf, bool, func, number, shape, string} = PropTypes +const {arrayOf, func, number, shape, string} = PropTypes DashVisualization.defaultProps = { name: '', @@ -71,7 +71,7 @@ DashVisualization.propTypes = { value: string.isRequired, }).isRequired ), - showStaticLegend: bool, + staticLegend: shape({}).isRequired, } DashVisualization.contextTypes = { diff --git a/ui/src/dashboards/constants/index.js b/ui/src/dashboards/constants/index.js index 25d5293c96..a9e7cdcf33 100644 --- a/ui/src/dashboards/constants/index.js +++ b/ui/src/dashboards/constants/index.js @@ -105,3 +105,6 @@ export const TYPE_QUERY_CONFIG = 'queryConfig' export const TYPE_SHIFTED = 'shifted queryConfig' export const TYPE_IFQL = 'ifql' export const DASHBOARD_NAME_MAX_LENGTH = 50 + +export const STATIC_LEGEND_SHOW = 'static' +export const STATIC_LEGEND_HIDE = null diff --git a/ui/src/shared/components/Dygraph.js b/ui/src/shared/components/Dygraph.js index df08d9a779..f51bc1314c 100644 --- a/ui/src/shared/components/Dygraph.js +++ b/ui/src/shared/components/Dygraph.js @@ -14,6 +14,7 @@ import {DISPLAY_OPTIONS} from 'src/dashboards/constants' import {buildDefaultYLabel} from 'shared/presenters' import {numberValueFormatter} from 'src/utils/formatting' +import {STATIC_LEGEND_SHOW} from 'src/dashboards/constants' import { OPTIONS, LINE_COLORS, @@ -302,10 +303,10 @@ export default class Dygraph extends Component { render() { const {isHidden, staticLegendHeight} = this.state - const {showStaticLegend} = this.props + const {staticLegend} = this.props let dygraphStyle = {...this.props.containerStyle, zIndex: '2'} - if (showStaticLegend) { + if (staticLegend.type === STATIC_LEGEND_SHOW) { const cellVerticalPadding = 16 dygraphStyle = { @@ -336,7 +337,7 @@ export default class Dygraph extends Component { className="dygraph-child-container" style={dygraphStyle} /> - {showStaticLegend + {staticLegend.type === STATIC_LEGEND_SHOW ? {}, onZoom: () => {}, + staticLegend: { + type: null, + }, } Dygraph.propTypes = { @@ -389,7 +393,7 @@ Dygraph.propTypes = { containerStyle: shape({}), isGraphFilled: bool, isBarGraph: bool, - showStaticLegend: bool, + staticLegend: shape({}).isRequired, overrideLineColors: array, dygraphSeries: shape({}).isRequired, ruleValues: shape({ diff --git a/ui/src/shared/components/LineGraph.js b/ui/src/shared/components/LineGraph.js index d05d04003c..8e5670442f 100644 --- a/ui/src/shared/components/LineGraph.js +++ b/ui/src/shared/components/LineGraph.js @@ -53,7 +53,7 @@ class LineGraph extends Component { isGraphFilled, showSingleStat, displayOptions, - showStaticLegend, + staticLegend, underlayCallback, overrideLineColors, isFetchingInitially, @@ -112,7 +112,7 @@ class LineGraph extends Component { setResolution={setResolution} overrideLineColors={lineColors} containerStyle={containerStyle} - showStaticLegend={showStaticLegend} + staticLegend={staticLegend} isGraphFilled={showSingleStat ? false : isGraphFilled} /> {showSingleStat @@ -160,7 +160,7 @@ LineGraph.propTypes = { underlayCallback: func, isGraphFilled: bool, isBarGraph: bool, - showStaticLegend: bool, + staticLegend: shape({}).isRequired, overrideLineColors: array, showSingleStat: bool, displayOptions: shape({ diff --git a/ui/src/shared/components/RefreshingGraph.js b/ui/src/shared/components/RefreshingGraph.js index 464631d757..260d9f91a8 100644 --- a/ui/src/shared/components/RefreshingGraph.js +++ b/ui/src/shared/components/RefreshingGraph.js @@ -22,7 +22,7 @@ const RefreshingGraph = ({ cellHeight, autoRefresh, resizerTopHeight, - showStaticLegend, + staticLegend, manualRefresh, // when changed, re-mounts the component synchronizer, resizeCoords, @@ -86,7 +86,7 @@ const RefreshingGraph = ({ isBarGraph={type === 'bar'} synchronizer={synchronizer} resizeCoords={resizeCoords} - showStaticLegend={showStaticLegend} + staticLegend={staticLegend} displayOptions={displayOptions} editQueryStatus={editQueryStatus} grabDataForDownload={grabDataForDownload} @@ -95,7 +95,7 @@ const RefreshingGraph = ({ ) } -const {arrayOf, func, number, shape, string, bool} = PropTypes +const {arrayOf, func, number, shape, string} = PropTypes RefreshingGraph.propTypes = { timeRange: shape({ @@ -111,7 +111,7 @@ RefreshingGraph.propTypes = { axes: shape(), queries: arrayOf(shape()).isRequired, editQueryStatus: func, - showStaticLegend: bool, + staticLegend: shape({}).isRequired, onZoom: func, resizeCoords: shape(), grabDataForDownload: func, From 31473cf559c94c3346240b30c3dcf2024a8f3ed2 Mon Sep 17 00:00:00 2001 From: Alex P Date: Thu, 1 Feb 2018 13:13:48 -0800 Subject: [PATCH 25/36] Remove static legend toggle from cell menu --- ui/src/shared/components/Layout.js | 11 ----------- ui/src/shared/components/LayoutCell.js | 10 +--------- ui/src/shared/components/LayoutCellMenu.js | 6 ------ 3 files changed, 1 insertion(+), 26 deletions(-) diff --git a/ui/src/shared/components/Layout.js b/ui/src/shared/components/Layout.js index 0428818637..0306013e24 100644 --- a/ui/src/shared/components/Layout.js +++ b/ui/src/shared/components/Layout.js @@ -18,25 +18,18 @@ const getSource = (cell, source, sources, defaultSource) => { class LayoutState extends Component { state = { celldata: [], - showStaticLegend: false, } grabDataForDownload = celldata => { this.setState({celldata}) } - toggleShowStaticLegend = () => { - const showStaticLegend = !this.state.showStaticLegend - this.setState({showStaticLegend}) - } - render() { return ( ) } @@ -60,10 +53,8 @@ const Layout = ( onDeleteCell, synchronizer, resizeCoords, - showStaticLegend, onCancelEditCell, onStopAddAnnotation, - toggleShowStaticLegend, onSummonOverlayTechnologies, grabDataForDownload, }, @@ -76,7 +67,6 @@ const Layout = ( onEditCell={onEditCell} onDeleteCell={onDeleteCell} onCancelEditCell={onCancelEditCell} - toggleShowStaticLegend={toggleShowStaticLegend} onSummonOverlayTechnologies={onSummonOverlayTechnologies} > {cell.isWidget @@ -93,7 +83,6 @@ const Layout = ( autoRefresh={autoRefresh} synchronizer={synchronizer} manualRefresh={manualRefresh} - showStaticLegend={showStaticLegend} onStopAddAnnotation={onStopAddAnnotation} grabDataForDownload={grabDataForDownload} resizeCoords={resizeCoords} diff --git a/ui/src/shared/components/LayoutCell.js b/ui/src/shared/components/LayoutCell.js index b4b524ec38..f87780c87b 100644 --- a/ui/src/shared/components/LayoutCell.js +++ b/ui/src/shared/components/LayoutCell.js @@ -30,13 +30,7 @@ class LayoutCell extends Component { } render() { - const { - cell, - children, - isEditable, - celldata, - toggleShowStaticLegend, - } = this.props + const {cell, children, isEditable, celldata} = this.props const queries = _.get(cell, ['queries'], []) @@ -51,7 +45,6 @@ class LayoutCell extends Component { onDelete={this.handleDeleteCell} onEdit={this.handleSummonOverlay} onCSVDownload={this.handleCSVDownload} - toggleShowStaticLegend={toggleShowStaticLegend} /> @@ -89,7 +82,6 @@ LayoutCell.propTypes = { onSummonOverlayTechnologies: func, isEditable: bool, onCancelEditCell: func, - toggleShowStaticLegend: func, celldata: arrayOf(shape()), } diff --git a/ui/src/shared/components/LayoutCellMenu.js b/ui/src/shared/components/LayoutCellMenu.js index 0f4ee001aa..4ab8dc328e 100644 --- a/ui/src/shared/components/LayoutCellMenu.js +++ b/ui/src/shared/components/LayoutCellMenu.js @@ -35,7 +35,6 @@ class LayoutCellMenu extends Component { isEditable, dataExists, onCSVDownload, - toggleShowStaticLegend, onStartAddingAnnotation, onStartEditingAnnotation, onDismissEditingAnnotation, @@ -67,10 +66,6 @@ class LayoutCellMenu extends Component { text: 'Edit Annotations', action: onStartEditingAnnotation, }, - { - text: 'Show Legend', - action: toggleShowStaticLegend, - }, ]} informParent={this.handleToggleSubMenu} /> @@ -115,7 +110,6 @@ LayoutCellMenu.propTypes = { dataExists: bool, onCSVDownload: func, queries: arrayOf(shape()), - toggleShowStaticLegend: func.isRequired, onStartAddingAnnotation: func.isRequired, onStartEditingAnnotation: func.isRequired, onDismissEditingAnnotation: func.isRequired, From a2f4201504b6e01f56eb94822ee47cfe212e6cdc Mon Sep 17 00:00:00 2001 From: Alex Paxton Date: Tue, 6 Feb 2018 12:50:58 -0800 Subject: [PATCH 26/36] transform cell.legend to staticLegend property in graphs, and add staticLegend to graphs Signed-off-by: Deniz Kusefoglu --- ui/src/dashboards/components/AxesOptions.js | 9 ++++---- .../components/CellEditorOverlay.js | 21 +++++++++---------- .../dashboards/components/DisplayOptions.js | 2 +- ui/src/dashboards/components/Visualization.js | 4 ++-- ui/src/dashboards/constants/index.js | 3 --- ui/src/shared/components/Dygraph.js | 7 +++---- ui/src/shared/components/Layout.js | 4 +++- ui/src/shared/components/LineGraph.js | 3 ++- ui/src/shared/components/RefreshingGraph.js | 5 +++-- ui/src/shared/constants/index.js | 5 +++++ ui/src/status/fixtures.js | 4 ++++ 11 files changed, 37 insertions(+), 30 deletions(-) diff --git a/ui/src/dashboards/components/AxesOptions.js b/ui/src/dashboards/components/AxesOptions.js index 0bfde61eb6..b850d93c02 100644 --- a/ui/src/dashboards/components/AxesOptions.js +++ b/ui/src/dashboards/components/AxesOptions.js @@ -7,7 +7,6 @@ import FancyScrollbar from 'shared/components/FancyScrollbar' import {DISPLAY_OPTIONS, TOOLTIP_CONTENT} from 'src/dashboards/constants' import {GRAPH_TYPES} from 'src/dashboards/graphics/graph' -import {STATIC_LEGEND_SHOW, STATIC_LEGEND_HIDE} from 'src/dashboards/constants' const {LINEAR, LOG, BASE_2, BASE_10} = DISPLAY_OPTIONS const getInputMin = scale => (scale === LOG ? '0' : null) @@ -114,12 +113,12 @@ const AxesOptions = ({ @@ -129,7 +128,7 @@ const AxesOptions = ({ ) } -const {arrayOf, func, shape, string} = PropTypes +const {arrayOf, bool, func, shape, string} = PropTypes AxesOptions.defaultProps = { axes: { @@ -160,7 +159,7 @@ AxesOptions.propTypes = { }), }).isRequired, onToggleStaticLegend: func.isRequired, - staticLegend: shape({}).isRequired, + staticLegend: bool, } export default AxesOptions diff --git a/ui/src/dashboards/components/CellEditorOverlay.js b/ui/src/dashboards/components/CellEditorOverlay.js index 9c87295e40..8d074447d7 100644 --- a/ui/src/dashboards/components/CellEditorOverlay.js +++ b/ui/src/dashboards/components/CellEditorOverlay.js @@ -14,12 +14,11 @@ import * as queryModifiers from 'src/utils/queryTransitions' import defaultQueryConfig from 'src/utils/defaultQueryConfig' import {buildQuery} from 'utils/influxql' import {getQueryConfig} from 'shared/apis' +import {GET_STATIC_LEGEND} from 'src/shared/constants' import { removeUnselectedTemplateValues, TYPE_QUERY_CONFIG, - STATIC_LEGEND_SHOW, - STATIC_LEGEND_HIDE, } from 'src/dashboards/constants' import {OVERLAY_TECHNOLOGY} from 'shared/constants/classNames' import {MINIMUM_HEIGHTS, INITIAL_HEIGHTS} from 'src/data_explorer/constants' @@ -35,10 +34,6 @@ import { validateColors, } from 'src/dashboards/constants/gaugeColors' -const FAKE_LEGEND_OPTS = { - type: null, - orient: 'bottom', -} class CellEditorOverlay extends Component { constructor(props) { super(props) @@ -66,7 +61,7 @@ class CellEditorOverlay extends Component { axes, colorSingleStatText: colorsTypeContainsText, colors: validateColors(colors, type, colorsTypeContainsText), - staticLegend: legend || FAKE_LEGEND_OPTS, + staticLegend: GET_STATIC_LEGEND(legend), } } @@ -302,6 +297,7 @@ class CellEditorOverlay extends Component { cellWorkingName: name, axes, colors, + staticLegend, } = this.state const {cell} = this.props @@ -324,6 +320,12 @@ class CellEditorOverlay extends Component { queries, axes, colors, + legend: staticLegend + ? { + type: 'static', + orientation: 'bottom', + } + : {}, }) } @@ -377,10 +379,7 @@ class CellEditorOverlay extends Component { }) } - handleToggleStaticLegend = newState => () => { - const type = newState ? STATIC_LEGEND_SHOW : STATIC_LEGEND_HIDE - const staticLegend = {...this.state.staticLegend, type} - + handleToggleStaticLegend = staticLegend => () => { this.setState({staticLegend}) } diff --git a/ui/src/dashboards/components/DisplayOptions.js b/ui/src/dashboards/components/DisplayOptions.js index 55f9a9a913..82cb14c8ca 100644 --- a/ui/src/dashboards/components/DisplayOptions.js +++ b/ui/src/dashboards/components/DisplayOptions.js @@ -146,7 +146,7 @@ DisplayOptions.propTypes = { colorSingleStatText: bool.isRequired, onToggleSingleStatText: func.isRequired, onToggleStaticLegend: func.isRequired, - staticLegend: shape({}).isRequired, + staticLegend: bool, } export default DisplayOptions diff --git a/ui/src/dashboards/components/Visualization.js b/ui/src/dashboards/components/Visualization.js index 4f54f14f25..629038c260 100644 --- a/ui/src/dashboards/components/Visualization.js +++ b/ui/src/dashboards/components/Visualization.js @@ -37,7 +37,7 @@ const DashVisualization = (
-const {arrayOf, func, number, shape, string} = PropTypes +const {arrayOf, bool, func, number, shape, string} = PropTypes DashVisualization.defaultProps = { name: '', @@ -71,7 +71,7 @@ DashVisualization.propTypes = { value: string.isRequired, }).isRequired ), - staticLegend: shape({}).isRequired, + staticLegend: bool, } DashVisualization.contextTypes = { diff --git a/ui/src/dashboards/constants/index.js b/ui/src/dashboards/constants/index.js index a9e7cdcf33..25d5293c96 100644 --- a/ui/src/dashboards/constants/index.js +++ b/ui/src/dashboards/constants/index.js @@ -105,6 +105,3 @@ export const TYPE_QUERY_CONFIG = 'queryConfig' export const TYPE_SHIFTED = 'shifted queryConfig' export const TYPE_IFQL = 'ifql' export const DASHBOARD_NAME_MAX_LENGTH = 50 - -export const STATIC_LEGEND_SHOW = 'static' -export const STATIC_LEGEND_HIDE = null diff --git a/ui/src/shared/components/Dygraph.js b/ui/src/shared/components/Dygraph.js index f51bc1314c..eda17935ed 100644 --- a/ui/src/shared/components/Dygraph.js +++ b/ui/src/shared/components/Dygraph.js @@ -14,7 +14,6 @@ import {DISPLAY_OPTIONS} from 'src/dashboards/constants' import {buildDefaultYLabel} from 'shared/presenters' import {numberValueFormatter} from 'src/utils/formatting' -import {STATIC_LEGEND_SHOW} from 'src/dashboards/constants' import { OPTIONS, LINE_COLORS, @@ -306,7 +305,7 @@ export default class Dygraph extends Component { const {staticLegend} = this.props let dygraphStyle = {...this.props.containerStyle, zIndex: '2'} - if (staticLegend.type === STATIC_LEGEND_SHOW) { + if (staticLegend) { const cellVerticalPadding = 16 dygraphStyle = { @@ -337,7 +336,7 @@ export default class Dygraph extends Component { className="dygraph-child-container" style={dygraphStyle} /> - {staticLegend.type === STATIC_LEGEND_SHOW + {staticLegend ? {}, isGraphFilled: true, overrideLineColors: null, + staticLegend: false, } LineGraph.propTypes = { @@ -160,7 +161,7 @@ LineGraph.propTypes = { underlayCallback: func, isGraphFilled: bool, isBarGraph: bool, - staticLegend: shape({}).isRequired, + staticLegend: bool, overrideLineColors: array, showSingleStat: bool, displayOptions: shape({ diff --git a/ui/src/shared/components/RefreshingGraph.js b/ui/src/shared/components/RefreshingGraph.js index 260d9f91a8..493dca5ab2 100644 --- a/ui/src/shared/components/RefreshingGraph.js +++ b/ui/src/shared/components/RefreshingGraph.js @@ -95,7 +95,7 @@ const RefreshingGraph = ({ ) } -const {arrayOf, func, number, shape, string} = PropTypes +const {arrayOf, bool, func, number, shape, string} = PropTypes RefreshingGraph.propTypes = { timeRange: shape({ @@ -111,7 +111,7 @@ RefreshingGraph.propTypes = { axes: shape(), queries: arrayOf(shape()).isRequired, editQueryStatus: func, - staticLegend: shape({}).isRequired, + staticLegend: bool, onZoom: func, resizeCoords: shape(), grabDataForDownload: func, @@ -128,6 +128,7 @@ RefreshingGraph.propTypes = { RefreshingGraph.defaultProps = { manualRefresh: 0, + staticLegend: false, } export default RefreshingGraph diff --git a/ui/src/shared/constants/index.js b/ui/src/shared/constants/index.js index 0bc9e48ac2..c258fdf72f 100644 --- a/ui/src/shared/constants/index.js +++ b/ui/src/shared/constants/index.js @@ -1,3 +1,5 @@ +import _ from 'lodash' + export const PERMISSIONS = { ViewAdmin: { description: 'Can view or edit admin screens', @@ -424,3 +426,6 @@ export const DEFAULT_SOURCE = { insecureSkipVerify: false, metaUrl: '', } + +export const GET_STATIC_LEGEND = legend => + _.get(legend, 'type', false) === 'static' diff --git a/ui/src/status/fixtures.js b/ui/src/status/fixtures.js index 3a221ae8b6..d366801897 100644 --- a/ui/src/status/fixtures.js +++ b/ui/src/status/fixtures.js @@ -6,6 +6,7 @@ export const fixtureStatusPageCells = [ y: 0, w: 12, h: 4, + legend: {}, name: 'Alert Events per Day – Last 30 Days', queries: [ { @@ -54,6 +55,7 @@ export const fixtureStatusPageCells = [ y: 5, w: 6.5, h: 6, + legend: {}, queries: [ { query: '', @@ -80,6 +82,7 @@ export const fixtureStatusPageCells = [ y: 5, w: 3, h: 6, + legend: {}, queries: [ { query: '', @@ -106,6 +109,7 @@ export const fixtureStatusPageCells = [ y: 5, w: 2.5, h: 6, + legend: {}, queries: [ { query: '', From a779c8181a34fd73218b7d24b755e5f8667a11eb Mon Sep 17 00:00:00 2001 From: deniz kusefoglu Date: Wed, 7 Feb 2018 10:13:32 -0800 Subject: [PATCH 27/36] Fix static legend click behavior in cell editor overlay --- ui/src/shared/components/StaticLegend.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/shared/components/StaticLegend.js b/ui/src/shared/components/StaticLegend.js index 4c1f677f75..b04dba8517 100644 --- a/ui/src/shared/components/StaticLegend.js +++ b/ui/src/shared/components/StaticLegend.js @@ -84,7 +84,7 @@ class StaticLegend extends Component {
Date: Wed, 7 Feb 2018 11:45:02 -0800 Subject: [PATCH 28/36] Fix render delay when static legend is toggled --- ui/src/shared/components/StaticLegend.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/shared/components/StaticLegend.js b/ui/src/shared/components/StaticLegend.js index b04dba8517..0cf907c700 100644 --- a/ui/src/shared/components/StaticLegend.js +++ b/ui/src/shared/components/StaticLegend.js @@ -33,7 +33,7 @@ class StaticLegend extends Component { } } - componentDidUpdate = () => { + componentDidMount = () => { const {height} = this.staticLegendRef.getBoundingClientRect() this.props.handleReceiveStaticLegendHeight(height) } From 167c90d6e1c7d7728a1a16a279ff0fa88a2b9352 Mon Sep 17 00:00:00 2001 From: Alex P Date: Wed, 7 Feb 2018 11:49:12 -0800 Subject: [PATCH 29/36] Ensure that static legend is accounted for in dashboard view as well I guess we need both methods! woooo --- ui/src/shared/components/StaticLegend.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ui/src/shared/components/StaticLegend.js b/ui/src/shared/components/StaticLegend.js index 0cf907c700..92d2c74f3c 100644 --- a/ui/src/shared/components/StaticLegend.js +++ b/ui/src/shared/components/StaticLegend.js @@ -38,6 +38,11 @@ class StaticLegend extends Component { this.props.handleReceiveStaticLegendHeight(height) } + componentDidUpdate = () => { + const {height} = this.staticLegendRef.getBoundingClientRect() + this.props.handleReceiveStaticLegendHeight(height) + } + componentWillUnmount = () => { this.props.handleReceiveStaticLegendHeight(null) } From 007cb0df3346cd775606f717dcaf463cceb92eca Mon Sep 17 00:00:00 2001 From: Alex P Date: Wed, 7 Feb 2018 12:07:46 -0800 Subject: [PATCH 30/36] Fix appearance of single static legend item Previously it suggested that it can be clicked, but actually does nothing. There is no hover state for this case --- ui/src/shared/components/StaticLegend.js | 10 +++++++--- ui/src/style/components/static-legend.scss | 7 +++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/ui/src/shared/components/StaticLegend.js b/ui/src/shared/components/StaticLegend.js index 92d2c74f3c..f5864bda22 100644 --- a/ui/src/shared/components/StaticLegend.js +++ b/ui/src/shared/components/StaticLegend.js @@ -15,9 +15,11 @@ const removeMeasurement = (label = '') => { return label.replace(measurement, '') } -const staticLegendItemClassname = (visibilities, i) => { +const staticLegendItemClassname = (visibilities, i, hoverEnabled) => { if (visibilities.length) { - return `static-legend--item${visibilities[i] ? '' : ' disabled'}` + return `${hoverEnabled + ? 'static-legend--item' + : 'static-legend--single'}${visibilities[i] ? '' : ' disabled'}` } // all series are visible to match expected initial state @@ -77,6 +79,8 @@ class StaticLegend extends Component { }) : [] + const hoverEnabled = labels.length > 1 + return (
{_.map(labels, (v, i) =>
diff --git a/ui/src/style/components/static-legend.scss b/ui/src/style/components/static-legend.scss index 44ec9a1af0..504ca28332 100644 --- a/ui/src/style/components/static-legend.scss +++ b/ui/src/style/components/static-legend.scss @@ -22,18 +22,21 @@ border-radius: 50%; background-color: $g20-white; } -.static-legend--item { +.static-legend--item, +.static-legend--single { height: 22px; line-height: 22px; white-space: nowrap; background-color: $g4-onyx; border-radius: 3px; - transition: background-color 0.25s ease, color 0.25s ease; color: $g20-white; font-size: 12px; font-weight: 600; padding: 0 7px; margin: 1px; +} +.static-legend--item { + transition: background-color 0.25s ease, color 0.25s ease; span, .static-legend--dot { From bed393e6399c24ef8e6cd1864a9ee605a0065049 Mon Sep 17 00:00:00 2001 From: deniz kusefoglu Date: Thu, 15 Feb 2018 23:53:33 -0500 Subject: [PATCH 31/36] Fix linting errors from merging on github --- ui/src/shared/annotations/styles.js | 5 ++--- ui/src/shared/components/Dygraph.js | 4 +--- ui/src/shared/components/NewAnnotation.js | 2 +- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/ui/src/shared/annotations/styles.js b/ui/src/shared/annotations/styles.js index f45673aa5b..82a952ed44 100644 --- a/ui/src/shared/annotations/styles.js +++ b/ui/src/shared/annotations/styles.js @@ -161,7 +161,6 @@ export const annotationStyle = ( isDragging, staticLegendHeight ) => { -export const annotationStyle = ({time}, dygraph, isMouseOver, isDragging) => { // TODO: export and test this function const [startX, endX] = dygraph.xAxisRange() let visibility = 'visible' @@ -177,7 +176,7 @@ export const annotationStyle = ({time}, dygraph, isMouseOver, isDragging) => { const height = staticLegendHeight ? `calc(100% - ${staticLegendHeight + 36}px)` : 'calc(100% - 36px)' - + return { left, position: 'absolute', @@ -240,7 +239,7 @@ export const annotationWindowStyle = ( position: 'absolute', top: '8px', background: `linear-gradient(to bottom, ${gradientStartColor} 0%,${gradientEndColor} 100%)`, - height: 'calc(100% - 36px)', + height, borderTop: `2px dotted rgba(${annotationColor},0.35)`, width, zIndex: zIndexWindow, diff --git a/ui/src/shared/components/Dygraph.js b/ui/src/shared/components/Dygraph.js index 5030905df5..b83e71360d 100644 --- a/ui/src/shared/components/Dygraph.js +++ b/ui/src/shared/components/Dygraph.js @@ -25,7 +25,6 @@ import { highlightSeriesOpts, } from 'src/shared/graphs/helpers' const {LINEAR, LOG, BASE_10, BASE_2} = DISPLAY_OPTIONS -import {ADDING, EDITING} from 'src/shared/annotations/helpers' class Dygraph extends Component { constructor(props) { @@ -304,8 +303,7 @@ class Dygraph extends Component { render() { const {isHidden, staticLegendHeight} = this.state - const {staticLegend,mode} = this.props - const hideLegend = mode === EDITING || mode === ADDING ? true : isHidden + const {staticLegend} = this.props let dygraphStyle = {...this.props.containerStyle, zIndex: '2'} if (staticLegend) { diff --git a/ui/src/shared/components/NewAnnotation.js b/ui/src/shared/components/NewAnnotation.js index 27a54accd5..b98adf14a7 100644 --- a/ui/src/shared/components/NewAnnotation.js +++ b/ui/src/shared/components/NewAnnotation.js @@ -172,7 +172,7 @@ class NewAnnotation extends Component { } } -const {bool, func, number, shape} = P +const {bool, func, number, shape} = PropTypes NewAnnotation.propTypes = { dygraph: shape({}).isRequired, From 68bcdc9e6a1230c58441eadf913274e7eb2881fb Mon Sep 17 00:00:00 2001 From: Deniz Kusefoglu Date: Tue, 20 Feb 2018 11:51:32 -0800 Subject: [PATCH 32/36] Fix test errors --- ui/src/dashboards/components/CellEditorOverlay.js | 10 ++++++---- ui/src/dashboards/components/DisplayOptions.js | 4 +++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/ui/src/dashboards/components/CellEditorOverlay.js b/ui/src/dashboards/components/CellEditorOverlay.js index 9975dbf377..88f2c9a777 100644 --- a/ui/src/dashboards/components/CellEditorOverlay.js +++ b/ui/src/dashboards/components/CellEditorOverlay.js @@ -61,8 +61,9 @@ class CellEditorOverlay extends Component { activeQueryIndex: 0, isDisplayOptionsTabActive: false, axes, - colorSingleStatText: colorsTypeContainsText, - colors: validateColors(colors, type, colorsTypeContainsText), + singleStatType, + gaugeColors: validateGaugeColors(colors), + singleStatColors: validateSingleStatColors(colors, singleStatType), staticLegend: GET_STATIC_LEGEND(legend), } } @@ -361,7 +362,8 @@ class CellEditorOverlay extends Component { cellWorkingType: type, cellWorkingName: name, axes, - colors, + gaugeColors, + singleStatColors, staticLegend, } = this.state @@ -556,7 +558,7 @@ class CellEditorOverlay extends Component { cellWorkingType, isDisplayOptionsTabActive, queriesWorkingDraft, - colorSingleStatText, + singleStatType, staticLegend, } = this.state diff --git a/ui/src/dashboards/components/DisplayOptions.js b/ui/src/dashboards/components/DisplayOptions.js index 659ea7d0c9..8ac4ddf179 100644 --- a/ui/src/dashboards/components/DisplayOptions.js +++ b/ui/src/dashboards/components/DisplayOptions.js @@ -117,7 +117,7 @@ class DisplayOptions extends Component { ) } } -const {arrayOf, func, number, shape, string} = PropTypes +const {arrayOf, func, number, shape, string, bool} = PropTypes DisplayOptions.propTypes = { onAddGaugeThreshold: func.isRequired, @@ -159,6 +159,8 @@ DisplayOptions.propTypes = { onToggleSingleStatText: func.isRequired, onToggleStaticLegend: func.isRequired, staticLegend: bool, + onToggleSingleStatType: func, + singleStatType: string, } export default DisplayOptions From ed1b836c392d865e0582f4827541dbed19e4b989 Mon Sep 17 00:00:00 2001 From: Luke Morris Date: Fri, 23 Feb 2018 16:24:38 -0800 Subject: [PATCH 33/36] This not needed anymore --- ui/src/shared/annotations/styles.js | 382 ---------------------------- 1 file changed, 382 deletions(-) delete mode 100644 ui/src/shared/annotations/styles.js diff --git a/ui/src/shared/annotations/styles.js b/ui/src/shared/annotations/styles.js deleted file mode 100644 index 82a952ed44..0000000000 --- a/ui/src/shared/annotations/styles.js +++ /dev/null @@ -1,382 +0,0 @@ -import {NEUTRALS, BLUES} from 'src/shared/constants/influxColors' - -// Styles for all things Annotations -const annotationColor = '255,255,255' -const annotationDragColor = '107,223,255' -const zIndexWindow = '1' -const zIndexAnnotation = '3' -const zIndexAnnotationActive = '4' -const timestampFontSize = '14px' -const timestampFontWeight = '600' - -export const flagStyle = (mouseOver, dragging, hasDuration, isEndpoint) => { - const baseStyle = { - position: 'absolute', - zIndex: '2', - } - let style = { - ...baseStyle, - top: '-3px', - left: '-2px', - width: '6px', - height: '6px', - backgroundColor: `rgb(${annotationColor})`, - borderRadius: '50%', - transition: 'background-color 0.25s ease, transform 0.25s ease', - } - - if (hasDuration) { - style = { - ...baseStyle, - top: '-6px', - width: '0', - height: '0', - left: '0', - border: '6px solid transparent', - borderLeftColor: `rgb(${annotationColor})`, - borderRadius: '0', - background: 'none', - transition: 'border-left-color 0.25s ease, transform 0.25s ease', - transformOrigin: '0% 50%', - } - } - - if (isEndpoint) { - style = { - ...baseStyle, - top: '-6px', - width: '0', - height: '0', - left: 'initial', - right: '0', - border: '6px solid transparent', - borderRightColor: `rgb(${annotationColor})`, - borderRadius: '0', - background: 'none', - transition: 'border-right-color 0.25s ease, transform 0.25s ease', - transformOrigin: '100% 50%', - } - } - - if (dragging) { - if (hasDuration) { - return { - ...style, - transform: 'scale(1.5,1.5)', - borderLeftColor: `rgb(${annotationDragColor})`, - } - } - - if (isEndpoint) { - return { - ...style, - transform: 'scale(1.5,1.5)', - borderRightColor: `rgb(${annotationDragColor})`, - } - } - - return { - ...style, - transform: 'scale(1.5,1.5)', - backgroundColor: `rgb(${annotationDragColor})`, - } - } - - if (mouseOver) { - return {...style, transform: 'scale(1.5,1.5)'} - } - - return style -} - -export const clickAreaStyle = (dragging, editing) => { - const style = { - position: 'absolute', - top: '-8px', - left: editing ? '-5px' : '-7px', - width: editing ? '12px' : '16px', - height: editing ? 'calc(100% + 8px)' : '16px', - zIndex: '4', - cursor: editing ? 'col-resize' : 'default', - } - - if (dragging) { - return { - ...style, - width: '10000px', - left: '-5000px', - height: '10000px', - top: '-5000px', - } - } - - return style -} - -export const tooltipStyle = annotationState => { - const {isDragging, isMouseOver} = annotationState - const isVisible = isDragging || isMouseOver - - return { - position: 'absolute', - bottom: 'calc(100% + 8px)', - left: '50%', - transform: 'translateX(-50%)', - backgroundColor: NEUTRALS[0], - zIndex: '3', - padding: isDragging ? '6px 12px' : '12px 12px 6px 12px', - borderRadius: '4px', - whiteSpace: 'nowrap', - userSelect: 'none', - display: isVisible ? 'flex' : 'none', - boxShadow: `0 0 10px 2px ${NEUTRALS[2]}`, - } -} - -export const tooltipItemsStyle = { - display: 'flex', - flexDirection: 'column', - alignItems: 'center', -} -export const tooltipTimestampStyle = { - color: NEUTRALS[20], - display: 'block', - fontSize: timestampFontSize, - fontWeight: timestampFontWeight, -} -export const tooltipInputContainer = {width: '100%', marginBottom: '4px'} -export const tooltipFormStyle = { - display: 'inline-flex', - alignItems: 'center', - flexWrap: 'nowrap', - width: '100%', -} -export const tooltipInputButton = {marginLeft: '2px'} -export const tooltipInput = {flex: '1 0 0'} - -export const annotationStyle = ( - {time}, - dygraph, - isMouseOver, - isDragging, - staticLegendHeight -) => { - // TODO: export and test this function - const [startX, endX] = dygraph.xAxisRange() - let visibility = 'visible' - - if (time < startX || time > endX) { - visibility = 'hidden' - } - - const containerLeftPadding = 16 - const left = `${dygraph.toDomXCoord(time) + containerLeftPadding}px` - const width = 2 - - const height = staticLegendHeight - ? `calc(100% - ${staticLegendHeight + 36}px)` - : 'calc(100% - 36px)' - - return { - left, - position: 'absolute', - top: '8px', - backgroundColor: `rgb(${isDragging - ? annotationDragColor - : annotationColor})`, - height, - width: `${width}px`, - transition: 'background-color 0.25s ease', - transform: `translateX(-${width / 2}px)`, // translate should always be half with width to horizontally center the annotation pole - visibility, - zIndex: - isDragging || isMouseOver ? zIndexAnnotationActive : zIndexAnnotation, - } -} - -export const annotationWindowStyle = ( - annotation, - dygraph, - staticLegendHeight -) => { - // TODO: export and test this function - const [startX, endX] = dygraph.xAxisRange() - const containerLeftPadding = 16 - const windowEnd = Number(annotation.time) + Number(annotation.duration) - - let windowStartXCoord = dygraph.toDomXCoord(annotation.time) - let windowEndXCoord = dygraph.toDomXCoord(windowEnd) - let visibility = 'visible' - - if (annotation.time < startX) { - windowStartXCoord = dygraph.toDomXCoord(startX) - } - - if (windowEnd > endX) { - windowEndXCoord = dygraph.toDomXCoord(endX) - } - - if (windowEnd < startX || annotation.time > endX) { - visibility = 'hidden' - } - - const windowWidth = windowEndXCoord - windowStartXCoord - const isDurationNegative = windowWidth < 0 - const foo = isDurationNegative ? windowWidth : 0 - - const left = `${windowStartXCoord + containerLeftPadding + foo}px` - const width = `${Math.abs(windowWidth)}px` - - const gradientStartColor = `rgba(${annotationColor},0.15)` - const gradientEndColor = `rgba(${annotationColor},0)` - - const height = staticLegendHeight - ? `calc(100% - ${staticLegendHeight + 36}px)` - : 'calc(100% - 36px)' - - return { - left, - position: 'absolute', - top: '8px', - background: `linear-gradient(to bottom, ${gradientStartColor} 0%,${gradientEndColor} 100%)`, - height, - borderTop: `2px dotted rgba(${annotationColor},0.35)`, - width, - zIndex: zIndexWindow, - visibility, - } -} - -// Styles for new Annotations -export const newAnnotationContainer = staticLegendHeight => { - const style = { - position: 'absolute', - zIndex: '9999', - top: '8px', - left: '16px', - width: 'calc(100% - 32px)', - height: 'calc(100% - 16px)', - cursor: 'pointer', - } - - return staticLegendHeight - ? {...style, height: `calc(100% - ${16 + staticLegendHeight}px)`} - : style -} -export const newAnnotationCrosshairStyle = left => { - const width = 2 - - return { - position: 'absolute', - top: '0', - left: `${left}px`, - height: 'calc(100% - 20px)', - width: `${width}px`, - transform: `translateX(-${width / 2}px)`, // translate should always be half with width to horizontally center the comment pole - background: `linear-gradient(to bottom, ${BLUES.hydrogen} 0%,${BLUES.pool} 100%)`, - visibility: left ? 'visible' : 'hidden', - transition: 'opacity 0.4s ease', - zIndex: '5', - cursor: 'pointer', - } -} -export const newAnnotationTooltipStyle = isMouseHovering => { - return { - display: isMouseHovering ? 'flex' : 'none', - flexDirection: 'column', - alignItems: 'center', - background: `linear-gradient(to bottom, ${BLUES.pool} 0%,${BLUES.ocean} 100%)`, - borderRadius: '4px', - padding: '6px 12px', - position: 'absolute', - bottom: 'calc(100% + 8px)', - left: '50%', - transform: 'translateX(-50%)', - zIndex: '10', - } -} -export const newAnnotationHelperStyle = { - whiteSpace: 'nowrap', - fontSize: '13px', - lineHeight: '13px', - fontWeight: '600', - color: BLUES.neutrino, - marginBottom: '4px', -} -export const newAnnotationTimestampStyle = { - whiteSpace: 'nowrap', - fontSize: timestampFontSize, - lineHeight: timestampFontSize, - fontWeight: timestampFontWeight, - color: NEUTRALS[20], -} -export const circleFlagStyle = { - position: 'absolute', - zIndex: '2', - top: '-3px', - left: '-2px', - width: '6px', - height: '6px', - backgroundColor: `rgb(${annotationDragColor})`, - borderRadius: '50%', - transition: 'background-color 0.25s ease, transform 0.25s ease', -} - -export const staticFlagStyle = { - position: 'absolute', - zIndex: '2', - top: '-6px', - width: '0', - height: '0', - left: '0', - border: '6px solid transparent', - borderLeftColor: `rgb(${annotationDragColor})`, - borderRadius: '0', - background: 'none', - transition: 'border-left-color 0.25s ease, transform 0.25s ease', - transformOrigin: '0% 50%', -} -export const draggingFlagStyle = { - position: 'absolute', - zIndex: '2', - top: '-6px', - width: '0', - height: '0', - left: 'initial', - right: '0', - border: '6px solid transparent', - borderRightColor: `rgb(${annotationDragColor})`, - borderRadius: '0', - background: 'none', - transition: 'border-right-color 0.25s ease, transform 0.25s ease', - transformOrigin: '100% 50%', -} - -export const newAnnotationWindowStyle = (isDragging, staticX, draggingX) => { - // TODO: export and test this function - - const width = `${Math.abs(Number(draggingX) - Number(staticX))}px` - - let left - - if (draggingX > staticX) { - left = `${staticX}px` - } else { - left = `${draggingX}px` - } - - const gradientStartColor = `rgba(${annotationDragColor},0.15)` - const gradientEndColor = `rgba(${annotationDragColor},0)` - - return { - left, - position: 'absolute', - top: '0', - background: `linear-gradient(to bottom, ${gradientStartColor} 0%,${gradientEndColor} 100%)`, - height: 'calc(100% - 20px)', - borderTop: `2px dotted rgba(${annotationDragColor},0.35)`, - width, - zIndex: '3', - visibility: isDragging ? 'visible' : 'hidden', - } -} From b4ecdf3c5ee8bbd66f5412076882715f93d0f924 Mon Sep 17 00:00:00 2001 From: Deniz Kusefoglu Date: Tue, 27 Feb 2018 10:02:43 -0800 Subject: [PATCH 34/36] Implement PR review suggestions. --- .../components/CellEditorOverlay.js | 4 +- ui/src/shared/components/Dygraph.js | 15 ++++---- ui/src/shared/components/DygraphLegend.js | 7 +--- ui/src/shared/components/Layout.js | 4 +- ui/src/shared/components/StaticLegend.js | 38 ++++++++----------- ui/src/shared/constants/index.js | 2 +- ui/src/shared/graphs/helpers.js | 6 +++ ui/src/style/components/static-legend.scss | 5 +++ 8 files changed, 40 insertions(+), 41 deletions(-) diff --git a/ui/src/dashboards/components/CellEditorOverlay.js b/ui/src/dashboards/components/CellEditorOverlay.js index c183a311bd..e53d362ab4 100644 --- a/ui/src/dashboards/components/CellEditorOverlay.js +++ b/ui/src/dashboards/components/CellEditorOverlay.js @@ -14,7 +14,7 @@ import * as queryModifiers from 'src/utils/queryTransitions' import defaultQueryConfig from 'src/utils/defaultQueryConfig' import {buildQuery} from 'utils/influxql' import {getQueryConfig} from 'shared/apis' -import {GET_STATIC_LEGEND} from 'src/shared/constants' +import {IS_STATIC_LEGEND} from 'src/shared/constants' import { removeUnselectedTemplateValues, @@ -46,7 +46,7 @@ class CellEditorOverlay extends Component { queriesWorkingDraft, activeQueryIndex: 0, isDisplayOptionsTabActive: false, - staticLegend: GET_STATIC_LEGEND(legend), + staticLegend: IS_STATIC_LEGEND(legend), } } diff --git a/ui/src/shared/components/Dygraph.js b/ui/src/shared/components/Dygraph.js index 897ef34a40..fce4703321 100644 --- a/ui/src/shared/components/Dygraph.js +++ b/ui/src/shared/components/Dygraph.js @@ -339,14 +339,13 @@ class Dygraph extends Component { className="dygraph-child-container" style={dygraphStyle} /> - {staticLegend - ? - : null} + {staticLegend && + }
) } diff --git a/ui/src/shared/components/DygraphLegend.js b/ui/src/shared/components/DygraphLegend.js index 2e2c836fb6..7f0b91082c 100644 --- a/ui/src/shared/components/DygraphLegend.js +++ b/ui/src/shared/components/DygraphLegend.js @@ -3,12 +3,7 @@ import _ from 'lodash' import classnames from 'classnames' import uuid from 'node-uuid' -import {makeLegendStyles} from 'shared/graphs/helpers' - -const removeMeasurement = (label = '') => { - const [measurement] = label.match(/^(.*)[.]/g) || [''] - return label.replace(measurement, '') -} +import {makeLegendStyles, removeMeasurement} from 'shared/graphs/helpers' class DygraphLegend extends Component { state = { diff --git a/ui/src/shared/components/Layout.js b/ui/src/shared/components/Layout.js index 4873a3188f..bb79fd0da1 100644 --- a/ui/src/shared/components/Layout.js +++ b/ui/src/shared/components/Layout.js @@ -3,7 +3,7 @@ import WidgetCell from 'shared/components/WidgetCell' import LayoutCell from 'shared/components/LayoutCell' import RefreshingGraph from 'shared/components/RefreshingGraph' import {buildQueriesForLayouts} from 'utils/buildQueriesForLayouts' -import {GET_STATIC_LEGEND} from 'src/shared/constants' +import {IS_STATIC_LEGEND} from 'src/shared/constants' import _ from 'lodash' @@ -75,7 +75,7 @@ const Layout = ( : { - const [measurement] = label.match(/^(.*)[.]/g) || [''] - return label.replace(measurement, '') -} +import {removeMeasurement} from 'shared/graphs/helpers' const staticLegendItemClassname = (visibilities, i, hoverEnabled) => { if (visibilities.length) { @@ -29,10 +17,11 @@ const staticLegendItemClassname = (visibilities, i, hoverEnabled) => { class StaticLegend extends Component { constructor(props) { super(props) + } - this.state = { - visibilities: [], - } + state = { + visibilities: [], + clickStatus: false, } componentDidMount = () => { @@ -51,6 +40,7 @@ class StaticLegend extends Component { handleClick = i => e => { const visibilities = this.props.dygraph.visibility() + const clickStatus = this.state.clickStatus if (e.shiftKey || e.metaKey) { visibilities[i] = !visibilities[i] @@ -59,13 +49,19 @@ class StaticLegend extends Component { return } - const newVisibilities = visibilities[i] - ? _.map(visibilities, v => !v) + const prevClickStatus = clickStatus && visibilities[i] + + const newVisibilities = prevClickStatus + ? _.map(visibilities, () => true) : _.map(visibilities, () => false) + newVisibilities[i] = true this.props.dygraph.setVisibility(newVisibilities) - this.setState({visibilities: newVisibilities}) + this.setState({ + visibilities: newVisibilities, + clickStatus: !prevClickStatus, + }) } render() { @@ -74,9 +70,7 @@ class StaticLegend extends Component { const labels = dygraph ? _.drop(dygraph.getLabels()) : [] const colors = dygraph - ? _.map(labels, l => { - return dygraph.attributes_.series_[l].options.color - }) + ? _.map(labels, l => dygraph.attributes_.series_[l].options.color) : [] const hoverEnabled = labels.length > 1 diff --git a/ui/src/shared/constants/index.js b/ui/src/shared/constants/index.js index 966d14d3a8..968c74aad0 100644 --- a/ui/src/shared/constants/index.js +++ b/ui/src/shared/constants/index.js @@ -426,7 +426,7 @@ export const DEFAULT_SOURCE = { metaUrl: '', } -export const GET_STATIC_LEGEND = legend => +export const IS_STATIC_LEGEND = legend => _.get(legend, 'type', false) === 'static' export const linksLink = '/chronograf/v1' diff --git a/ui/src/shared/graphs/helpers.js b/ui/src/shared/graphs/helpers.js index 082f7e0493..85e5aa3b79 100644 --- a/ui/src/shared/graphs/helpers.js +++ b/ui/src/shared/graphs/helpers.js @@ -173,6 +173,12 @@ export const makeLegendStyles = (graph, legend, pageX) => { } } +// globally matches anything that ends in a '.' +export const removeMeasurement = (label = '') => { + const [measurement] = label.match(/^(.*)[.]/g) || [''] + return label.replace(measurement, '') +} + export const OPTIONS = { rightGap: 0, axisLineWidth: 2, diff --git a/ui/src/style/components/static-legend.scss b/ui/src/style/components/static-legend.scss index 504ca28332..a9600a11a5 100644 --- a/ui/src/style/components/static-legend.scss +++ b/ui/src/style/components/static-legend.scss @@ -6,7 +6,12 @@ */ .static-legend { + position: absolute; + width: calc(100% - 32px); + bottom: 8px; + left: 16px; display: flex; + padding-top: 8px; align-items: flex-end; flex-wrap: wrap; max-height: 50%; From 67d7eebb00012fc606cc1738bc78652ed9ac68c7 Mon Sep 17 00:00:00 2001 From: Deniz Kusefoglu Date: Tue, 27 Feb 2018 10:03:26 -0800 Subject: [PATCH 35/36] No style left behind --- ui/src/shared/components/StaticLegend.js | 1 - 1 file changed, 1 deletion(-) diff --git a/ui/src/shared/components/StaticLegend.js b/ui/src/shared/components/StaticLegend.js index 83eef81f5b..9751bf2dbd 100644 --- a/ui/src/shared/components/StaticLegend.js +++ b/ui/src/shared/components/StaticLegend.js @@ -78,7 +78,6 @@ class StaticLegend extends Component { return (
{ this.staticLegendRef = s }} From bda43293f6a63cf7c0b3c3dc99783280a36c14ee Mon Sep 17 00:00:00 2001 From: Deniz Kusefoglu Date: Tue, 27 Feb 2018 11:46:02 -0800 Subject: [PATCH 36/36] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5572eb3855..fb0d4ccfa4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## v1.4.2.0 [unreleased] ### Features 1. [#2837] (https://github.com/influxdata/chronograf/pull/2837): Prevent execution of queries in cells that are not in view on the dashboard page +1. [#2829] (https://github.com/influxdata/chronograf/pull/2829): Add an optional persistent legend which can toggle series visibility to dashboard cells ### UI Improvements 1. [#2848](https://github.com/influxdata/chronograf/pull/2848): Add ability to set a prefix and suffix on Single Stat and Gauge cell types 1. [#2831](https://github.com/influxdata/chronograf/pull/2831): Rename 'Create Alerts' page to 'Manage Tasks'; Redesign page to improve clarity of purpose