From f2238a9b92a1a19ca2022c1be3e5eef061046ccd Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Tue, 14 Mar 2017 11:35:16 -0600 Subject: Added the following ux improvements: * Add text for the buttons on environment detail page * Reduced the size of the charts * Environment name is now a link Also some general code cleanup --- .../javascripts/monitoring/prometheus_graph.js | 60 ++++++++++++---------- .../projects/environments/_external_url.html.haml | 1 + .../environments/_metrics_button.html.haml | 1 + app/views/projects/environments/metrics.html.haml | 3 +- app/views/projects/environments/show.html.haml | 4 +- 5 files changed, 39 insertions(+), 30 deletions(-) diff --git a/app/assets/javascripts/monitoring/prometheus_graph.js b/app/assets/javascripts/monitoring/prometheus_graph.js index 844a0785bc9..ce937fff9ad 100644 --- a/app/assets/javascripts/monitoring/prometheus_graph.js +++ b/app/assets/javascripts/monitoring/prometheus_graph.js @@ -1,4 +1,4 @@ -/* eslint-disable no-new*/ +/* eslint-disable no-new */ /* global Flash */ import d3 from 'd3'; @@ -21,9 +21,9 @@ class PrometheusGraph { const parentContainerWidth = $(prometheusGraphsContainer).parent().width() + extraAddedWidthParent; this.originalWidth = parentContainerWidth; - this.originalHeight = 400; + this.originalHeight = 330; this.width = parentContainerWidth - this.margin.left - this.margin.right; - this.height = 400 - this.margin.top - this.margin.bottom; + this.height = this.originalHeight - this.margin.top - this.margin.bottom; this.backOffRequestCounter = 0; this.configureGraph(); this.init(); @@ -49,13 +49,16 @@ class PrometheusGraph { }); } - plotValues(valuesToPlot, key) { + plotValues(key) { const x = d3.time.scale() .range([0, this.width]); const y = d3.scale.linear() .range([this.height, 0]); + this.graphSpecificProperties[key].xScale = x; + this.graphSpecificProperties[key].yScale = y; + const prometheusGraphContainer = `${prometheusGraphsContainer}[graph-type=${key}]`; const graphSpecifics = this.graphSpecificProperties[key]; @@ -67,13 +70,13 @@ class PrometheusGraph { .attr('transform', `translate(${this.margin.left},${this.margin.top})`); const axisLabelContainer = d3.select(prometheusGraphContainer) - .attr('width', this.originalWidth + this.marginLabelContainer.left + this.marginLabelContainer.right) - .attr('height', this.originalHeight + this.marginLabelContainer.bottom + this.marginLabelContainer.top) + .attr('width', this.originalWidth) + .attr('height', this.originalHeight) .append('g') .attr('transform', `translate(${this.marginLabelContainer.left},${this.marginLabelContainer.top})`); - x.domain(d3.extent(valuesToPlot, d => d.time)); - y.domain([0, d3.max(valuesToPlot.map(metricValue => metricValue.value))]); + x.domain(d3.extent(graphSpecifics.data, d => d.time)); + y.domain([0, d3.max(graphSpecifics.data.map(metricValue => metricValue.value))]); const xAxis = d3.svg.axis() .scale(x) @@ -108,13 +111,13 @@ class PrometheusGraph { .y(d => y(d.value)); chart.append('path') - .datum(valuesToPlot) + .datum(graphSpecifics.data) .attr('d', area) .attr('class', 'metric-area') .attr('fill', graphSpecifics.area_fill_color); chart.append('path') - .datum(valuesToPlot) + .datum(graphSpecifics.data) .attr('class', 'metric-line') .attr('stroke', graphSpecifics.line_color) .attr('fill', 'none') @@ -126,7 +129,7 @@ class PrometheusGraph { .attr('class', 'prometheus-graph-overlay') .attr('width', this.width) .attr('height', this.height) - .on('mousemove', this.handleMouseOverGraph.bind(this, x, y, valuesToPlot, chart, prometheusGraphContainer, key)); + .on('mousemove', this.handleMouseOverGraph.bind(this, x, y, chart, prometheusGraphContainer, key)); } // The legends from the metric @@ -139,9 +142,9 @@ class PrometheusGraph { .attr('stroke-width', '1') .attr({ x1: 0, - y1: this.originalHeight - this.marginLabelContainer.top, + y1: this.originalHeight - 80, x2: this.originalWidth - this.margin.right, - y2: this.originalHeight - this.marginLabelContainer.top, + y2: this.originalHeight - 80, }); axisLabelContainer.append('line') @@ -152,26 +155,26 @@ class PrometheusGraph { x1: 0, y1: 0, x2: 0, - y2: this.originalHeight - this.marginLabelContainer.top, + y2: this.originalHeight - 80, }); axisLabelContainer.append('text') .attr('class', 'label-axis-text') .attr('text-anchor', 'middle') - .attr('transform', `translate(15, ${(this.originalHeight - this.marginLabelContainer.top) / 2}) rotate(-90)`) + .attr('transform', `translate(15, ${(this.originalHeight - 80) / 2}) rotate(-90)`) .text(graphSpecifics.graph_legend_title); axisLabelContainer.append('rect') .attr('class', 'rect-axis-text') .attr('x', (this.originalWidth / 2) - this.margin.right) - .attr('y', this.originalHeight - this.marginLabelContainer.top - 20) + .attr('y', this.originalHeight - 100) .attr('width', 30) .attr('height', 80); axisLabelContainer.append('text') .attr('class', 'label-axis-text') .attr('x', (this.originalWidth / 2) - this.margin.right) - .attr('y', this.originalHeight - this.marginLabelContainer.top) + .attr('y', this.originalHeight - 80) .attr('dy', '.35em') .text('Time'); @@ -197,16 +200,18 @@ class PrometheusGraph { .attr('y', (this.originalHeight / 2) - 25); } - handleMouseOverGraph(x, y, valuesToPlot, chart, prometheusGraphContainer, key) { + handleMouseOverGraph(x, y, chart, prometheusGraphContainer, key) { + const graphSpecifics = this.graphSpecificProperties[key]; const rectOverlay = document.querySelector(`${prometheusGraphContainer} .prometheus-graph-overlay`); - const timeValueFromOverlay = x.invert(d3.mouse(rectOverlay)[0]); - const timeValueIndex = bisectDate(valuesToPlot, timeValueFromOverlay, 1); - const d0 = valuesToPlot[timeValueIndex - 1]; - const d1 = valuesToPlot[timeValueIndex]; + const mouseCoordOverlay = d3.mouse(rectOverlay)[0]; + const timeValueFromOverlay = x.invert(mouseCoordOverlay); + const timeValueIndex = bisectDate(graphSpecifics.data, timeValueFromOverlay, 1); + const d0 = graphSpecifics.data[timeValueIndex - 1]; + const d1 = graphSpecifics.data[timeValueIndex]; const currentData = timeValueFromOverlay - d0.time > d1.time - timeValueFromOverlay ? d1 : d0; - const maxValueMetric = y(d3.max(valuesToPlot.map(metricValue => metricValue.value))); + const maxValueMetric = y(d3.max(graphSpecifics.data.map(metricValue => metricValue.value))); const currentTimeCoordinate = x(currentData.time); - const graphSpecifics = this.graphSpecificProperties[key]; + // Remove the current selectors d3.selectAll(`${prometheusGraphContainer} .selected-metric-line`).remove(); d3.selectAll(`${prometheusGraphContainer} .circle-metric`).remove(); @@ -263,12 +268,14 @@ class PrometheusGraph { cpu_values: { area_fill_color: '#edf3fc', line_color: '#5b99f7', - graph_legend_title: 'CPU utilization (%)', + graph_legend_title: 'CPU Usage (Cores)', + data: [], }, memory_values: { area_fill_color: '#fca326', line_color: '#fc6d26', - graph_legend_title: 'Memory usage (MB)', + graph_legend_title: 'Memory Usage (MB)', + data: [], }, }; @@ -328,7 +335,6 @@ class PrometheusGraph { })); } }); - this.data = metricTypes; } } diff --git a/app/views/projects/environments/_external_url.html.haml b/app/views/projects/environments/_external_url.html.haml index bf0f1819073..a82ef5ee5bb 100644 --- a/app/views/projects/environments/_external_url.html.haml +++ b/app/views/projects/environments/_external_url.html.haml @@ -1,3 +1,4 @@ - if environment.external_url && can?(current_user, :read_environment, environment) = link_to environment.external_url, target: '_blank', rel: 'noopener noreferrer', class: 'btn external-url' do = icon('external-link') + View deployment diff --git a/app/views/projects/environments/_metrics_button.html.haml b/app/views/projects/environments/_metrics_button.html.haml index acbac1869fd..e27281d6917 100644 --- a/app/views/projects/environments/_metrics_button.html.haml +++ b/app/views/projects/environments/_metrics_button.html.haml @@ -4,3 +4,4 @@ = link_to environment_metrics_path(environment), title: 'See metrics', class: 'btn metrics-button' do = icon('area-chart') + Monitoring diff --git a/app/views/projects/environments/metrics.html.haml b/app/views/projects/environments/metrics.html.haml index 3b45162df52..5627192c36c 100644 --- a/app/views/projects/environments/metrics.html.haml +++ b/app/views/projects/environments/metrics.html.haml @@ -11,7 +11,8 @@ .col-sm-6 %h3.page-title Environment: - = @environment.name + = link_to environment_path(@environment) do + = @environment.name .col-sm-6 .nav-controls diff --git a/app/views/projects/environments/show.html.haml b/app/views/projects/environments/show.html.haml index f463a429f65..ff6aaebda22 100644 --- a/app/views/projects/environments/show.html.haml +++ b/app/views/projects/environments/show.html.haml @@ -4,9 +4,9 @@ %div{ class: container_class } .top-area.adjust - .col-md-9 + .col-md-7 %h3.page-title= @environment.name - .col-md-3 + .col-md-5 .nav-controls = render 'projects/environments/metrics_button', environment: @environment = render 'projects/environments/terminal_button', environment: @environment -- cgit v1.2.1 From df3c8345a8c17643800a34c960529a2d89d74b27 Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Tue, 21 Mar 2017 10:51:23 -0600 Subject: Readded missing statement from the rebase --- app/assets/javascripts/monitoring/prometheus_graph.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/javascripts/monitoring/prometheus_graph.js b/app/assets/javascripts/monitoring/prometheus_graph.js index ce937fff9ad..2c38f0038f0 100644 --- a/app/assets/javascripts/monitoring/prometheus_graph.js +++ b/app/assets/javascripts/monitoring/prometheus_graph.js @@ -335,6 +335,7 @@ class PrometheusGraph { })); } }); + this.data = metricTypes; } } -- cgit v1.2.1 From b076d03424179aca6e544223b831010ae01fdd33 Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Tue, 21 Mar 2017 15:57:52 -0600 Subject: Hover lines are now synced up when hovering in any graph Cleaned up some code --- app/assets/javascripts/dispatcher.js | 1 + .../javascripts/monitoring/prometheus_graph.js | 142 +++++++++++---------- 2 files changed, 76 insertions(+), 67 deletions(-) diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js index 80490052389..cd83a2730dc 100644 --- a/app/assets/javascripts/dispatcher.js +++ b/app/assets/javascripts/dispatcher.js @@ -43,6 +43,7 @@ import GroupsList from './groups_list'; import ProjectsList from './projects_list'; import MiniPipelineGraph from './mini_pipeline_graph_dropdown'; import BlobLinePermalinkUpdater from './blob/blob_line_permalink_updater'; +import PrometheusGraph from './monitoring/prometheus_graph'; import UserCallout from './user_callout'; const ShortcutsBlob = require('./shortcuts_blob'); diff --git a/app/assets/javascripts/monitoring/prometheus_graph.js b/app/assets/javascripts/monitoring/prometheus_graph.js index 2c38f0038f0..0fdeed9ccbd 100644 --- a/app/assets/javascripts/monitoring/prometheus_graph.js +++ b/app/assets/javascripts/monitoring/prometheus_graph.js @@ -30,10 +30,10 @@ class PrometheusGraph { } createGraph() { - Object.keys(this.data).forEach((key) => { - const value = this.data[key]; - if (value.length > 0) { - this.plotValues(value, key); + Object.keys(this.graphSpecificProperties).forEach((key) => { + const value = this.graphSpecificProperties[key]; + if (value.data.length > 0) { + this.plotValues(key); } }); } @@ -129,7 +129,7 @@ class PrometheusGraph { .attr('class', 'prometheus-graph-overlay') .attr('width', this.width) .attr('height', this.height) - .on('mousemove', this.handleMouseOverGraph.bind(this, x, y, chart, prometheusGraphContainer, key)); + .on('mousemove', this.handleMouseOverGraph.bind(this, chart, prometheusGraphContainer)); } // The legends from the metric @@ -200,67 +200,73 @@ class PrometheusGraph { .attr('y', (this.originalHeight / 2) - 25); } - handleMouseOverGraph(x, y, chart, prometheusGraphContainer, key) { - const graphSpecifics = this.graphSpecificProperties[key]; + handleMouseOverGraph(chart, prometheusGraphContainer) { const rectOverlay = document.querySelector(`${prometheusGraphContainer} .prometheus-graph-overlay`); - const mouseCoordOverlay = d3.mouse(rectOverlay)[0]; - const timeValueFromOverlay = x.invert(mouseCoordOverlay); - const timeValueIndex = bisectDate(graphSpecifics.data, timeValueFromOverlay, 1); - const d0 = graphSpecifics.data[timeValueIndex - 1]; - const d1 = graphSpecifics.data[timeValueIndex]; - const currentData = timeValueFromOverlay - d0.time > d1.time - timeValueFromOverlay ? d1 : d0; - const maxValueMetric = y(d3.max(graphSpecifics.data.map(metricValue => metricValue.value))); - const currentTimeCoordinate = x(currentData.time); - - // Remove the current selectors - d3.selectAll(`${prometheusGraphContainer} .selected-metric-line`).remove(); - d3.selectAll(`${prometheusGraphContainer} .circle-metric`).remove(); - d3.selectAll(`${prometheusGraphContainer} .rect-text-metric`).remove(); - d3.selectAll(`${prometheusGraphContainer} .text-metric`).remove(); - - chart.append('line') - .attr('class', 'selected-metric-line') - .attr({ - x1: currentTimeCoordinate, - y1: y(0), - x2: currentTimeCoordinate, - y2: maxValueMetric, - }); - - chart.append('circle') - .attr('class', 'circle-metric') - .attr('fill', graphSpecifics.line_color) - .attr('cx', currentTimeCoordinate) - .attr('cy', y(currentData.value)) - .attr('r', this.commonGraphProperties.circle_radius_metric); - - // The little box with text - const rectTextMetric = chart.append('g') - .attr('class', 'rect-text-metric') - .attr('translate', `(${currentTimeCoordinate}, ${y(currentData.value)})`); - - rectTextMetric.append('rect') - .attr('class', 'rect-metric') - .attr('x', currentTimeCoordinate + 10) - .attr('y', maxValueMetric) - .attr('width', this.commonGraphProperties.rect_text_width) - .attr('height', this.commonGraphProperties.rect_text_height); - - rectTextMetric.append('text') - .attr('class', 'text-metric') - .attr('x', currentTimeCoordinate + 35) - .attr('y', maxValueMetric + 35) - .text(timeFormat(currentData.time)); - - rectTextMetric.append('text') - .attr('class', 'text-metric-date') - .attr('x', currentTimeCoordinate + 15) - .attr('y', maxValueMetric + 15) - .text(dayFormat(currentData.time)); - - // Update the text - d3.select(`${prometheusGraphContainer} .text-metric-usage`) + const currentXCoordinate = d3.mouse(rectOverlay)[0]; + + Object.keys(this.graphSpecificProperties).forEach((key) => { + const currentGraphProps = this.graphSpecificProperties[key]; + const timeValueOverlay = currentGraphProps.xScale.invert(currentXCoordinate); + const overlayIndex = bisectDate(currentGraphProps.data, timeValueOverlay, 1); + const d0 = currentGraphProps.data[overlayIndex - 1]; + const d1 = currentGraphProps.data[overlayIndex]; + const evalTime = timeValueOverlay - d0.time > d1.time - timeValueOverlay; + const currentData = evalTime ? d1 : d0; + const currentTimeCoordinate = currentGraphProps.xScale(currentData.time); + const currentPrometheusGraphContainer = `${prometheusGraphsContainer}[graph-type=${key}]`; + const maxValueFromData = d3.max(currentGraphProps.data.map(metricValue => metricValue.value)); + const maxMetricValue = currentGraphProps.yScale(maxValueFromData); + + // Clear up all the pieces of the flag + d3.selectAll(`${currentPrometheusGraphContainer} .selected-metric-line`).remove(); + d3.selectAll(`${currentPrometheusGraphContainer} .circle-metric`).remove(); + d3.selectAll(`${currentPrometheusGraphContainer} .rect-text-metric`).remove(); + d3.selectAll(`${currentPrometheusGraphContainer} .text-metric`).remove(); + + const currentChart = d3.select(currentPrometheusGraphContainer).select('g'); + currentChart.append('line') + .attr('class', 'selected-metric-line') + .attr({ + x1: currentTimeCoordinate, + y1: currentGraphProps.yScale(0), + x2: currentTimeCoordinate, + y2: maxMetricValue, + }); + + currentChart.append('circle') + .attr('class', 'circle-metric') + .attr('fill', currentGraphProps.line_color) + .attr('cx', currentTimeCoordinate) + .attr('cy', currentGraphProps.yScale(currentData.value)) + .attr('r', this.commonGraphProperties.circle_radius_metric); + + // The little box with text + const rectTextMetric = currentChart.append('g') + .attr('class', 'rect-text-metric') + .attr('translate', `(${currentTimeCoordinate}, ${currentGraphProps.yScale(currentData.value)})`); + + rectTextMetric.append('rect') + .attr('class', 'rect-metric') + .attr('x', currentTimeCoordinate + 10) + .attr('y', maxMetricValue) + .attr('width', this.commonGraphProperties.rect_text_width) + .attr('height', this.commonGraphProperties.rect_text_height); + + rectTextMetric.append('text') + .attr('class', 'text-metric') + .attr('x', currentTimeCoordinate + 35) + .attr('y', maxMetricValue + 35) + .text(timeFormat(currentData.time)); + + rectTextMetric.append('text') + .attr('class', 'text-metric-date') + .attr('x', currentTimeCoordinate + 15) + .attr('y', maxMetricValue + 15) + .text(dayFormat(currentData.time)); + + d3.select(`${currentPrometheusGraphContainer} .text-metric-usage`) .text(currentData.value.substring(0, 8)); + }); } configureGraph() { @@ -270,12 +276,16 @@ class PrometheusGraph { line_color: '#5b99f7', graph_legend_title: 'CPU Usage (Cores)', data: [], + xScale: {}, + yScale: {}, }, memory_values: { area_fill_color: '#fca326', line_color: '#fc6d26', graph_legend_title: 'Memory Usage (MB)', data: [], + xScale: {}, + yScale: {}, }, }; @@ -325,17 +335,15 @@ class PrometheusGraph { } transformData(metricsResponse) { - const metricTypes = {}; Object.keys(metricsResponse.metrics).forEach((key) => { if (key === 'cpu_values' || key === 'memory_values') { const metricValues = (metricsResponse.metrics[key])[0]; - metricTypes[key] = metricValues.values.map(metric => ({ + this.graphSpecificProperties[key].data = metricValues.values.map(metric => ({ time: new Date(metric[0] * 1000), value: metric[1], })); } }); - this.data = metricTypes; } } -- cgit v1.2.1 From 5b0890edcc0af98378e62e6998d3e51378b01900 Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Tue, 21 Mar 2017 16:40:15 -0600 Subject: Legend text is now bolded also the Y legend text has a transparent background to help differentiate legends --- .../javascripts/monitoring/prometheus_graph.js | 20 +++++++++++++------- app/assets/stylesheets/pages/environments.scss | 10 +++++++++- 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/monitoring/prometheus_graph.js b/app/assets/javascripts/monitoring/prometheus_graph.js index 0fdeed9ccbd..04298fccd97 100644 --- a/app/assets/javascripts/monitoring/prometheus_graph.js +++ b/app/assets/javascripts/monitoring/prometheus_graph.js @@ -129,7 +129,7 @@ class PrometheusGraph { .attr('class', 'prometheus-graph-overlay') .attr('width', this.width) .attr('height', this.height) - .on('mousemove', this.handleMouseOverGraph.bind(this, chart, prometheusGraphContainer)); + .on('mousemove', this.handleMouseOverGraph.bind(this, prometheusGraphContainer)); } // The legends from the metric @@ -141,9 +141,9 @@ class PrometheusGraph { .attr('stroke', '#000000') .attr('stroke-width', '1') .attr({ - x1: 0, + x1: 10, y1: this.originalHeight - 80, - x2: this.originalWidth - this.margin.right, + x2: (this.originalWidth - this.margin.right) + 10, y2: this.originalHeight - 80, }); @@ -152,11 +152,17 @@ class PrometheusGraph { .attr('stroke', '#000000') .attr('stroke-width', '1') .attr({ - x1: 0, + x1: 10, y1: 0, - x2: 0, + x2: 10, y2: this.originalHeight - 80, }); + axisLabelContainer.append('rect') + .attr('class', 'rect-axis-text') + .attr('x', 0) + .attr('y', 50) + .attr('width', 30) + .attr('height', 150); axisLabelContainer.append('text') .attr('class', 'label-axis-text') @@ -189,7 +195,7 @@ class PrometheusGraph { .attr('height', 35); axisLabelContainer.append('text') - .attr('class', 'label-axis-text') + .attr('class', 'text-metric-title') .attr('x', this.originalWidth - 140) .attr('y', (this.originalHeight / 2) - 50) .text('Average'); @@ -200,7 +206,7 @@ class PrometheusGraph { .attr('y', (this.originalHeight / 2) - 25); } - handleMouseOverGraph(chart, prometheusGraphContainer) { + handleMouseOverGraph(prometheusGraphContainer) { const rectOverlay = document.querySelector(`${prometheusGraphContainer} .prometheus-graph-overlay`); const currentXCoordinate = d3.mouse(rectOverlay)[0]; diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss index 3d91e0b22d8..b55fa185406 100644 --- a/app/assets/stylesheets/pages/environments.scss +++ b/app/assets/stylesheets/pages/environments.scss @@ -159,11 +159,19 @@ text { fill: $stat-graph-axis-fill; } + .label-axis-text, + .text-metric-usage { + fill: $black; + font-weight: 500; + } + .legend-axis-text{ + fill: $black; + } } .x-axis path, .y-axis path, -.label-x-axis-line, +.x-axis-line, .label-y-axis-line { fill: none; stroke-width: 1; -- cgit v1.2.1 From 8efd23015d3321824c12df1e3d3ed87674f8cd4d Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Wed, 22 Mar 2017 17:58:57 -0600 Subject: Fixed prometheus_graph_spec.js and scss-linters --- app/assets/stylesheets/pages/environments.scss | 6 ++++-- spec/javascripts/monitoring/prometheus_graph_spec.js | 10 ++++++---- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/app/assets/stylesheets/pages/environments.scss b/app/assets/stylesheets/pages/environments.scss index b55fa185406..6faa3794c83 100644 --- a/app/assets/stylesheets/pages/environments.scss +++ b/app/assets/stylesheets/pages/environments.scss @@ -159,19 +159,21 @@ text { fill: $stat-graph-axis-fill; } + .label-axis-text, .text-metric-usage { fill: $black; font-weight: 500; } - .legend-axis-text{ + + .legend-axis-text { fill: $black; } } .x-axis path, .y-axis path, -.x-axis-line, +.label-x-axis-line, .label-y-axis-line { fill: none; stroke-width: 1; diff --git a/spec/javascripts/monitoring/prometheus_graph_spec.js b/spec/javascripts/monitoring/prometheus_graph_spec.js index a3c1c5e1b7c..c2bcd9c0f7c 100644 --- a/spec/javascripts/monitoring/prometheus_graph_spec.js +++ b/spec/javascripts/monitoring/prometheus_graph_spec.js @@ -37,9 +37,11 @@ describe('PrometheusGraph', () => { it('transforms the data', () => { this.prometheusGraph.init(prometheusMockData.metrics); - expect(this.prometheusGraph.data).toBeDefined(); - expect(this.prometheusGraph.data.cpu_values.length).toBe(121); - expect(this.prometheusGraph.data.memory_values.length).toBe(121); + Object.keys(this.prometheusGraph.graphSpecificProperties, (key) => { + const graphProps = this.prometheusGraph.graphSpecificProperties[key]; + expect(graphProps.data).toBeDefined(); + expect(graphProps.data.length).toBe(121); + }); }); it('creates two graphs', () => { @@ -68,7 +70,7 @@ describe('PrometheusGraph', () => { expect($prometheusGraphContents.find('.label-y-axis-line')).toBeDefined(); expect($prometheusGraphContents.find('.label-axis-text')).toBeDefined(); expect($prometheusGraphContents.find('.rect-axis-text')).toBeDefined(); - expect($axisLabelContainer.find('rect').length).toBe(2); + expect($axisLabelContainer.find('rect').length).toBe(3); expect($axisLabelContainer.find('text').length).toBe(4); }); }); -- cgit v1.2.1 From 902d2600d7e862966229a89c34a1a89136580fa4 Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Fri, 24 Mar 2017 15:30:10 -0600 Subject: Added a number input to provide a way to format the number of desired decimals for the cpu metrics --- app/assets/javascripts/dispatcher.js | 1 - .../javascripts/monitoring/prometheus_graph.js | 20 +++++++++++++++----- app/views/projects/environments/metrics.html.haml | 12 ++++++++++-- 3 files changed, 25 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js index cd83a2730dc..80490052389 100644 --- a/app/assets/javascripts/dispatcher.js +++ b/app/assets/javascripts/dispatcher.js @@ -43,7 +43,6 @@ import GroupsList from './groups_list'; import ProjectsList from './projects_list'; import MiniPipelineGraph from './mini_pipeline_graph_dropdown'; import BlobLinePermalinkUpdater from './blob/blob_line_permalink_updater'; -import PrometheusGraph from './monitoring/prometheus_graph'; import UserCallout from './user_callout'; const ShortcutsBlob = require('./shortcuts_blob'); diff --git a/app/assets/javascripts/monitoring/prometheus_graph.js b/app/assets/javascripts/monitoring/prometheus_graph.js index 04298fccd97..17b704e192a 100644 --- a/app/assets/javascripts/monitoring/prometheus_graph.js +++ b/app/assets/javascripts/monitoring/prometheus_graph.js @@ -25,6 +25,7 @@ class PrometheusGraph { this.width = parentContainerWidth - this.margin.left - this.margin.right; this.height = this.originalHeight - this.margin.top - this.margin.bottom; this.backOffRequestCounter = 0; + this.cpuNumberFormatInput = $('input[graph-type="cpu_values"]'); this.configureGraph(); this.init(); } @@ -270,8 +271,15 @@ class PrometheusGraph { .attr('y', maxMetricValue + 15) .text(dayFormat(currentData.time)); + let currentMetricValue = currentData.value; + if (key === 'cpu_values') { + currentMetricValue = Number(currentMetricValue).toFixed(this.cpuNumberFormatInput.val()); + currentMetricValue = `${currentMetricValue}%`; + } else { + currentMetricValue = currentMetricValue.substring(0, 8); + } d3.select(`${currentPrometheusGraphContainer} .text-metric-usage`) - .text(currentData.value.substring(0, 8)); + .text(currentMetricValue); }); } @@ -344,10 +352,12 @@ class PrometheusGraph { Object.keys(metricsResponse.metrics).forEach((key) => { if (key === 'cpu_values' || key === 'memory_values') { const metricValues = (metricsResponse.metrics[key])[0]; - this.graphSpecificProperties[key].data = metricValues.values.map(metric => ({ - time: new Date(metric[0] * 1000), - value: metric[1], - })); + if (typeof metricValues !== 'undefined') { + this.graphSpecificProperties[key].data = metricValues.values.map(metric => ({ + time: new Date(metric[0] * 1000), + value: metric[1], + })); + } } }); } diff --git a/app/views/projects/environments/metrics.html.haml b/app/views/projects/environments/metrics.html.haml index 5627192c36c..cfff0428fbd 100644 --- a/app/views/projects/environments/metrics.html.haml +++ b/app/views/projects/environments/metrics.html.haml @@ -19,8 +19,16 @@ = render 'projects/deployments/actions', deployment: @environment.last_deployment .row .col-sm-12 - %h4 - CPU utilization + .row + .col-sm-10 + %h4 + CPU utilization + .col-sm-2.form-horizontal + .form-group + %label{ for: 'decimal_format', class:'control-label col-sm-6' } + Format + .col-sm-6 + %input.form-control{ name: 'decimal_format', type: 'number', value: '4', 'graph-type': 'cpu_values', min: '1' } %svg.prometheus-graph{ 'graph-type' => 'cpu_values' } .row .col-sm-12 -- cgit v1.2.1 From dff378d7fe1d8a66c60abb50ebe6d297e09b8820 Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Tue, 28 Mar 2017 09:55:08 -0600 Subject: Added CHANGELOG --- changelogs/unreleased/environment-performance-improvements.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelogs/unreleased/environment-performance-improvements.yml diff --git a/changelogs/unreleased/environment-performance-improvements.yml b/changelogs/unreleased/environment-performance-improvements.yml new file mode 100644 index 00000000000..43e8f0afcee --- /dev/null +++ b/changelogs/unreleased/environment-performance-improvements.yml @@ -0,0 +1,4 @@ +--- +title: Improved UX for the environments metrics view +merge_request: 9946 +author: -- cgit v1.2.1 From b4795830026fc1fd361e2dace64a70abeb0cd7ae Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Tue, 28 Mar 2017 13:00:00 -0600 Subject: Added a formatRelevantDigits text utility --- app/assets/javascripts/lib/utils/text_utility.js | 24 ++++++++++++++++++++ .../javascripts/monitoring/prometheus_graph.js | 6 ++--- app/views/projects/environments/metrics.html.haml | 12 ++-------- spec/javascripts/lib/utils/text_utility_spec.js | 26 ++++++++++++++++++++++ 4 files changed, 54 insertions(+), 14 deletions(-) diff --git a/app/assets/javascripts/lib/utils/text_utility.js b/app/assets/javascripts/lib/utils/text_utility.js index 2e5f8a09fc1..2b135b4f96f 100644 --- a/app/assets/javascripts/lib/utils/text_utility.js +++ b/app/assets/javascripts/lib/utils/text_utility.js @@ -188,5 +188,29 @@ require('vendor/latinise'); gl.text.slugify = function(str) { return str.trim().toLowerCase().latinise(); }; + gl.text.formatRelevantDigits = function(number) { + var digitsLeft = ''; + var relevantDigits = 0; + if (isNaN(Number(number))) { + return 0; + } else { + digitsLeft = number.split('.')[0]; + switch (digitsLeft.length) { + case 1: + relevantDigits = 3; + break; + case 2: + relevantDigits = 2; + break; + case 3: + relevantDigits = 1; + break; + default: + relevantDigits = 4; + break; + } + return Number(number).toFixed(relevantDigits); + } + }; })(window); }).call(window); diff --git a/app/assets/javascripts/monitoring/prometheus_graph.js b/app/assets/javascripts/monitoring/prometheus_graph.js index 17b704e192a..eb9e93dba09 100644 --- a/app/assets/javascripts/monitoring/prometheus_graph.js +++ b/app/assets/javascripts/monitoring/prometheus_graph.js @@ -25,7 +25,6 @@ class PrometheusGraph { this.width = parentContainerWidth - this.margin.left - this.margin.right; this.height = this.originalHeight - this.margin.top - this.margin.bottom; this.backOffRequestCounter = 0; - this.cpuNumberFormatInput = $('input[graph-type="cpu_values"]'); this.configureGraph(); this.init(); } @@ -271,12 +270,11 @@ class PrometheusGraph { .attr('y', maxMetricValue + 15) .text(dayFormat(currentData.time)); - let currentMetricValue = currentData.value; + let currentMetricValue = gl.text.formatRelevantDigits(currentData.value); if (key === 'cpu_values') { - currentMetricValue = Number(currentMetricValue).toFixed(this.cpuNumberFormatInput.val()); currentMetricValue = `${currentMetricValue}%`; } else { - currentMetricValue = currentMetricValue.substring(0, 8); + currentMetricValue = `${currentMetricValue} MB`; } d3.select(`${currentPrometheusGraphContainer} .text-metric-usage`) .text(currentMetricValue); diff --git a/app/views/projects/environments/metrics.html.haml b/app/views/projects/environments/metrics.html.haml index cfff0428fbd..5627192c36c 100644 --- a/app/views/projects/environments/metrics.html.haml +++ b/app/views/projects/environments/metrics.html.haml @@ -19,16 +19,8 @@ = render 'projects/deployments/actions', deployment: @environment.last_deployment .row .col-sm-12 - .row - .col-sm-10 - %h4 - CPU utilization - .col-sm-2.form-horizontal - .form-group - %label{ for: 'decimal_format', class:'control-label col-sm-6' } - Format - .col-sm-6 - %input.form-control{ name: 'decimal_format', type: 'number', value: '4', 'graph-type': 'cpu_values', min: '1' } + %h4 + CPU utilization %svg.prometheus-graph{ 'graph-type' => 'cpu_values' } .row .col-sm-12 diff --git a/spec/javascripts/lib/utils/text_utility_spec.js b/spec/javascripts/lib/utils/text_utility_spec.js index 4200e943121..3d0e92ed240 100644 --- a/spec/javascripts/lib/utils/text_utility_spec.js +++ b/spec/javascripts/lib/utils/text_utility_spec.js @@ -105,6 +105,32 @@ require('~/lib/utils/text_utility'); expect(textArea.value).toEqual(`${initialValue}* `); }); }); + + describe('gl.text.formatRelevantDigits', () => { + it('returns 0 when the number is NaN', () => { + expect(gl.text.formatRelevantDigits('fail')).toBe(0); + }); + + it('returns 4 decimals when there is 4 plus digits to the left', () => { + const formattedNumber = gl.text.formatRelevantDigits('1000.1234567').split('.')[1]; + expect(formattedNumber.length).toBe(4); + }); + + it('returns 3 decimals when there is 1 digit to the left', () => { + const formattedNumber = gl.text.formatRelevantDigits('0.1234567').split('.')[1]; + expect(formattedNumber.length).toBe(3); + }); + + it('returns 2 decimals when there is 2 digits to the left', () => { + const formattedNumber = gl.text.formatRelevantDigits('10.1234567').split('.')[1]; + expect(formattedNumber.length).toBe(2); + }); + + it('returns 1 decimal when there is 3 digits to the left', () => { + const formattedNumber = gl.text.formatRelevantDigits('100.1234567').split('.')[1]; + expect(formattedNumber.length).toBe(1); + }); + }); }); }); })(); -- cgit v1.2.1 From d745876e23e48e7fdf1b569c7e10dd4e2ca2734a Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Wed, 29 Mar 2017 10:10:30 -0600 Subject: Code corrections with a helper and a variable --- app/assets/javascripts/monitoring/prometheus_graph.js | 18 +++++++++--------- app/views/projects/environments/metrics.html.haml | 3 +-- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/app/assets/javascripts/monitoring/prometheus_graph.js b/app/assets/javascripts/monitoring/prometheus_graph.js index eb9e93dba09..a7608468a97 100644 --- a/app/assets/javascripts/monitoring/prometheus_graph.js +++ b/app/assets/javascripts/monitoring/prometheus_graph.js @@ -50,19 +50,19 @@ class PrometheusGraph { } plotValues(key) { + const graphSpecifics = this.graphSpecificProperties[key]; + const x = d3.time.scale() .range([0, this.width]); const y = d3.scale.linear() .range([this.height, 0]); - this.graphSpecificProperties[key].xScale = x; - this.graphSpecificProperties[key].yScale = y; + graphSpecifics.xScale = x; + graphSpecifics.yScale = y; const prometheusGraphContainer = `${prometheusGraphsContainer}[graph-type=${key}]`; - const graphSpecifics = this.graphSpecificProperties[key]; - const chart = d3.select(prometheusGraphContainer) .attr('width', this.width + this.margin.left + this.margin.right) .attr('height', this.height + this.margin.bottom + this.margin.top) @@ -142,9 +142,9 @@ class PrometheusGraph { .attr('stroke-width', '1') .attr({ x1: 10, - y1: this.originalHeight - 80, + y1: this.originalHeight - this.margin.top, x2: (this.originalWidth - this.margin.right) + 10, - y2: this.originalHeight - 80, + y2: this.originalHeight - this.margin.top, }); axisLabelContainer.append('line') @@ -155,7 +155,7 @@ class PrometheusGraph { x1: 10, y1: 0, x2: 10, - y2: this.originalHeight - 80, + y2: this.originalHeight - this.margin.top, }); axisLabelContainer.append('rect') .attr('class', 'rect-axis-text') @@ -167,7 +167,7 @@ class PrometheusGraph { axisLabelContainer.append('text') .attr('class', 'label-axis-text') .attr('text-anchor', 'middle') - .attr('transform', `translate(15, ${(this.originalHeight - 80) / 2}) rotate(-90)`) + .attr('transform', `translate(15, ${(this.originalHeight - this.margin.top) / 2}) rotate(-90)`) .text(graphSpecifics.graph_legend_title); axisLabelContainer.append('rect') @@ -180,7 +180,7 @@ class PrometheusGraph { axisLabelContainer.append('text') .attr('class', 'label-axis-text') .attr('x', (this.originalWidth / 2) - this.margin.right) - .attr('y', this.originalHeight - 80) + .attr('y', this.originalHeight - this.margin.top) .attr('dy', '.35em') .text('Time'); diff --git a/app/views/projects/environments/metrics.html.haml b/app/views/projects/environments/metrics.html.haml index 5627192c36c..92dc58cd38d 100644 --- a/app/views/projects/environments/metrics.html.haml +++ b/app/views/projects/environments/metrics.html.haml @@ -11,8 +11,7 @@ .col-sm-6 %h3.page-title Environment: - = link_to environment_path(@environment) do - = @environment.name + = link_to @environment.name, environment_path(@environment) .col-sm-6 .nav-controls -- cgit v1.2.1 From 3069a2c959fcdf05b95a5c0893d4c31e10950a01 Mon Sep 17 00:00:00 2001 From: Jose Ivan Vargas Date: Mon, 3 Apr 2017 10:37:08 -0500 Subject: Removed formatRelevantDigits from text_utils.js and added it to a new file number_utils.js Also improved code formatting --- app/assets/javascripts/lib/utils/number_utils.js | 34 ++++ app/assets/javascripts/lib/utils/text_utility.js | 24 --- .../javascripts/monitoring/prometheus_graph.js | 186 +++++++++++---------- spec/javascripts/lib/utils/number_utility_spec.js | 41 +++++ spec/javascripts/lib/utils/text_utility_spec.js | 26 --- 5 files changed, 169 insertions(+), 142 deletions(-) create mode 100644 app/assets/javascripts/lib/utils/number_utils.js create mode 100644 spec/javascripts/lib/utils/number_utility_spec.js diff --git a/app/assets/javascripts/lib/utils/number_utils.js b/app/assets/javascripts/lib/utils/number_utils.js new file mode 100644 index 00000000000..e2bf69ee52e --- /dev/null +++ b/app/assets/javascripts/lib/utils/number_utils.js @@ -0,0 +1,34 @@ +/* eslint-disable import/prefer-default-export */ + +/** + * Function that allows a number with an X amount of decimals + * to be formatted in the following fashion: + * * For 1 digit to the left of the decimal point and X digits to the right of it + * * * Show 3 digits to the right + * * For 2 digits to the left of the decimal point and X digits to the right of it + * * * Show 2 digits to the right +*/ +export function formatRelevantDigits(number) { + let digitsLeft = ''; + let relevantDigits = 0; + let formattedNumber = ''; + if (!isNaN(Number(number))) { + digitsLeft = number.split('.')[0]; + switch (digitsLeft.length) { + case 1: + relevantDigits = 3; + break; + case 2: + relevantDigits = 2; + break; + case 3: + relevantDigits = 1; + break; + default: + relevantDigits = 4; + break; + } + formattedNumber = Number(number).toFixed(relevantDigits); + } + return formattedNumber; +} diff --git a/app/assets/javascripts/lib/utils/text_utility.js b/app/assets/javascripts/lib/utils/text_utility.js index 2b135b4f96f..2e5f8a09fc1 100644 --- a/app/assets/javascripts/lib/utils/text_utility.js +++ b/app/assets/javascripts/lib/utils/text_utility.js @@ -188,29 +188,5 @@ require('vendor/latinise'); gl.text.slugify = function(str) { return str.trim().toLowerCase().latinise(); }; - gl.text.formatRelevantDigits = function(number) { - var digitsLeft = ''; - var relevantDigits = 0; - if (isNaN(Number(number))) { - return 0; - } else { - digitsLeft = number.split('.')[0]; - switch (digitsLeft.length) { - case 1: - relevantDigits = 3; - break; - case 2: - relevantDigits = 2; - break; - case 3: - relevantDigits = 1; - break; - default: - relevantDigits = 4; - break; - } - return Number(number).toFixed(relevantDigits); - } - }; })(window); }).call(window); diff --git a/app/assets/javascripts/monitoring/prometheus_graph.js b/app/assets/javascripts/monitoring/prometheus_graph.js index a7608468a97..a6ffa0f59de 100644 --- a/app/assets/javascripts/monitoring/prometheus_graph.js +++ b/app/assets/javascripts/monitoring/prometheus_graph.js @@ -3,7 +3,7 @@ import d3 from 'd3'; import statusCodes from '~/lib/utils/http_status'; -import '../lib/utils/common_utils'; +import { formatRelevantDigits } from '~/lib/utils/number_utils'; import '../flash'; const prometheusGraphsContainer = '.prometheus-graph'; @@ -64,10 +64,10 @@ class PrometheusGraph { const prometheusGraphContainer = `${prometheusGraphsContainer}[graph-type=${key}]`; const chart = d3.select(prometheusGraphContainer) - .attr('width', this.width + this.margin.left + this.margin.right) - .attr('height', this.height + this.margin.bottom + this.margin.top) - .append('g') - .attr('transform', `translate(${this.margin.left},${this.margin.top})`); + .attr('width', this.width + this.margin.left + this.margin.right) + .attr('height', this.height + this.margin.bottom + this.margin.top) + .append('g') + .attr('transform', `translate(${this.margin.left},${this.margin.top})`); const axisLabelContainer = d3.select(prometheusGraphContainer) .attr('width', this.originalWidth) @@ -79,26 +79,26 @@ class PrometheusGraph { y.domain([0, d3.max(graphSpecifics.data.map(metricValue => metricValue.value))]); const xAxis = d3.svg.axis() - .scale(x) - .ticks(this.commonGraphProperties.axis_no_ticks) - .orient('bottom'); + .scale(x) + .ticks(this.commonGraphProperties.axis_no_ticks) + .orient('bottom'); const yAxis = d3.svg.axis() - .scale(y) - .ticks(this.commonGraphProperties.axis_no_ticks) - .tickSize(-this.width) - .orient('left'); + .scale(y) + .ticks(this.commonGraphProperties.axis_no_ticks) + .tickSize(-this.width) + .orient('left'); this.createAxisLabelContainers(axisLabelContainer, key); chart.append('g') - .attr('class', 'x-axis') - .attr('transform', `translate(0,${this.height})`) - .call(xAxis); + .attr('class', 'x-axis') + .attr('transform', `translate(0,${this.height})`) + .call(xAxis); chart.append('g') - .attr('class', 'y-axis') - .call(yAxis); + .attr('class', 'y-axis') + .call(yAxis); const area = d3.svg.area() .x(d => x(d.time)) @@ -111,10 +111,10 @@ class PrometheusGraph { .y(d => y(d.value)); chart.append('path') - .datum(graphSpecifics.data) - .attr('d', area) - .attr('class', 'metric-area') - .attr('fill', graphSpecifics.area_fill_color); + .datum(graphSpecifics.data) + .attr('d', area) + .attr('class', 'metric-area') + .attr('fill', graphSpecifics.area_fill_color); chart.append('path') .datum(graphSpecifics.data) @@ -137,73 +137,74 @@ class PrometheusGraph { const graphSpecifics = this.graphSpecificProperties[key]; axisLabelContainer.append('line') - .attr('class', 'label-x-axis-line') - .attr('stroke', '#000000') - .attr('stroke-width', '1') - .attr({ - x1: 10, - y1: this.originalHeight - this.margin.top, - x2: (this.originalWidth - this.margin.right) + 10, - y2: this.originalHeight - this.margin.top, - }); + .attr('class', 'label-x-axis-line') + .attr('stroke', '#000000') + .attr('stroke-width', '1') + .attr({ + x1: 10, + y1: this.originalHeight - this.margin.top, + x2: (this.originalWidth - this.margin.right) + 10, + y2: this.originalHeight - this.margin.top, + }); axisLabelContainer.append('line') - .attr('class', 'label-y-axis-line') - .attr('stroke', '#000000') - .attr('stroke-width', '1') - .attr({ - x1: 10, - y1: 0, - x2: 10, - y2: this.originalHeight - this.margin.top, - }); + .attr('class', 'label-y-axis-line') + .attr('stroke', '#000000') + .attr('stroke-width', '1') + .attr({ + x1: 10, + y1: 0, + x2: 10, + y2: this.originalHeight - this.margin.top, + }); + axisLabelContainer.append('rect') - .attr('class', 'rect-axis-text') - .attr('x', 0) - .attr('y', 50) - .attr('width', 30) - .attr('height', 150); + .attr('class', 'rect-axis-text') + .attr('x', 0) + .attr('y', 50) + .attr('width', 30) + .attr('height', 150); axisLabelContainer.append('text') - .attr('class', 'label-axis-text') - .attr('text-anchor', 'middle') - .attr('transform', `translate(15, ${(this.originalHeight - this.margin.top) / 2}) rotate(-90)`) - .text(graphSpecifics.graph_legend_title); + .attr('class', 'label-axis-text') + .attr('text-anchor', 'middle') + .attr('transform', `translate(15, ${(this.originalHeight - this.margin.top) / 2}) rotate(-90)`) + .text(graphSpecifics.graph_legend_title); axisLabelContainer.append('rect') - .attr('class', 'rect-axis-text') - .attr('x', (this.originalWidth / 2) - this.margin.right) - .attr('y', this.originalHeight - 100) - .attr('width', 30) - .attr('height', 80); + .attr('class', 'rect-axis-text') + .attr('x', (this.originalWidth / 2) - this.margin.right) + .attr('y', this.originalHeight - 100) + .attr('width', 30) + .attr('height', 80); axisLabelContainer.append('text') - .attr('class', 'label-axis-text') - .attr('x', (this.originalWidth / 2) - this.margin.right) - .attr('y', this.originalHeight - this.margin.top) - .attr('dy', '.35em') - .text('Time'); + .attr('class', 'label-axis-text') + .attr('x', (this.originalWidth / 2) - this.margin.right) + .attr('y', this.originalHeight - this.margin.top) + .attr('dy', '.35em') + .text('Time'); // Legends // Metric Usage axisLabelContainer.append('rect') - .attr('x', this.originalWidth - 170) - .attr('y', (this.originalHeight / 2) - 60) - .style('fill', graphSpecifics.area_fill_color) - .attr('width', 20) - .attr('height', 35); + .attr('x', this.originalWidth - 170) + .attr('y', (this.originalHeight / 2) - 60) + .style('fill', graphSpecifics.area_fill_color) + .attr('width', 20) + .attr('height', 35); axisLabelContainer.append('text') - .attr('class', 'text-metric-title') - .attr('x', this.originalWidth - 140) - .attr('y', (this.originalHeight / 2) - 50) - .text('Average'); + .attr('class', 'text-metric-title') + .attr('x', this.originalWidth - 140) + .attr('y', (this.originalHeight / 2) - 50) + .text('Average'); axisLabelContainer.append('text') - .attr('class', 'text-metric-usage') - .attr('x', this.originalWidth - 140) - .attr('y', (this.originalHeight / 2) - 25); + .attr('class', 'text-metric-usage') + .attr('x', this.originalWidth - 140) + .attr('y', (this.originalHeight / 2) - 25); } handleMouseOverGraph(prometheusGraphContainer) { @@ -240,44 +241,45 @@ class PrometheusGraph { }); currentChart.append('circle') - .attr('class', 'circle-metric') - .attr('fill', currentGraphProps.line_color) - .attr('cx', currentTimeCoordinate) - .attr('cy', currentGraphProps.yScale(currentData.value)) - .attr('r', this.commonGraphProperties.circle_radius_metric); + .attr('class', 'circle-metric') + .attr('fill', currentGraphProps.line_color) + .attr('cx', currentTimeCoordinate) + .attr('cy', currentGraphProps.yScale(currentData.value)) + .attr('r', this.commonGraphProperties.circle_radius_metric); // The little box with text const rectTextMetric = currentChart.append('g') - .attr('class', 'rect-text-metric') - .attr('translate', `(${currentTimeCoordinate}, ${currentGraphProps.yScale(currentData.value)})`); + .attr('class', 'rect-text-metric') + .attr('translate', `(${currentTimeCoordinate}, ${currentGraphProps.yScale(currentData.value)})`); rectTextMetric.append('rect') - .attr('class', 'rect-metric') - .attr('x', currentTimeCoordinate + 10) - .attr('y', maxMetricValue) - .attr('width', this.commonGraphProperties.rect_text_width) - .attr('height', this.commonGraphProperties.rect_text_height); + .attr('class', 'rect-metric') + .attr('x', currentTimeCoordinate + 10) + .attr('y', maxMetricValue) + .attr('width', this.commonGraphProperties.rect_text_width) + .attr('height', this.commonGraphProperties.rect_text_height); rectTextMetric.append('text') - .attr('class', 'text-metric') - .attr('x', currentTimeCoordinate + 35) - .attr('y', maxMetricValue + 35) - .text(timeFormat(currentData.time)); + .attr('class', 'text-metric') + .attr('x', currentTimeCoordinate + 35) + .attr('y', maxMetricValue + 35) + .text(timeFormat(currentData.time)); rectTextMetric.append('text') - .attr('class', 'text-metric-date') - .attr('x', currentTimeCoordinate + 15) - .attr('y', maxMetricValue + 15) - .text(dayFormat(currentData.time)); + .attr('class', 'text-metric-date') + .attr('x', currentTimeCoordinate + 15) + .attr('y', maxMetricValue + 15) + .text(dayFormat(currentData.time)); - let currentMetricValue = gl.text.formatRelevantDigits(currentData.value); + let currentMetricValue = formatRelevantDigits(currentData.value); if (key === 'cpu_values') { currentMetricValue = `${currentMetricValue}%`; } else { currentMetricValue = `${currentMetricValue} MB`; } + d3.select(`${currentPrometheusGraphContainer} .text-metric-usage`) - .text(currentMetricValue); + .text(currentMetricValue); }); } diff --git a/spec/javascripts/lib/utils/number_utility_spec.js b/spec/javascripts/lib/utils/number_utility_spec.js new file mode 100644 index 00000000000..5fde8be9123 --- /dev/null +++ b/spec/javascripts/lib/utils/number_utility_spec.js @@ -0,0 +1,41 @@ +import { formatRelevantDigits } from '~/lib/utils/number_utils'; + +describe('Number Utils', () => { + describe('formatRelevantDigits', () => { + it('returns an empty string when the number is NaN', () => { + expect(formatRelevantDigits('fail')).toBe(''); + }); + + it('returns 4 decimals when there is 4 plus digits to the left', () => { + const formattedNumber = formatRelevantDigits('1000.1234567'); + const rightFromDecimal = formattedNumber.split('.')[1]; + const leftFromDecimal = formattedNumber.split('.')[0]; + expect(rightFromDecimal.length).toBe(4); + expect(leftFromDecimal.length).toBe(4); + }); + + it('returns 3 decimals when there is 1 digit to the left', () => { + const formattedNumber = formatRelevantDigits('0.1234567'); + const rightFromDecimal = formattedNumber.split('.')[1]; + const leftFromDecimal = formattedNumber.split('.')[0]; + expect(rightFromDecimal.length).toBe(3); + expect(leftFromDecimal.length).toBe(1); + }); + + it('returns 2 decimals when there is 2 digits to the left', () => { + const formattedNumber = formatRelevantDigits('10.1234567'); + const rightFromDecimal = formattedNumber.split('.')[1]; + const leftFromDecimal = formattedNumber.split('.')[0]; + expect(rightFromDecimal.length).toBe(2); + expect(leftFromDecimal.length).toBe(2); + }); + + it('returns 1 decimal when there is 3 digits to the left', () => { + const formattedNumber = formatRelevantDigits('100.1234567'); + const rightFromDecimal = formattedNumber.split('.')[1]; + const leftFromDecimal = formattedNumber.split('.')[0]; + expect(rightFromDecimal.length).toBe(1); + expect(leftFromDecimal.length).toBe(3); + }); + }); +}); diff --git a/spec/javascripts/lib/utils/text_utility_spec.js b/spec/javascripts/lib/utils/text_utility_spec.js index 3d0e92ed240..4200e943121 100644 --- a/spec/javascripts/lib/utils/text_utility_spec.js +++ b/spec/javascripts/lib/utils/text_utility_spec.js @@ -105,32 +105,6 @@ require('~/lib/utils/text_utility'); expect(textArea.value).toEqual(`${initialValue}* `); }); }); - - describe('gl.text.formatRelevantDigits', () => { - it('returns 0 when the number is NaN', () => { - expect(gl.text.formatRelevantDigits('fail')).toBe(0); - }); - - it('returns 4 decimals when there is 4 plus digits to the left', () => { - const formattedNumber = gl.text.formatRelevantDigits('1000.1234567').split('.')[1]; - expect(formattedNumber.length).toBe(4); - }); - - it('returns 3 decimals when there is 1 digit to the left', () => { - const formattedNumber = gl.text.formatRelevantDigits('0.1234567').split('.')[1]; - expect(formattedNumber.length).toBe(3); - }); - - it('returns 2 decimals when there is 2 digits to the left', () => { - const formattedNumber = gl.text.formatRelevantDigits('10.1234567').split('.')[1]; - expect(formattedNumber.length).toBe(2); - }); - - it('returns 1 decimal when there is 3 digits to the left', () => { - const formattedNumber = gl.text.formatRelevantDigits('100.1234567').split('.')[1]; - expect(formattedNumber.length).toBe(1); - }); - }); }); }); })(); -- cgit v1.2.1