You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pinot.apache.org by ji...@apache.org on 2019/02/22 18:39:05 UTC

[incubator-pinot] branch master updated: [TE] frontend - harleyjj/alert-details - multiple alert overview improvements for MVP (#3863)

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

jihao 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 4f96cba  [TE] frontend - harleyjj/alert-details - multiple alert overview improvements for MVP (#3863)
4f96cba is described below

commit 4f96cbaf896eebd76751da3c0058856a044f4fab
Author: Harley Jackson <ha...@gmail.com>
AuthorDate: Fri Feb 22 10:38:59 2019 -0800

    [TE] frontend - harleyjj/alert-details - multiple alert overview improvements for MVP (#3863)
    
    1. Implements dimension handling for alert preview and overview
    2. Implements anomaly labeling for new alert overview
    3. Adjust date pill defaults and normalize timestamp generation to startOf('day')
    4. address eslint warnings
    5. Address styling issues in Preview and Alert Overview
    6. Change "View Documentation" buttons to "View Docs & Examples"
    7. Point alert page link to new Alert Overview instead of yaml editor
---
 .../app/pods/components/alert-details/component.js | 264 +++++++++++++++------
 .../app/pods/components/alert-details/template.hbs | 132 +++++++----
 .../self-serve-alert-details/template.hbs          |   2 +-
 .../self-serve-alert-yaml-details/template.hbs     |   2 +-
 .../app/pods/components/yaml-editor/template.hbs   |   4 +-
 .../custom/anomalies-table/dimensions/template.hbs |   2 +-
 .../app/pods/manage/yaml/template.hbs              |   2 +-
 thirdeye/thirdeye-frontend/app/utils/anomaly.js    |  33 +++
 .../app/utils/manage-alert-utils.js                |  20 +-
 9 files changed, 323 insertions(+), 138 deletions(-)

diff --git a/thirdeye/thirdeye-frontend/app/pods/components/alert-details/component.js b/thirdeye/thirdeye-frontend/app/pods/components/alert-details/component.js
index d2deb78..3ec89e6 100644
--- a/thirdeye/thirdeye-frontend/app/pods/components/alert-details/component.js
+++ b/thirdeye/thirdeye-frontend/app/pods/components/alert-details/component.js
@@ -14,11 +14,17 @@
  */
 
 import Component from '@ember/component';
-import { computed, observer, set, get, getProperties } from '@ember/object';
+import { computed, observer, set, get, getProperties, getWithDefault } from '@ember/object';
 import { later } from '@ember/runloop';
 import { checkStatus, humanizeFloat } from 'thirdeye-frontend/utils/utils';
-import { colorMapping, toColor, makeTime } from 'thirdeye-frontend/utils/rca-utils';
-import { getYamlPreviewAnomalies, getAnomaliesByAlertId, getFormattedDuration } from 'thirdeye-frontend/utils/anomaly';
+import { colorMapping, toColor, makeTime, toMetricLabel, extractTail } from 'thirdeye-frontend/utils/rca-utils';
+import { getYamlPreviewAnomalies,
+  getAnomaliesByAlertId,
+  getFormattedDuration,
+  anomalyResponseMapNew,
+  anomalyResponseObj,
+  updateAnomalyFeedback,
+  verifyAnomalyFeedback  } from 'thirdeye-frontend/utils/anomaly';
 import { inject as service } from '@ember/service';
 import { task } from 'ember-concurrency';
 import floatToPercent from 'thirdeye-frontend/utils/float-to-percent';
@@ -32,7 +38,7 @@ const TIME_PICKER_INCREMENT = 5; // tells date picker hours field how granularly
 const DEFAULT_ACTIVE_DURATION = '1m'; // setting this date range selection as default (Last 24 Hours)
 const UI_DATE_FORMAT = 'MMM D, YYYY hh:mm a'; // format for date picker to use (usually varies by route or metric)
 const DISPLAY_DATE_FORMAT = 'YYYY-MM-DD HH:mm'; // format used consistently across app to display custom date range
-const TIME_RANGE_OPTIONS = ['1m', '3m'];
+const TIME_RANGE_OPTIONS = ['1w', '1m', '3m'];
 
 export default Component.extend({
   anomaliesApiService: service('services/api/anomalies'),
@@ -54,6 +60,7 @@ export default Component.extend({
   },
   errorTimeseries: null,
   metricUrn: null,
+  metricUrnList: [],
   errorBaseline: null,
   compareMode: 'wo1w',
   baseline: null,
@@ -82,14 +89,51 @@ export default Component.extend({
   currentPage: 1,
   isPreviewMode: false,
   alertId: null,
+  feedbackOptions: ['Not reviewed yet', 'Yes - unexpected', 'Expected temporary change', 'Expected permanent change', 'No change observed'],
+  labelMap: anomalyResponseMapNew,
+  labelResponse: {},
+  selectedDimension: null,
 
 
-  updateVisuals: observer('analysisRange', function() {
-    const isPreviewMode = get(this, 'isPreviewMode');
-    if(!isPreviewMode) {
-      this._fetchAnomalies();
+  updateVisuals: observer(
+    'analysisRange',
+    'metricUrn',
+    function() {
+      const isPreviewMode = get(this, 'isPreviewMode');
+      if(!isPreviewMode) {
+        this._fetchAnomalies();
+      } else {
+        this._fetchTimeseries();
+      }
+    }),
+
+  /**
+   * Whether the alert has multiple dimensions
+   * @type {Boolean}
+   */
+  dimensionOptions: computed(
+    'metricUrnList',
+    function() {
+      const metricUrnList = get(this, 'metricUrnList');
+      let options = [];
+      metricUrnList.forEach(urn => {
+        options.push(toMetricLabel(extractTail(decodeURIComponent(urn))));
+      });
+      return options;
     }
-  }),
+  ),
+
+  /**
+   * Whether the alert has multiple dimensions
+   * @type {Boolean}
+   */
+  alertHasDimensions: computed(
+    'metricUrnList',
+    function() {
+      const metricUrnList = get(this, 'metricUrnList');
+      return (metricUrnList.length > 1);
+    }
+  ),
 
   /**
    * Table pagination: number of pages to display
@@ -224,30 +268,30 @@ export default Component.extend({
     'analysisRange',
     function () {
       const {
-        metricUrn, anomalies, timeseries, baseline, analysisRange
+        metricUrn, anomalies, timeseries, baseline
       } = getProperties(this, 'metricUrn', 'anomalies', 'timeseries',
-        'baseline', 'analysisRange');
+        'baseline');
 
       const series = {};
 
       if (!_.isEmpty(anomalies)) {
 
-          anomalies
-            .filter(anomaly => anomaly.metricUrn === metricUrn)
-            .forEach(anomaly => {
-              const key = this._formatAnomaly(anomaly);
-              series[key] = {
-                timestamps: [anomaly.startTime, anomaly.endTime],
-                values: [1, 1],
-                type: 'line',
-                color: 'teal',
-                axis: 'y2'
-              };
-              series[key + '-region'] = Object.assign({}, series[key], {
-                type: 'region',
-                color: 'orange'
-              });
+        anomalies
+          .filter(anomaly => anomaly.metricUrn === metricUrn)
+          .forEach(anomaly => {
+            const key = this._formatAnomaly(anomaly);
+            series[key] = {
+              timestamps: [anomaly.startTime, anomaly.endTime],
+              values: [1, 1],
+              type: 'line',
+              color: 'teal',
+              axis: 'y2'
+            };
+            series[key + '-region'] = Object.assign({}, series[key], {
+              type: 'region',
+              color: 'orange'
             });
+          });
       }
 
       if (timeseries && !_.isEmpty(timeseries.value)) {
@@ -267,7 +311,6 @@ export default Component.extend({
           color: 'light-' + toColor(metricUrn)
         };
       }
-
       return series;
     }
   ),
@@ -279,12 +322,15 @@ export default Component.extend({
    */
   tableAnomalies: computed(
     'anomalies',
+    'labelResponse',
     function() {
       const anomalies = get(this, 'anomalies');
+      const labelResponse = get(this, 'labelResponse');
       let tableData = [];
       let i = 1;
 
       anomalies.forEach(a => {
+        const change = (a.avgBaselineVal !== 0) ? (a.avgCurrentVal/a.avgBaselineVal - 1.0) * 100.0 : 0;
         let tableRow = {
           number: i,
           anomalyId: a.id,
@@ -293,12 +339,18 @@ export default Component.extend({
           durationStr: getFormattedDuration(a.startTime, a.endTime),
           shownCurrent: humanizeFloat(a.avgCurrentVal),
           shownBaseline: humanizeFloat(a.avgBaselineVal),
-          change: ((a.avgCurrentVal/a.avgBaselineVal - 1.0) * 100.0),
-          shownChangeRate: humanizeFloat(((a.avgCurrentVal/a.avgBaselineVal - 1.0) * 100.0))
+          change: change,
+          shownChangeRate: humanizeFloat(change),
+          anomalyFeedback: a.feedback ? a.feedback.feedbackType : a.statusClassification,
+          dimensionList: Object.keys(a.dimensions),
+          dimensions: a.dimensions,
+          showResponseSaved: (labelResponse.anomalyId === a.id) ? labelResponse.showResponseSaved : false,
+          showResponseFailed: (labelResponse.anomalyId === a.id) ? labelResponse.showResponseFailed: false
         };
         tableData.push(tableRow);
         i++;
       });
+
       return tableData;
     }
   ),
@@ -378,10 +430,10 @@ export default Component.extend({
       const endDate = Number(analysisRange[1]) || Number(get(this, 'endDate'));
       const duration = get(this, 'duration') || DEFAULT_ACTIVE_DURATION;
       const predefinedRanges = {
-        'Today': [moment().startOf('day'), moment()],
+        'Today': [moment().startOf('day'), moment().startOf('day').add(1, 'days')],
         'Last 24 hours': [moment().subtract(1, 'day'), moment()],
-        'Yesterday': [moment().subtract(1, 'day').startOf('day'), moment().subtract(1, 'days').endOf('day')],
-        'Last Week': [moment().subtract(1, 'week'), moment()]
+        'Yesterday': [moment().subtract(1, 'day').startOf('day'), moment().startOf('day')],
+        'Last Week': [moment().subtract(1, 'week').startOf('day'), moment().startOf('day')]
       };
 
       return {
@@ -401,9 +453,8 @@ export default Component.extend({
       analysisRange,
       notifications,
       isPreviewMode,
-      alertId,
-      metricUrn,
-    } = this.getProperties('analysisRange', 'notifications', 'isPreviewMode', 'alertId', 'metricUrn');
+      alertId
+    } = this.getProperties('analysisRange', 'notifications', 'isPreviewMode', 'alertId');
 
     //detection alert fetch
     const start = analysisRange[0];
@@ -413,7 +464,10 @@ export default Component.extend({
     try {
       if(isPreviewMode){
         applicationAnomalies = yield getYamlPreviewAnomalies(alertYaml, start, end);
-        set(this, 'metricUrn', Object.keys(applicationAnomalies.diagnostics['0'])[0]);
+        const metricUrnList = Object.keys(applicationAnomalies.diagnostics['0']);
+        set(this, 'metricUrnList', metricUrnList);
+        set(this, 'selectedDimension', toMetricLabel(extractTail(decodeURIComponent(metricUrnList[0]))));
+        set(this, 'metricUrn', metricUrnList[0]);
         anomalies = applicationAnomalies.anomalies;
       } else {
         applicationAnomalies = yield getAnomaliesByAlertId(alertId, start, end);
@@ -452,8 +506,11 @@ export default Component.extend({
     this._super(...arguments);
     const isPreviewMode = get(this, 'isPreviewMode');
     if (!isPreviewMode) {
-      set(this, 'analysisRange', [moment().subtract(1, 'month').startOf('hour').valueOf(), moment().startOf('hour').valueOf()])
+      set(this, 'analysisRange', [moment().subtract(1, 'month').startOf('hour').valueOf(), moment().startOf('hour').valueOf()]);
+      set(this, 'duration', '1m');
       this._fetchAnomalies();
+    } else {
+      set(this, 'duration', '1w');
     }
   },
 
@@ -540,18 +597,18 @@ export default Component.extend({
     try {
       const content = get(this, 'alertYaml');
       this.get('_getAnomalyMapping').perform(content)
-      .then(results => {
-        this.setProperties({
-          anomalyMapping: results.anomalyMapping,
-          anomalies: results.anomalies,
-          isLoading: false
+        .then(results => {
+          this.setProperties({
+            anomalyMapping: results.anomalyMapping,
+            anomalies: results.anomalies,
+            isLoading: false
+          });
+          if (get(this, 'metricUrn')) {
+            this._fetchTimeseries();
+          } else {
+            throw new Error('Unable to get MetricUrn from response');
+          }
         });
-        if (get(this, 'metricUrn')) {
-          this._fetchTimeseries();
-        } else {
-          throw new Error('Unable to get MetricUrn from response');
-        }
-      });
     } catch (error) {
       set(this, 'isLoading', false);
       throw new Error(`Unable to retrieve anomaly data. ${error}`);
@@ -560,31 +617,96 @@ export default Component.extend({
 
   actions: {
     /**
+     * Handle dynamically saving anomaly feedback responses
+     * @method onChangeAnomalyResponse
+     * @param {Object} anomalyRecord - the anomaly being responded to
+     * @param {String} selectedResponse - user-selected anomaly feedback option
+     * @param {Object} inputObj - the selection object
+     */
+    onChangeAnomalyFeedback: async function(anomalyRecord, selectedResponse, inputObj) {
+      const labelMap = get(this, 'labelMap');
+      const loadedResponsesArr = [];
+      const newOptionsArr = [];
+      // Update select field
+      set(inputObj, 'selected', selectedResponse);
+      // Reset status icon
+      set(this, 'renderStatusIcon', false);
+      const responseObj = anomalyResponseObj.find(res => res.name === selectedResponse);
+      try {
+        // Save anomaly feedback
+        await updateAnomalyFeedback(anomalyRecord.anomalyId, responseObj.value);
+        // We make a call to ensure our new response got saved
+        const anomaly = await verifyAnomalyFeedback(anomalyRecord.anomalyId, responseObj.status);
+        const filterMap = getWithDefault(anomaly, 'searchFilters.statusFilterMap', null);
+        // This verifies that the status change got saved as key in the anomaly statusFilterMap property
+        const keyPresent = filterMap && Object.keys(filterMap).find(key => responseObj.status.includes(key));
+        if (keyPresent) {
+          this.set('labelResponse', {
+            anomalyId: anomalyRecord.id,
+            showResponseSaved: true,
+            showResponseFailed: false
+          });
+
+          // Collect all available new labels
+          loadedResponsesArr.push(responseObj.status, ...get(this, 'anomalyData').mapBy('anomalyFeedback'));
+          loadedResponsesArr.forEach((response) => {
+            if (labelMap[response]) { newOptionsArr.push(labelMap[response]); }
+          });
+          // Update resolutionOptions array - we may have a new option now
+          set(this, 'resolutionOptions', [ ...new Set([ 'All Resolutions', ...newOptionsArr ])]);
+        } else {
+          throw 'Response not saved';
+        }
+      } catch (err) {
+        this.set('labelResponse', {
+          anomalyId: anomalyRecord.id,
+          showResponseSaved: false,
+          showResponseFailed: true
+        });
+      }
+      // Force status icon to refresh
+      set(this, 'renderStatusIcon', true);
+    },
+
+    onSelectDimension(selected) {
+      const metricUrnList = get(this, 'metricUrnList');
+      const newMetricUrn = metricUrnList.find(urn => {
+        if (toMetricLabel(extractTail(decodeURIComponent(urn))) === selected) {
+          return urn;
+        }
+      });
+      this.setProperties({
+        metricUrn: newMetricUrn,
+        selectedDimension: toMetricLabel(extractTail(decodeURIComponent(newMetricUrn)))
+      });
+    },
+
+    /**
       * Action handler for page clicks
       * @param {Number|String} page
       */
-     onPaginationClick(page) {
-       let newPage = page;
-       let currentPage = this.get('currentPage');
-
-       switch (page) {
-         case 'previous':
-           if (currentPage > 1) {
-             newPage = --currentPage;
-           } else {
-             newPage = currentPage;
-           }
-           break;
-         case 'next':
-         if (currentPage < this.get('pagesNum')) {
-           newPage = ++currentPage;
-         } else {
-           newPage = currentPage;
-         }
-           break;
-       }
-       this.set('currentPage', newPage);
-     },
+    onPaginationClick(page) {
+      let newPage = page;
+      let currentPage = this.get('currentPage');
+
+      switch (page) {
+        case 'previous':
+          if (currentPage > 1) {
+            newPage = --currentPage;
+          } else {
+            newPage = currentPage;
+          }
+          break;
+        case 'next':
+          if (currentPage < this.get('pagesNum')) {
+            newPage = ++currentPage;
+          } else {
+            newPage = currentPage;
+          }
+          break;
+      }
+      this.set('currentPage', newPage);
+    },
 
     /**
      * Sets the new custom date range for anomaly coverage
@@ -654,6 +776,6 @@ export default Component.extend({
 
       //On sort, set table to first pagination page
       this.set('currentPage', 1);
-    },
+    }
   }
 });
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/alert-details/template.hbs b/thirdeye/thirdeye-frontend/app/pods/components/alert-details/template.hbs
index 7b7ebcb..e244671 100644
--- a/thirdeye/thirdeye-frontend/app/pods/components/alert-details/template.hbs
+++ b/thirdeye/thirdeye-frontend/app/pods/components/alert-details/template.hbs
@@ -18,52 +18,82 @@
         {{ember-spinner scale=0.5 rotate=10 speed='1.1' color='#3498DB'}}Please wait while we compile the data.
       {{else}}
         {{#if dataIsCurrent}}
-         <div class="te-content-block">
-          {{range-pill-selectors
-            title="Showing"
-            uiDateFormat=pill.uiDateFormat
-            activeRangeEnd=pill.activeRangeEnd
-            activeRangeStart=pill.activeRangeStart
-            timeRangeOptions=pill.timeRangeOptions
-            timePickerIncrement=pill.timePickerIncrement
-            predefinedRanges=pill.predefinedRanges
-            selectAction=(action "onRangeSelection")
-          }}
-          <div class="te-horizontal-cards te-content-block">
-            <h4 class="te-self-serve__block-title">
-              <label for="select-dimension" class="control-label te-label">
-                Alert Performance
-                <span>
-                  <i class="glyphicon glyphicon-question-sign"></i>
-                  {{#tooltip-on-element class="te-tooltip"}}
-                    All estimated performance numbers are based on reviewed anomalies.
-                  {{/tooltip-on-element}}
-                </span>
-              </label>
-            </h4>
-            <div class="te-horizontal-cards__container">
-              {{!-- Alert anomaly stats cards --}}
-              {{stats-cards stats=stats}}
-            </div>
+        {{range-pill-selectors
+          title="Showing"
+          uiDateFormat=pill.uiDateFormat
+          activeRangeEnd=pill.activeRangeEnd
+          activeRangeStart=pill.activeRangeStart
+          timeRangeOptions=pill.timeRangeOptions
+          timePickerIncrement=pill.timePickerIncrement
+          predefinedRanges=pill.predefinedRanges
+          selectAction=(action "onRangeSelection")
+        }}
+        <div class="te-horizontal-cards te-content-block">
+          <h4 class="te-self-serve__block-title">
+            <label for="select-dimension" class="control-label te-label">
+              Alert Performance
+              <span>
+                <i class="glyphicon glyphicon-question-sign"></i>
+                {{#tooltip-on-element class="te-tooltip"}}
+                  All estimated performance numbers are based on reviewed anomalies.
+                {{/tooltip-on-element}}
+              </span>
+            </label>
+          </h4>
+          {{!-- Alert anomaly stats cards --}}
+          {{stats-cards stats=stats}}
 
-            {{#if repRunStatus}}
-              <p class="te-self-serve__block-subtext te-self-serve__block-subtext--normal">Replay in progress. Please check back later...</p>
-            {{/if}}
-          </div>
-          {{timeseries-chart
-            series=series
-            colorMapping=colorMapping
-            axis=axis
-            zoom=zoom
-            legend=legend
-          }}
-          {{#if anomalies}}
-            {{!-- Baseline type selector --}}
-            {{range-pill-selectors
-              title="Baseline"
-              timeRangeOptions=baselineOptions
-              selectAction=(action "onBaselineOptionClick")
+          {{#if repRunStatus}}
+            <p class="te-self-serve__block-subtext te-self-serve__block-subtext--normal">Replay in progress. Please check back later...</p>
+          {{/if}}
+        </div>
+
+        <div class="te-content-block">
+          {{#if alertHasDimensions}}
+            <h4 class="te-self-serve__block-title">Anomalies over time for dimension {{selectedDimension}}</h4>
+          {{else}}
+            <h4 class="te-self-serve__block-title">Anomalies over time </h4>
+          {{/if}}
+          {{#if alertHasDimensions}}
+            <div class="te-form__select te-form__select--wider col-md-3">
+              {{#power-select
+                triggerId="select-dimension"
+                triggerClass="te-form__select"
+                options=dimensionOptions
+                searchEnabled=true
+                searchPlaceholder="Type to filter..."
+                matchTriggerWidth=true
+                matchContentWidth=true
+                selected=selectedDimension
+                onchange=(action "onSelectDimension")
+                as |dimension|
+              }}
+                {{dimension}}
+              {{/power-select}}
+            </div>
+          {{/if}}
+          <div class="col-xs-12 te-graph-container">
+            {{timeseries-chart
+              series=series
+              colorMapping=colorMapping
+              axis=axis
+              zoom=zoom
+              legend=legend
             }}
+            {{#unless isPreviewMode}}
+              <div class="te-form__note">
+                NOTE: If you find the metric shown above is inconsistent, please email <a class="thirdeye-link-secondary" target="_blank" href="{{graphMailtoLink}}">ask_thirdeye</a>.
+              </div>
+            {{/unless}}
+        </div>
+        {{!-- Baseline type selector --}}
+        {{range-pill-selectors
+          title="Baseline"
+          timeRangeOptions=baselineOptions
+          selectAction=(action "onBaselineOptionClick")
+        }}
+          {{#if anomalies}}
+
             {{!-- Alert anomaly table --}}
             <div class="te-block-container">
               <table class="te-anomaly-table">
@@ -90,7 +120,7 @@
                           <i class="te-anomaly-table__icon glyphicon {{if sortColumnChangeUp "glyphicon-menu-up" "glyphicon-menu-down"}}"></i>
                         </a>
                       </th>
-                      {{#if notPreview}}
+                      {{#unless isPreviewMode}}
                         <th class="te-anomaly-table__cell-head">
                           <a class="te-anomaly-table__cell-link" {{action "toggleSortDirection" "feedback"}}>
                             Feedback
@@ -98,7 +128,7 @@
                           </a>
                         </th>
                         <th class="te-anomaly-table__cell-head"></th>
-                      {{/if}}
+                      {{/unless}}
                     </tr>
                   </thead>
                 {{/if}}
@@ -125,7 +155,7 @@
                           <ul class="te-anomaly-table__list">
                            {{#each anomaly.dimensionList as |dimension|}}
                               <li class="te-anomaly-table__list-item te-anomaly-table__list-item--smaller" title="{{dimension.dimensionVal}}">
-                                {{dimension.dimensionKey}}: <span class="stronger">{{dimension.dimensionVal}}</span>
+                                {{dimension}}: <span class="stronger">{{get anomaly.dimensions dimension}}</span>
                               </li>
                            {{else}}
                               -
@@ -145,7 +175,7 @@
                           </li>
                         </ul>
                        </td>
-                       {{#if notPreview}}
+                       {{#unless isPreviewMode}}
                          <td class="te-anomaly-table__cell">
                             {{#if renderStatusIcon}}
                               {{#if anomaly.showResponseSaved}}
@@ -168,10 +198,10 @@
                               {{#power-select
                                 triggerId=anomaly.anomalyId
                                 triggerClass="te-anomaly-table__select"
-                                options=responseOptions
+                                options=feedbackOptions
                                 searchEnabled=false
                                 selected=(get labelMap anomaly.anomalyFeedback)
-                                onchange=(action "onChangeAnomalyResponse" anomaly)
+                                onchange=(action "onChangeAnomalyFeedback" anomaly)
                                 as |response|
                               }}
                                 {{response}}
@@ -185,7 +215,7 @@
                               {{/link-to}}
                             </div>
                          </td>
-                       {{/if}}
+                       {{/unless}}
                     </tr>
                   {{/each}}
                 </tbody>
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/self-serve-alert-details/template.hbs b/thirdeye/thirdeye-frontend/app/pods/components/self-serve-alert-details/template.hbs
index 049a441..efe6cb4 100644
--- a/thirdeye/thirdeye-frontend/app/pods/components/self-serve-alert-details/template.hbs
+++ b/thirdeye/thirdeye-frontend/app/pods/components/self-serve-alert-details/template.hbs
@@ -13,7 +13,7 @@
       </div>
       {{#if (eq displayMode "list")}}
         {{#if alertData.isNewPipeline}}
-          {{#link-to "manage.yaml" alertData.id}}
+          {{#link-to "manage.explore-new" alertData.id}}
             <div class="te-search-results__title-name" title={{alertData.functionName}}>{{alertData.functionName}}</div>
           {{/link-to}}
         {{else}}
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/self-serve-alert-yaml-details/template.hbs b/thirdeye/thirdeye-frontend/app/pods/components/self-serve-alert-yaml-details/template.hbs
index 81deb18..caac5a1 100644
--- a/thirdeye/thirdeye-frontend/app/pods/components/self-serve-alert-yaml-details/template.hbs
+++ b/thirdeye/thirdeye-frontend/app/pods/components/self-serve-alert-yaml-details/template.hbs
@@ -10,7 +10,7 @@
         {{/if}}
       </div>
       {{#if (eq displayMode "list")}}
-        {{#link-to "manage.yaml" alertData.id}}
+        {{#link-to "manage.explore-new" alertData.id}}
           <div class="te-search-results__title-name" title={{alertData.functionName}}>{{alertData.functionName}}</div>
         {{/link-to}}
       {{/if}}
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/yaml-editor/template.hbs b/thirdeye/thirdeye-frontend/app/pods/components/yaml-editor/template.hbs
index 3f46c86..5fd0080 100644
--- a/thirdeye/thirdeye-frontend/app/pods/components/yaml-editor/template.hbs
+++ b/thirdeye/thirdeye-frontend/app/pods/components/yaml-editor/template.hbs
@@ -19,7 +19,7 @@
         class="te-button te-button--link"
       }}
       {{bs-button
-        defaultText="View Documentation"
+        defaultText="View Docs & Examples"
         type="outline-primary"
         buttonType="link"
         onClick=(action "triggerDoc" "Anomaly")
@@ -100,7 +100,7 @@
           class="te-button te-button--link"
         }}
         {{bs-button
-          defaultText="View Documentation"
+          defaultText="View Docs & Examples"
           type="outline-primary"
           buttonType="link"
           onClick=(action "triggerDoc" "subscription")
diff --git a/thirdeye/thirdeye-frontend/app/pods/custom/anomalies-table/dimensions/template.hbs b/thirdeye/thirdeye-frontend/app/pods/custom/anomalies-table/dimensions/template.hbs
index 411b2f0..0ee3aee 100644
--- a/thirdeye/thirdeye-frontend/app/pods/custom/anomalies-table/dimensions/template.hbs
+++ b/thirdeye/thirdeye-frontend/app/pods/custom/anomalies-table/dimensions/template.hbs
@@ -1,7 +1,7 @@
 <ul class="te-anomaly-table__list">
   <li class="te-anomaly-table__list-item" title="{{record.anomaly.functionName}}">
     {{#if record.anomaly.detectionConfigId}}
-      {{#link-to "manage.yaml" record.anomaly.detectionConfigId class="te-anomaly-table__link"}}
+      {{#link-to "manage.explore-new" record.anomaly.detectionConfigId class="te-anomaly-table__link"}}
         {{record.anomaly.functionName}}
       {{/link-to}}
     {{else}}
diff --git a/thirdeye/thirdeye-frontend/app/pods/manage/yaml/template.hbs b/thirdeye/thirdeye-frontend/app/pods/manage/yaml/template.hbs
index 999f91d..9312dff 100644
--- a/thirdeye/thirdeye-frontend/app/pods/manage/yaml/template.hbs
+++ b/thirdeye/thirdeye-frontend/app/pods/manage/yaml/template.hbs
@@ -6,7 +6,7 @@
     }}
     <div class="te-search-results__cta">
       {{#link-to "manage.explore-new" model.alertId}}
-        <button class="te-button te-button--outline">Alert Overview</button>
+        <button class="te-button te-button--outline">Back to Overview</button>
       {{/link-to}}
     </div>
     {{/self-serve-alert-yaml-details}}
diff --git a/thirdeye/thirdeye-frontend/app/utils/anomaly.js b/thirdeye/thirdeye-frontend/app/utils/anomaly.js
index 98032c4..84c44a4 100644
--- a/thirdeye/thirdeye-frontend/app/utils/anomaly.js
+++ b/thirdeye/thirdeye-frontend/app/utils/anomaly.js
@@ -41,6 +41,29 @@ export const anomalyResponseObj = [
   }
 ];
 
+export const anomalyResponseObjNew = [
+  { name: 'Not reviewed yet',
+    value: 'NONE',
+    status: 'Not Resolved'
+  },
+  { name: 'Yes - unexpected',
+    value: 'ANOMALY',
+    status: 'Confirmed Anomaly'
+  },
+  { name: 'Expected temporary change',
+    value: 'ANOMALY_EXPECTED',
+    status: 'Expected Anomaly'
+  },
+  { name: 'Expected permanent change',
+    value: 'ANOMALY_NEW_TREND',
+    status: 'Confirmed - New Trend'
+  },
+  { name: 'No change observed',
+    value: 'NOT_ANOMALY',
+    status: 'False Alarm'
+  }
+];
+
 /**
  * Mapping for anomalyResponseObj 'status' to 'name' for easy lookup
  */
@@ -49,6 +72,14 @@ anomalyResponseObj.forEach((obj) => {
   anomalyResponseMap[obj.status] = obj.name;
 });
 
+/**
+ * Mapping for anomalyResponseObjNew 'value' to 'name' for easy lookup
+ */
+export let anomalyResponseMapNew = {};
+anomalyResponseObjNew.forEach((obj) => {
+  anomalyResponseMapNew[obj.value] = obj.name;
+});
+
 
 /**
  * Update feedback status on any anomaly
@@ -137,6 +168,8 @@ export function pluralizeTime(time, unit) {
 export default {
   anomalyResponseObj,
   anomalyResponseMap,
+  anomalyResponseObjNew,
+  anomalyResponseMapNew,
   updateAnomalyFeedback,
   getFormattedDuration,
   verifyAnomalyFeedback,
diff --git a/thirdeye/thirdeye-frontend/app/utils/manage-alert-utils.js b/thirdeye/thirdeye-frontend/app/utils/manage-alert-utils.js
index c32f178..6d48070 100644
--- a/thirdeye/thirdeye-frontend/app/utils/manage-alert-utils.js
+++ b/thirdeye/thirdeye-frontend/app/utils/manage-alert-utils.js
@@ -162,22 +162,22 @@ export function setUpTimeRangeOptions(datesKeys, duration) {
       [ 'today', ['Today'] ]
     ]);
 
-   datesKeys.forEach((value) => {
-     const currVal = dateKeyMap.get(value);
-     const label = currVal[0];
-     let start = moment().subtract(currVal[1], currVal[2]).utc();
-     switch(label) {
+  datesKeys.forEach((value) => {
+    const currVal = dateKeyMap.get(value);
+    const label = currVal[0];
+    let start = moment().subtract(currVal[1], currVal[2]).startOf('day');
+    switch(label) {
       case 'Today':
         start = moment().startOf('day');
         break;
       case 'Yesterday':
         start = moment().subtract(1, 'day').startOf('day');
         break;
-     }
-     const end = (label === 'Yesterday') ? moment().subtract(1, 'days').endOf('day') : moment();
-     const isActive = duration === value;
-     newRangeArr.push({ name: label, value, start, end, isActive });
-   });
+    }
+    const end = (label === 'Yesterday') ? moment().startOf('day') : moment().startOf('day').add(1, 'days');
+    const isActive = duration === value;
+    newRangeArr.push({ name: label, value, start, end, isActive });
+  });
 
   newRangeArr.push(defaultCustomRange);
   return newRangeArr;


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