You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pinot.apache.org by ap...@apache.org on 2019/01/08 18:15:11 UTC

[incubator-pinot] branch master updated: [TE] rootcause - fix slider and offset quirks (#3663)

This is an automated email from the ASF dual-hosted git repository.

apucher pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-pinot.git


The following commit(s) were added to refs/heads/master by this push:
     new 06dc0e9  [TE] rootcause - fix slider and offset quirks (#3663)
06dc0e9 is described below

commit 06dc0e9b2807ff2c023186be9c80394978e82476
Author: Alexander Pucher <ap...@linkedin.com>
AuthorDate: Tue Jan 8 10:15:06 2019 -0800

    [TE] rootcause - fix slider and offset quirks (#3663)
    
    This PR fixes a number of quirks in the RCA UI related to the range slider and offsets:
    * range slider no longer stuck on first click after changing compare mode
    * range slider no longer stale when anomaly range changes
    * (most) new offsets now supported in algo tab
    
    Thanks to @aaronucsd for help with this one!
---
 .../rootcause-select-comparison-range/component.js |  90 +++------
 .../component.js                                   | 216 ---------------------
 .../template.hbs                                   |  74 -------
 thirdeye/thirdeye-frontend/app/utils/rca-utils.js  |  76 +++++---
 4 files changed, 75 insertions(+), 381 deletions(-)

diff --git a/thirdeye/thirdeye-frontend/app/pods/components/rootcause-select-comparison-range/component.js b/thirdeye/thirdeye-frontend/app/pods/components/rootcause-select-comparison-range/component.js
index 0367de6..a766bee 100644
--- a/thirdeye/thirdeye-frontend/app/pods/components/rootcause-select-comparison-range/component.js
+++ b/thirdeye/thirdeye-frontend/app/pods/components/rootcause-select-comparison-range/component.js
@@ -4,6 +4,7 @@ import $ from 'jquery';
 import {
   makeTime
 } from 'thirdeye-frontend/utils/rca-utils';
+import _ from 'lodash';
 
 // TODO consolidate rootcause-select-comparison-range2, rootcause-slider
 
@@ -35,8 +36,7 @@ export default Component.extend({
   compareMode: null, // ""
   onChange: null, // func (start, end, compareMode)
   slider: null,
-  originalMinInvestigatePeriod: null,
-  originalMaxInvestigatePeriod: null,
+  sliderOptionsCache: null,
 
   rangeOptions: {
     'Last hour': [makeTime().subtract(1, 'hours').startOf('hour'), makeTime().startOf('hours').add(1, 'hours')],
@@ -68,19 +68,19 @@ export default Component.extend({
     }
   ],
 
-  minDisplayWindow: computed('displayRange.[]', function() {//display window start - slider
+  minDisplayWindow: computed('displayRange', function() {//display window start - slider
     return makeTime(this.get('displayRange')[0]);
   }),
 
-  maxDisplayWindow: computed('displayRange.[]', function() {//display window end - slider
+  maxDisplayWindow: computed('displayRange', function() {//display window end - slider
     return makeTime(this.get('displayRange')[1]);
   }),
 
-  minInvestigatePeriod: computed('anomalyRange.[]', function() {//Investigation period start - slider
+  minInvestigatePeriod: computed('anomalyRange', function() {//Investigation period start - slider
     return makeTime(this.get('anomalyRange')[0]);
   }),
 
-  maxInvestigatePeriod: computed('anomalyRange.[]', function() {//Investigation period - slider
+  maxInvestigatePeriod: computed('anomalyRange', function() {//Investigation period - slider
     return makeTime(this.get('anomalyRange')[1]);
   }),
 
@@ -88,12 +88,11 @@ export default Component.extend({
     return namedToEpocMapping[this.get('granularity')];
   }),
 
-
-  startFormatted: computed('anomalyRange.[]', function() {//investigation start
+  startFormatted: computed('anomalyRange', function() {//investigation start
     return makeTime(this.get('anomalyRange')[0]).format(serverDateFormat);
   }),
 
-  endFormatted: computed('anomalyRange.[]', function() {//investigation end
+  endFormatted: computed('anomalyRange', function() {//investigation end
     return makeTime(this.get('anomalyRange')[1]).format(serverDateFormat);
   }),
 
@@ -101,8 +100,13 @@ export default Component.extend({
     return makeTime().startOf('hour').add(1, 'hours').format(serverDateFormat);
   }),
 
-  compareModeFormatted: computed('compareMode', function() {
-    return this.get('compareMode');
+  compareModeFormatted: computed('compareMode', {
+    get () {
+      return this.get('compareMode');
+    },
+    set () {
+      // ignore to prevent override
+    }
   }),
 
   /**
@@ -112,7 +116,8 @@ export default Component.extend({
     this._super(...arguments);
     let $range = $('.js-range-slider');
     const timeFormat = this.get('timeFormat');
-    const { compareMode, onChange } = this.getProperties('compareMode', 'onChange');
+    const { onChange } = this.getProperties('onChange');
+    const $$ = this;
 
     $range.ionRangeSlider({
       type: 'double',
@@ -129,7 +134,7 @@ export default Component.extend({
       },
       onFinish: function (data) {
         // Update the display window's investigation period on the chart
-        onChange(makeTime(data.from).valueOf(), makeTime(data.to).valueOf(), compareMode);
+        onChange(makeTime(data.from).valueOf(), makeTime(data.to).valueOf(), $$.get('compareMode'));
       }
     });
 
@@ -148,37 +153,24 @@ export default Component.extend({
       // granularityOneWay: this.get('granularity')
     });
 
-    // Save original investigation periods
-    this.setProperties({
-      originalMinInvestigatePeriod: this.get('minInvestigatePeriod'),
-      originalMaxInvestigatePeriod: this.get('maxInvestigatePeriod')
-    });
-
     // Update the slider, by calling it's update method
-    this.get('slider').update({
+    const sliderOptionsCache = this.get('sliderOptionsCache');
+
+    const sliderOptions = {
       step: this.get('granularityOneWay'),
       min: this.get('minDisplayWindow').format('x'),
-      max: this.get('maxDisplayWindow').format('x')
-    });
+      max: this.get('maxDisplayWindow').format('x'),
+      from: this.get('minInvestigatePeriod').format('x'),
+      to: this.get('maxInvestigatePeriod').format('x')
+    };
+
+    if (!_.isEqual(sliderOptions, sliderOptionsCache)) {
+      this.get('slider').update(sliderOptions);
+      this.set('sliderOptionsCache', sliderOptions);
+    }
   },
 
   actions: {
-    onRange(start, end) {
-      const { compareMode, onChange } = this.getProperties('compareMode', 'onChange');
-
-      // Update anomalyRange for computed to recalculate
-      this.set('anomalyRange', [makeTime(start).valueOf(), makeTime(end).valueOf()]);
-
-      // Investigation period changed on date picker. Update the slider's min and max.
-      this.get('slider').update({
-        from: this.get('minInvestigatePeriod').format('x'),
-        to: this.get('maxInvestigatePeriod').format('x')
-      });
-
-      // Update the display window's investigation period on the chart
-      onChange(makeTime(start).valueOf(), makeTime(end).valueOf(), compareMode);
-    },
-
     onPickerRange(type, time) {
       const { compareMode, onChange } = this.getProperties('compareMode', 'onChange');
 
@@ -189,10 +181,6 @@ export default Component.extend({
       // Update for the date picker to be in sync
       this.set('anomalyRange', [makeTime(start).valueOf(), makeTime(end).valueOf()]);
 
-      // Investigation period changed on date picker. Update the slider's min and max.
-      let sliderOptions = type === 'start' ? { from: this.get('minInvestigatePeriod').format('x') } : { to: this.get('maxInvestigatePeriod').format('x') };
-      this.get('slider').update(sliderOptions);
-
       // Update the display window's investiation period on the chart
       onChange(makeTime(start).valueOf(), makeTime(end).valueOf(), compareMode);
     },
@@ -200,24 +188,6 @@ export default Component.extend({
     onCompareMode(compareMode) {
       const { anomalyRange, onChange } = this.getProperties('anomalyRange', 'onChange');
       onChange(anomalyRange[0], anomalyRange[1], compareMode);
-    },
-
-    resetSlider() {
-      const slider = this.get('slider');
-      // RESET - reset slider to it's first values
-      slider.reset();
-      // get original investigation periods
-      this.setProperties({
-        minInvestigatePeriod: this.get('originalMinInvestigatePeriod'),
-        maxInvestigatePeriod: this.get('originalMaxInvestigatePeriod')
-      });
-
-      // Update the slider, by calling it's update method
-      this.get('slider').update({
-        from: this.get('minInvestigatePeriod').format('x'),
-        to: this.get('maxInvestigatePeriod').format('x')
-      });
     }
-
   }
 });
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/rootcause-select-comparison-range2/component.js b/thirdeye/thirdeye-frontend/app/pods/components/rootcause-select-comparison-range2/component.js
deleted file mode 100644
index 4c8f32a..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/components/rootcause-select-comparison-range2/component.js
+++ /dev/null
@@ -1,216 +0,0 @@
-import { computed } from '@ember/object';
-import Component from '@ember/component';
-import $ from 'jquery';
-import {
-  makeTime,
-  dateFormatFull
-} from 'thirdeye-frontend/utils/rca-utils';
-
-// TODO merge this with rootcause-select-comparison-range
-
-/**
- * Date format the date picker component expects
- * @type String
- *
- */
-const serverDateFormat = 'YYYY-MM-DD HH:mm';
-
-/**
- * @summary Mapping between values that are named on the backend to epoc time value in millis
- * @type {Object}
- * @example  `1_HOURS=3600000=1hr , 1800000=30mins` etc since we using epoc time values in millis
- */
-const namedToEpocMapping = {
-  '5_MINUTES': 300000,
-  '15_MINUTES': 900000,
-  '30_MINUTES': 1800000,
-  '1_HOURS': 3600000,
-  '3_HOURS': 10800000,
-  '1_DAYS': 86400000
-};
-
-
-export default Component.extend({
-  timeFormat: "MMM D, hh:mm a z",//slider
-  range: null, // [0, 0]
-  compareMode: null, // ""
-  onChange: null, // func (start, end, compareMode)
-  slider: null,
-  originalMinInvestigatePeriod: null,
-  originalMaxInvestigatePeriod: null,
-
-  rangeOptions: {
-    'Last hour': [makeTime().subtract(1, 'hours').startOf('hour'), makeTime().startOf('hours').add(1, 'hours')],
-    'Last 3 hours': [makeTime().subtract(3, 'hours').startOf('hour'), makeTime().startOf('hours').add(1, 'hours')],
-    'Last 6 hours': [makeTime().subtract(6, 'hours').startOf('hour'), makeTime().startOf('hours').add(1, 'hours')],
-    'Last 24 hours': [makeTime().subtract(24, 'hours').startOf('hour'), makeTime().startOf('hours').add(1, 'hours')]
-  },
-
-  compareModeOptions: [
-    'WoW',
-    'Wo2W',
-    'Wo3W',
-    'Wo4W',
-    'mean4w',
-    'median4w',
-    'min4w',
-    'max4w',
-    'predicted',
-    'none'
-  ],
-
-  minDisplayWindow: computed('displayRange.[]', function() {//display window start - slider
-    return makeTime(this.get('displayRange')[0]);
-  }),
-
-  maxDisplayWindow: computed('displayRange.[]', function() {//display window end - slider
-    return makeTime(this.get('displayRange')[1]);
-  }),
-
-  minInvestigatePeriod: computed('anomalyRange.[]', function() {//Investigation period start - slider
-    return makeTime(this.get('anomalyRange')[0]);
-  }),
-
-  maxInvestigatePeriod: computed('anomalyRange.[]', function() {//Investigation period - slider
-    return makeTime(this.get('anomalyRange')[1]);
-  }),
-
-  granularityOneWay: computed('granularity', function() {
-    return namedToEpocMapping[this.get('granularity')];
-  }),
-
-
-  startFormatted: computed('anomalyRange.[]', function() {//investigation start
-    return makeTime(this.get('anomalyRange')[0]).format(serverDateFormat);
-  }),
-
-  endFormatted: computed('anomalyRange.[]', function() {//investigation end
-    return makeTime(this.get('anomalyRange')[1]).format(serverDateFormat);
-  }),
-
-  maxDateFormatted: computed(function() {
-    return makeTime().startOf('hour').add(1, 'hours').format(serverDateFormat);
-  }),
-
-  compareModeFormatted: computed('compareMode', function() {
-    return this.get('compareMode');
-  }),
-
-  /**
-   * Default after elements are inserted
-   */
-  didInsertElement() {
-    this._super(...arguments);
-    let $range = $('.js-range-slider');
-    const timeFormat = this.get('timeFormat');
-    const { compareMode, onChange } = this.getProperties('compareMode', 'onChange');
-
-    $range.ionRangeSlider({
-      type: 'double',
-      grid: true,
-      grid_num: 1,
-      hide_min_max: true,
-      step: this.get('granularityOneWay'),
-      min: this.get('minDisplayWindow').format('x'),
-      max: this.get('maxDisplayWindow').format('x'),
-      from: this.get('minInvestigatePeriod').format('x'),
-      to: this.get('maxInvestigatePeriod').format('x'),
-      prettify: function (num) {
-        return makeTime(num).format(timeFormat);
-      },
-      onFinish: function (data) {
-        // Update the display window's investigation period on the chart
-        onChange(makeTime(data.from).valueOf(), makeTime(data.to).valueOf(), compareMode);
-      }
-    });
-
-    // Save slider instance to var
-    this.set('slider', $range.data('ionRangeSlider'));
-  },
-
-  didRender() {
-    this._super(...arguments);
-
-    // Set oneway assignment from these existing CPs
-    this.setProperties({
-      startFormattedOneWay: this.get('startFormatted'),
-      endFormattedOneWay: this.get('endFormatted'),
-      maxDateFormattedOneWay: this.get('maxDateFormatted'),
-      // granularityOneWay: this.get('granularity')
-    });
-
-    // Save original investigation periods
-    this.setProperties({
-      originalMinInvestigatePeriod: this.get('minInvestigatePeriod'),
-      originalMaxInvestigatePeriod: this.get('maxInvestigatePeriod')
-    });
-
-    // Update the slider, by calling it's update method
-    if (this.get('slider')) {
-      this.get('slider').update({
-        step: this.get('granularityOneWay'),
-        min: this.get('minDisplayWindow').format('x'),
-        max: this.get('maxDisplayWindow').format('x')
-      });
-    }
-  },
-
-  actions: {
-    onRange(start, end) {
-      const { compareMode, onChange } = this.getProperties('compareMode', 'onChange');
-
-      // Update anomalyRange for computed to recalculate
-      this.set('anomalyRange', [makeTime(start).valueOf(), makeTime(end).valueOf()]);
-
-      // Investigation period changed on date picker. Update the slider's min and max.
-      this.get('slider').update({
-        from: this.get('minInvestigatePeriod').format('x'),
-        to: this.get('maxInvestigatePeriod').format('x')
-      });
-
-      // Update the display window's investiation period on the chart
-      onChange(makeTime(start).valueOf(), makeTime(end).valueOf(), compareMode);
-    },
-
-    onPickerRange(type, time) {
-      const { compareMode, onChange } = this.getProperties('compareMode', 'onChange');
-
-      // Update anomalyRange for computed to recalculate
-      const start = type === 'start' ? makeTime(time).valueOf() : this.get('minInvestigatePeriod').valueOf();
-      const end = type === 'start' ? this.get('maxInvestigatePeriod').valueOf() : makeTime(time).valueOf();
-
-      // Update for the date picker to be in sync
-      this.set('anomalyRange', [makeTime(start).valueOf(), makeTime(end).valueOf()]);
-
-      // Investigation period changed on date picker. Update the slider's min and max.
-      let sliderOptions = type === 'start' ? { from: this.get('minInvestigatePeriod').format('x') } : { to: this.get('maxInvestigatePeriod').format('x') };
-      this.get('slider').update(sliderOptions);
-
-      // Update the display window's investiation period on the chart
-      onChange(makeTime(start).valueOf(), makeTime(end).valueOf(), compareMode);
-    },
-
-    onCompareMode(compareMode) {
-      const { anomalyRange, onChange } = this.getProperties('anomalyRange', 'onChange');
-      onChange(anomalyRange[0], anomalyRange[1], compareMode);
-    },
-
-    resetSlider() {
-      const slider = this.get('slider');
-      // RESET - reset slider to it's first values
-      slider.reset();
-      // get original investigation periods
-      this.setProperties({
-        minInvestigatePeriod: this.get('originalMinInvestigatePeriod'),
-        maxInvestigatePeriod: this.get('originalMaxInvestigatePeriod')
-      });
-
-      // Update the slider, by calling it's update method
-      this.get('slider').update({
-        from: this.get('minInvestigatePeriod').format('x'),
-        to: this.get('maxInvestigatePeriod').format('x')
-      });
-    }
-
-  }
-});
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/rootcause-select-comparison-range2/template.hbs b/thirdeye/thirdeye-frontend/app/pods/components/rootcause-select-comparison-range2/template.hbs
deleted file mode 100644
index 88caf8b..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/components/rootcause-select-comparison-range2/template.hbs
+++ /dev/null
@@ -1,74 +0,0 @@
-<div class="col-xs-3">
-  <label class="te-label te-label--small">Baseline
-    <span>
-      <i class="glyphicon glyphicon-question-sign"></i>
-      {{#tooltip-on-element class="te-tooltip"}}
-        This is the compare mode for computing the baseline in the charts above and below. For example, "Wo2W" uses data from the analysis period shifted by two weeks.
-      {{/tooltip-on-element}}
-    </span>
-  </label>
-  {{#power-select
-    selected=compareModeFormatted
-    options=compareModeOptions
-    searchEnabled=false
-    triggerId="select-compare-mode"
-    onchange=(action "onCompareMode")
-  as |mode|
-  }}
-    {{mode}}
-  {{/power-select}}
-</div>
-<div class="col-xs-9">
-  <!-- Investigation range slider -->
-  <div class="date-slider date-slider--offset" style="position: relative;top: 20px;">
-    <div class="date-slider__picker">
-      <div class="date-slider__picker-item">
-        <label class="te-label te-label--small">Investigation Period
-          <span>
-            <i class="glyphicon glyphicon-question-sign"></i>
-            {{#tooltip-on-element class="te-tooltip"}}
-              Typically, this is your anomaly period. It is highlighted in orange in the graph above. It also affects the data in views below.
-            {{/tooltip-on-element}}
-          </span>
-        </label>
-      </div>
-      <div class="date-slider__picker-item">
-        {{date-range-picker
-          class="te-range-picker te-range-picker__from"
-          singleDatePicker=true
-          showDropdowns=true
-          timePicker=true
-          timePicker24Hour=true
-          timePickerIncrement=5
-          start=startFormattedOneWay
-          end=startFormattedOneWay
-          maxDate=maxDateFormatted
-          ranges=rangeOptions
-          format=timeFormat
-          serverFormat="YYYY-MM-DD HH:mm"
-          applyAction=(action "onPickerRange" "start")
-        }}
-      </div>
-      <div class="date-slider__picker-item">
-        <label class="te-label te-label--small">to</label>
-      </div>
-      <div class="date-slider__picker-item">
-        {{date-range-picker
-          class="te-range-picker te-range-picker__to"
-          singleDatePicker=true
-          showDropdowns=true
-          timePicker=true
-          timePicker24Hour=true
-          timePickerIncrement=5
-          start=endFormattedOneWay
-          end=endFormattedOneWay
-          maxDate=maxDateFormatted
-          ranges=rangeOptions
-          format=timeFormat
-          serverFormat="YYYY-MM-DD HH:mm"
-          applyAction=(action "onPickerRange" "end")
-        }}
-      </div>
-    </div>
-  </div>
-</div>
diff --git a/thirdeye/thirdeye-frontend/app/utils/rca-utils.js b/thirdeye/thirdeye-frontend/app/utils/rca-utils.js
index 151eaae..4c2103c 100644
--- a/thirdeye/thirdeye-frontend/app/utils/rca-utils.js
+++ b/thirdeye/thirdeye-frontend/app/utils/rca-utils.js
@@ -376,48 +376,62 @@ export function filterPrefix(urns, prefixes) {
 }
 
 /**
- * Converts a time range tuple to another time range with a given offset
+ * Converts a time range tuple to another time range with a given offset (in Pacific time zone)
  *
  * @param {Array} range time range tuple [start, end]
  * @param {string} offset time offset ('current', 'baseline', 'wo1w', 'wo2w', 'wo3w', 'wo4w)
  * @returns {Array} offset time range tuple
  */
 export function toBaselineRange(range, offset) {
-  const offsetWeeks = {
-    current: 0,
-    none: 0,
-    predicted: 0,
-    wow: 1,
-    wo1w: 1,
-    wo2w: 2,
-    wo3w: 3,
-    wo4w: 4,
-    mean4w: 1, // default. not fully supported by backend yet
-    median4w: 1, // default. not fully supported by backend yet
-    min4w: 1, // default. not fully supported by backend yet
-    max4w: 1, // default. not fully supported by backend yet
-    ho1h: 1,
-    ho2h: 1,
-    ho3h: 1,
-    median4h: 1,
-    mean4h: 1,
-    do1d: 1,
-    do2d: 1,
-    do3d: 1,
-    median4d: 1,
-    mean4d: 1,
-    mo1m: 1,
-    mo2m: 1,
-    mo3m: 1,
-    median4m: 1,
-    mean4m: 1
+  const timeOffset = {
+    current: [0, 'weeks'],
+    predicted: [0, 'weeks'], // no backend support
+    none: [0, 'weeks'], // no backend support
+
+    wow: [1, 'weeks'],
+    wo1w: [1, 'weeks'],
+    wo2w: [2, 'weeks'],
+    wo3w: [3, 'weeks'],
+    wo4w: [4, 'weeks'],
+    mean4w: [1, 'weeks'], // no backend support
+    median4w: [1, 'weeks'], // no backend support
+    min4w: [1, 'weeks'], // no backend support
+    max4w: [1, 'weeks'], // no backend support
+
+    ho1h: [1, 'hours'],
+    ho2h: [2, 'hours'],
+    ho3h: [3, 'hours'],
+    ho6h: [6, 'hours'],
+    median6h: [1, 'hours'], // no backend support
+    mean6h: [1, 'hours'], // no backend support
+    min6h: [1, 'hours'], // no backend support
+    max6h: [1, 'hours'], // no backend support
+
+    do1d: [1, 'days'],
+    do2d: [2, 'days'],
+    do3d: [3, 'days'],
+    do4d: [4, 'days'],
+    median4d: [1, 'days'], // no backend support
+    mean4d: [1, 'days'], // no backend support
+    min4d: [1, 'days'], // no backend support
+    max4d: [1, 'days'], // no backend support
+
+    mo1m: [1, 'months'],
+    mo2m: [2, 'months'],
+    mo3m: [3, 'months'],
+    mo6m: [6, 'months'],
+    median6m: [1, 'months'], // no backend support
+    mean6m: [1, 'months'], // no backend support
+    min6m: [1, 'months'], // no backend support
+    max6m: [1, 'months'] // no backend support
+
   }[offset.toLowerCase()];
 
-  if (offsetWeeks === 0) {
+  if (!timeOffset || timeOffset[0] === 0) {
     return range;
   }
 
-  const start = makeTime(range[0]).subtract(offsetWeeks, 'weeks').valueOf();
+  const start = makeTime(range[0]).subtract(timeOffset[0], timeOffset[1]).valueOf();
   const end = start + (range[1] - range[0]);
 
   return [start, end];


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org
For additional commands, e-mail: commits-help@pinot.apache.org