From 7188a713761b187f31ff35c6b9065315b5e385a9 Mon Sep 17 00:00:00 2001 From: Xaun Lopez Date: Thu, 14 Sep 2017 18:26:16 +0100 Subject: [PATCH 1/2] Refactor thresholds --- .../chart-threshold.component.coffee | 45 ++++++++++------ .../accounts-cash-projection.directive.coffee | 8 +-- .../highcharts-factory.svc.coffee | 53 ++++++++----------- 3 files changed, 53 insertions(+), 53 deletions(-) diff --git a/src/components/widgets-common/chart-threshold/chart-threshold.component.coffee b/src/components/widgets-common/chart-threshold/chart-threshold.component.coffee index 2ae8ad7a..98e9df92 100644 --- a/src/components/widgets-common/chart-threshold/chart-threshold.component.coffee +++ b/src/components/widgets-common/chart-threshold/chart-threshold.component.coffee @@ -14,6 +14,7 @@ module.component('chartThreshold', { disabled: ' ctrl = this @@ -30,6 +31,7 @@ module.component('chartThreshold', { ctrl.disabled ||= false ctrl.kpiTargetMode ||= 'min' ctrl.kpiCreateLabel ||= 'Get alerted when the target threshold goes below' + ctrl.thresholdColor ||= 'rgba(0, 0, 0, 0.7)' # Get attachable kpi templates ImpacKpisSvc.getAttachableKpis(ctrl.widget.endpoint).then( (templates)-> @@ -74,17 +76,23 @@ module.component('chartThreshold', { }] return unless ImpacKpisSvc.validateKpiTargets(params.targets) promise = if ctrl.isEditingKpi - ImpacKpisSvc.update(getKpi(), params, false) + ImpacKpisSvc.update(getKpi(), params, false).then( + (kpi)-> + # Remove old threshold from chart + ctrl.chart.removeThreshold(kpi.id) + angular.extend(getKpi(), kpi) + ) else params.metadata.hist_parameters = ctrl.widget.metadata.hist_parameters params.widget_id = ctrl.widget.id - ImpacKpisSvc.create('impac', ctrl.kpi.endpoint, ctrl.kpi.watchables[0], params) + ImpacKpisSvc.create('impac', ctrl.kpi.endpoint, ctrl.kpi.watchables[0], params).then( + (kpi)-> + ctrl.widget.kpis.push(kpi) + kpi + ) promise.then( (kpi)-> - ctrl.widget.kpis.push(kpi) ctrl.onComplete($event: { kpi: kpi }) if _.isFunction(ctrl.onComplete) - (err)-> - toastr.error('Failed to save KPI', 'Error') ).finally(-> ctrl.cancelCreateKpi() ) @@ -97,6 +105,7 @@ module.component('chartThreshold', { -> toastr.success("Deleted #{kpiDesc} KPI") _.remove(ctrl.widget.kpis, (k)-> k.id == kpi.id) + ctrl.chart.removeThreshold(kpi.id) ctrl.onComplete($event: {}) if _.isFunction(ctrl.onComplete) -> toastr.error("Failed to delete #{kpiDesc} KPI", 'Error') @@ -111,12 +120,10 @@ module.component('chartThreshold', { onChartNotify = (chart)-> ctrl.chart = chart - validateHistParameters() - Highcharts.addEvent(chart.container, 'click', onChartClick) - thresholdSeries = _.filter(chart.series, (s) -> _.includes(s.name.toLowerCase(), 'threshold')) - _.each(thresholdSeries, (t)-> - Highcharts.addEvent(t, 'click', (event)-> onThresholdClick(t)) - ) + return unless validateHistParameters() + Highcharts.addEvent(chart.hc.container, 'click', onChartClick) + _.each buildThresholdsFromKpis(), (threshold)-> + ctrl.chart.addThreshold(threshold) return onChartClick = (event)-> @@ -148,19 +155,25 @@ module.component('chartThreshold', { shrinkChart = -> return unless ctrl.chart - ctrl.chart.setSize(null, ctrl.chart.chartHeight - ctrl.chartShrinkSize, false) - ctrl.chart.container.parentElement.style.height = "#{ctrl.chart.chartHeight}px" + ctrl.chart.hc.setSize(null, ctrl.chart.hc.chartHeight - ctrl.chartShrinkSize, false) + ctrl.chart.hc.container.parentElement.style.height = "#{ctrl.chart.hc.chartHeight}px" growChart = -> return unless ctrl.chart - ctrl.chart.setSize(null, ctrl.chart.chartHeight + ctrl.chartShrinkSize, false) - ctrl.chart.container.parentElement.style.height = "#{ctrl.chart.chartHeight}px" + ctrl.chart.hc.setSize(null, ctrl.chart.hc.chartHeight + ctrl.chartShrinkSize, false) + ctrl.chart.hc.container.parentElement.style.height = "#{ctrl.chart.hc.chartHeight}px" # Disable threshold when selected time period is strictly in the past validateHistParameters = -> widgetHistParams = ctrl.widget.metadata && ctrl.widget.metadata.hist_parameters ctrl.disabled = widgetHistParams? && moment(widgetHistParams.to) <= moment.utc().startOf('day') - return + return !ctrl.disabled + + # Validate and build threshold data from widget kpi templates + buildThresholdsFromKpis = -> + targets = ctrl.widget.kpis? && ctrl.widget.kpis[0] && ctrl.widget.kpis[0].targets + return [] unless ImpacKpisSvc.validateKpiTargets(targets) + [{ kpiId: ctrl.widget.kpis[0].id, value: targets.threshold[0].min, name: 'Alert Threshold', color: ctrl.thresholdColor, onClickEvent: onThresholdClick }] return ctrl }) diff --git a/src/components/widgets/accounts-cash-projection/accounts-cash-projection.directive.coffee b/src/components/widgets/accounts-cash-projection/accounts-cash-projection.directive.coffee index eb9578da..5c7c3d06 100644 --- a/src/components/widgets/accounts-cash-projection/accounts-cash-projection.directive.coffee +++ b/src/components/widgets/accounts-cash-projection/accounts-cash-projection.directive.coffee @@ -122,7 +122,6 @@ module.controller('WidgetAccountsCashProjectionCtrl', ($scope, $q, $filter, Impa currency: w.metadata.currency showToday: true showLegend: true - thresholds: getThresholds() $scope.chart ||= new HighchartsFactory($scope.chartId(), w.content.chart, options) $scope.chart.render(w.content.chart, options) @@ -131,7 +130,7 @@ module.controller('WidgetAccountsCashProjectionCtrl', ($scope, $q, $filter, Impa $scope.chart.addCustomLegend(legendFormatter) $scope.chart.addSeriesEvent('click', onClickBar) - $scope.chartDeferred.notify($scope.chart.hc) + $scope.chartDeferred.notify($scope.chart) $scope.chartId = -> "cashProjectionChart-#{w.id}" @@ -147,11 +146,6 @@ module.controller('WidgetAccountsCashProjectionCtrl', ($scope, $q, $filter, Impa getPeriod = -> w.metadata? && w.metadata.hist_parameters? && w.metadata.hist_parameters.period || 'MONTHLY' - getThresholds = -> - targets = w.kpis? && w.kpis[0] && w.kpis[0].targets - return [] unless ImpacKpisSvc.validateKpiTargets(targets) - [{ kpiId: w.kpis[0].id, value: targets.threshold[0].min }] - # Widget is ready: can trigger the "wait for settings to be ready" # -------------------------------------- $scope.widgetDeferred.resolve(settingsPromises) diff --git a/src/services/highcharts-factory/highcharts-factory.svc.coffee b/src/services/highcharts-factory/highcharts-factory.svc.coffee index 2a69ddcc..8ccf3b5f 100644 --- a/src/services/highcharts-factory/highcharts-factory.svc.coffee +++ b/src/services/highcharts-factory/highcharts-factory.svc.coffee @@ -46,7 +46,6 @@ angular @hc = Highcharts.stockChart(@id, chartConfig) else @hc.update(chartConfig) - @addThresholds() return @ template: -> @@ -78,7 +77,7 @@ angular xAxis: plotLines: [{ color: _.get(@options, 'todayMarkerColor', 'rgba(0, 85, 255, 0.2)') - value: moment.utc().startOf('day').unix() * 1000 + value: moment.utc().startOf('day').unix() * 1000 width: 1 label: text: null @@ -88,42 +87,36 @@ angular y: -5 }] - addThresholds: (options = @options)-> + addThreshold: (thresholdOptions)-> return if _.isEmpty(@hc) - # Remove existing thresholds - for s in @hc.series - s.remove() if s? && _.includes(s.name.toLowerCase(), 'threshold') + # Initialize data matrix + data = angular.copy @data.series[0].data + for vector in data + # When in the past, set y-axis value at null + if !thresholdOptions.fullLengthThresholds && moment.unix(vector[0] / 1000) < moment.utc().startOf('day') + vector[1] = null + # When in the future, set y-axis value at thresholdOptions.value + else + vector[1] = parseFloat(thresholdOptions.value) + # Build & add threshold serie + threshold = angular.extend( + { data: data, showInLegend: false, marker: { enabled: false } }, + thresholdOptions + ) + thresholdSerie = @hc.addSeries(threshold) + Highcharts.addEvent(thresholdSerie, 'click', (_event)-> thresholdOptions.onClickEvent(thresholdSerie)) + thresholdSerie - return @hc if _.isEmpty(options.thresholds) - - for threshold in options.thresholds - # Initialize data matrix - data = angular.copy @data.series[0].data - for vector in data - # When in the past, set y-axis value at null - if !options.fullLengthThresholds && moment.unix(vector[0] / 1000) < moment.utc().startOf('day') - vector[1] = null - # When in the future, set y-axis value at threshold.value - else - vector[1] = parseFloat(threshold.value) - - @hc.addSeries({ - name: 'Threshold KPI' - kpiId: threshold.kpiId - data: data - color: _.get(options, 'thresholdsColor', 'rgba(255, 0, 0, 0.5)') - showInLegend: false - marker: { enabled: false } - }, true) - - return @hc + removeThreshold: (kpiId)-> + thresholdSerie = _.find(@hc.series, (s)-> s.options.kpiId == kpiId) + thresholdSerie.remove() if thresholdSerie? # Extend default chart formatters to add custom legend img icon addCustomLegend: (formatterCallback, useHTML = true) -> @hc.legend.update({ useHTML: useHTML labelFormatter: formatterCallback - }, true) + }) # Adds events to series objects addSeriesEvent: (eventName, callback) -> From 24938622a7de54132c7bed50262b5aa547eaf203 Mon Sep 17 00:00:00 2001 From: Xaun Lopez Date: Fri, 15 Sep 2017 16:25:33 +0100 Subject: [PATCH 2/2] Fix duplicate thresholds added on widget save settings --- .../chart-threshold.component.coffee | 6 ++++-- .../highcharts-factory.svc.coffee | 13 +++++++++---- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/components/widgets-common/chart-threshold/chart-threshold.component.coffee b/src/components/widgets-common/chart-threshold/chart-threshold.component.coffee index 98e9df92..7a785670 100644 --- a/src/components/widgets-common/chart-threshold/chart-threshold.component.coffee +++ b/src/components/widgets-common/chart-threshold/chart-threshold.component.coffee @@ -123,7 +123,9 @@ module.component('chartThreshold', { return unless validateHistParameters() Highcharts.addEvent(chart.hc.container, 'click', onChartClick) _.each buildThresholdsFromKpis(), (threshold)-> - ctrl.chart.addThreshold(threshold) + thresholdSerie = ctrl.chart.findThreshold(threshold.kpiId) + thresholdSerie = ctrl.chart.addThreshold(threshold) unless thresholdSerie? + ctrl.chart.addThresholdEvent(thresholdSerie, 'click', onThresholdClick) return onChartClick = (event)-> @@ -173,7 +175,7 @@ module.component('chartThreshold', { buildThresholdsFromKpis = -> targets = ctrl.widget.kpis? && ctrl.widget.kpis[0] && ctrl.widget.kpis[0].targets return [] unless ImpacKpisSvc.validateKpiTargets(targets) - [{ kpiId: ctrl.widget.kpis[0].id, value: targets.threshold[0].min, name: 'Alert Threshold', color: ctrl.thresholdColor, onClickEvent: onThresholdClick }] + [{ kpiId: ctrl.widget.kpis[0].id, value: targets.threshold[0].min, name: 'Alert Threshold', color: ctrl.thresholdColor }] return ctrl }) diff --git a/src/services/highcharts-factory/highcharts-factory.svc.coffee b/src/services/highcharts-factory/highcharts-factory.svc.coffee index 8ccf3b5f..a8d88f4b 100644 --- a/src/services/highcharts-factory/highcharts-factory.svc.coffee +++ b/src/services/highcharts-factory/highcharts-factory.svc.coffee @@ -103,14 +103,19 @@ angular { data: data, showInLegend: false, marker: { enabled: false } }, thresholdOptions ) - thresholdSerie = @hc.addSeries(threshold) - Highcharts.addEvent(thresholdSerie, 'click', (_event)-> thresholdOptions.onClickEvent(thresholdSerie)) - thresholdSerie + @hc.addSeries(threshold) removeThreshold: (kpiId)-> - thresholdSerie = _.find(@hc.series, (s)-> s.options.kpiId == kpiId) + thresholdSerie = @findThreshold(kpiId) thresholdSerie.remove() if thresholdSerie? + findThreshold: (kpiId)-> + _.find(@hc.series, (s)-> s.options.kpiId == kpiId) + + addThresholdEvent: (thresholdSerie, eventName, callback)-> + return unless thresholdSerie? && eventName? && _.isFunction(callback) + Highcharts.addEvent(thresholdSerie, eventName, (_event)-> callback(thresholdSerie)) + # Extend default chart formatters to add custom legend img icon addCustomLegend: (formatterCallback, useHTML = true) -> @hc.legend.update({