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

[incubator-pinot] branch master updated: [TE] frontend - harleyjj/alert-details - updates to alert-details component (#3811)

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

akshayrai09 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 5dec913  [TE] frontend - harleyjj/alert-details - updates to alert-details component (#3811)
5dec913 is described below

commit 5dec9131c939eb037767944d530ced09f7771a9c
Author: Harley Jackson <ha...@gmail.com>
AuthorDate: Fri Feb 8 16:39:28 2019 -0800

    [TE] frontend - harleyjj/alert-details - updates to alert-details component (#3811)
---
 .../app/pods/components/alert-details/component.js | 149 ++++++--
 .../app/pods/components/alert-details/template.hbs | 381 +++++++++++----------
 .../app/pods/components/yaml-editor/component.js   |   4 +
 .../app/pods/components/yaml-editor/template.hbs   |   4 +-
 4 files changed, 333 insertions(+), 205 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 34259fa..dc647a9 100644
--- a/thirdeye/thirdeye-frontend/app/pods/components/alert-details/component.js
+++ b/thirdeye/thirdeye-frontend/app/pods/components/alert-details/component.js
@@ -40,7 +40,6 @@ export default Component.extend({
   timeseries: null,
   isLoading: false,
   analysisRange: [moment().subtract(1, 'month').startOf('hour').valueOf(), moment().startOf('hour').valueOf()],
-  displayRange: [moment().subtract(2, 'month').startOf('hour').valueOf(), moment().startOf('hour').valueOf()],
   isPendingData: false,
   colorMapping: colorMapping,
   zoom: {
@@ -73,12 +72,14 @@ export default Component.extend({
     { name: 'none', isActive: false}
   ],
   sortColumnStartUp: false,
-  sortColumnScoreUp: false,
   sortColumnChangeUp: false,
   sortColumnNumberUp: true,
   sortColumnResolutionUp: false,
   selectedSortMode: '',
   selectedBaseline: 'wo1w',
+  pageSize: 10,
+  currentPage: 1,
+
 
   // alertYamlChanged: observer('alertYaml', 'analysisRange', 'disableYamlSave', async function() {
   //   set(this, 'isPendingData', true);
@@ -96,6 +97,87 @@ export default Component.extend({
   //   }
   // }),
 
+  /**
+   * Table pagination: number of pages to display
+   * @type {Number}
+   */
+  paginationSize: computed(
+    'pagesNum',
+    'pageSize',
+    function() {
+      const { pagesNum, pageSize } = this.getProperties('pagesNum', 'pageSize');
+      return Math.min(pagesNum, pageSize/2);
+    }
+  ),
+
+  /**
+   * Table pagination: total Number of pages to display
+   * @type {Number}
+   */
+  pagesNum: computed(
+    'tableAnomalies',
+    'pageSize',
+    function() {
+      const { tableAnomalies, pageSize } = this.getProperties('tableAnomalies', 'pageSize');
+      const anomalyCount = tableAnomalies.length || 0;
+      return Math.ceil(anomalyCount/pageSize);
+    }
+  ),
+
+  /**
+   * Table pagination: creates the page Array for view
+   * @type {Array}
+   */
+  viewPages: computed(
+    'pages',
+    'currentPage',
+    'paginationSize',
+    'pagesNum',
+    function() {
+      const {
+        currentPage,
+        pagesNum: max,
+        paginationSize: size
+      } = this.getProperties('currentPage', 'pagesNum', 'paginationSize');
+      const step = Math.floor(size / 2);
+
+      if (max === 1) { return; }
+
+      const startingNumber = ((max - currentPage) < step)
+        ? Math.max(max - size + 1, 1)
+        : Math.max(currentPage - step, 1);
+
+      return [...new Array(size)].map((page, index) => startingNumber + index);
+    }
+  ),
+
+  /**
+   * Table pagination: pre-filtered and sorted anomalies with pagination
+   * @type {Array}
+   */
+  paginatedFilteredAnomalies: computed(
+    'tableAnomalies',
+    'pageSize',
+    'currentPage',
+    'selectedSortMode',
+    function() {
+      let anomalies = this.get('tableAnomalies');
+      const { pageSize, currentPage, selectedSortMode } = getProperties(this, 'pageSize', 'currentPage', 'selectedSortMode');
+
+      if (selectedSortMode) {
+        let [ sortKey, sortDir ] = selectedSortMode.split(':');
+
+        if (sortDir === 'up') {
+          anomalies = anomalies.sortBy(sortKey);
+        } else {
+          anomalies = anomalies.sortBy(sortKey).reverse();
+        }
+      }
+
+      return anomalies.slice((currentPage - 1) * pageSize, currentPage * pageSize);
+    }
+  ),
+
   disablePreviewButton: computed(
     'alertYaml',
     'isLoading',
@@ -105,9 +187,9 @@ export default Component.extend({
   ),
 
   axis: computed(
-    'displayRange',
+    'analysisRange',
     function () {
-      const displayRange = getProperties(this, 'displayRange');
+      const analysisRange = getProperties(this, 'analysisRange');
 
       return {
         y: {
@@ -124,8 +206,8 @@ export default Component.extend({
         x: {
           type: 'timeseries',
           show: true,
-          min: displayRange[0],
-          max: displayRange[1],
+          min: analysisRange[0],
+          max: analysisRange[1],
           tick: {
             fit: false,
             format: (d) => {
@@ -146,12 +228,11 @@ export default Component.extend({
     'timeseries',
     'baseline',
     'analysisRange',
-    'displayRange',
     function () {
       const {
-        metricUrn, anomalies, timeseries, baseline, analysisRange, displayRange
+        metricUrn, anomalies, timeseries, baseline, analysisRange
       } = getProperties(this, 'metricUrn', 'anomalies', 'timeseries',
-        'baseline', 'analysisRange', 'displayRange');
+        'baseline', 'analysisRange');
 
       const series = {};
 
@@ -193,16 +274,6 @@ export default Component.extend({
         };
       }
 
-      // detection range
-      if (timeseries && !_.isEmpty(timeseries.value)) {
-        series['pre-detection-region'] = {
-          timestamps: [displayRange[0], analysisRange[0]],
-          values: [1, 1],
-          type: 'region',
-          color: 'grey'
-        };
-      }
-
       return series;
     }
   ),
@@ -221,11 +292,12 @@ export default Component.extend({
 
       anomalies.forEach(a => {
         let tableRow = {
-          index: i,
+          number: i,
+          start: a,
           startDateStr: this._formatAnomaly(a),
-          severityScore: a.score,
           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))
         };
         tableData.push(tableRow);
@@ -432,15 +504,15 @@ export default Component.extend({
   _fetchTimeseries() {
     const {
       metricUrn,
-      displayRange,
+      analysisRange,
       selectedBaseline
-    } = this.getProperties('metricUrn', 'displayRange', 'selectedBaseline');
+    } = this.getProperties('metricUrn', 'analysisRange', 'selectedBaseline');
     const granularity = '15_MINUTES';
     const timezone = moment.tz.guess();
 
     set(this, 'errorTimeseries', null);
 
-    const urlCurrent = `/rootcause/metric/timeseries?urn=${metricUrn}&start=${displayRange[0]}&end=${displayRange[1]}&offset=current&granularity=${granularity}&timezone=${timezone}`;
+    const urlCurrent = `/rootcause/metric/timeseries?urn=${metricUrn}&start=${analysisRange[0]}&end=${analysisRange[1]}&offset=current&granularity=${granularity}&timezone=${timezone}`;
     fetch(urlCurrent)
       .then(checkStatus)
       .then(res => {
@@ -452,7 +524,7 @@ export default Component.extend({
 
     set(this, 'errorBaseline', null);
 
-    const urlBaseline = `/rootcause/metric/timeseries?urn=${metricUrn}&start=${displayRange[0]}&end=${displayRange[1]}&offset=${selectedBaseline}&granularity=${granularity}&timezone=${timezone}`;
+    const urlBaseline = `/rootcause/metric/timeseries?urn=${metricUrn}&start=${analysisRange[0]}&end=${analysisRange[1]}&offset=${selectedBaseline}&granularity=${granularity}&timezone=${timezone}`;
     fetch(urlBaseline)
       .then(checkStatus)
       .then(res => set(this, 'baseline', res));
@@ -480,6 +552,33 @@ export default Component.extend({
 
   actions: {
     /**
+      * 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);
+     },
+
+    /**
      * Sets the new custom date range for anomaly coverage
      * @method onRangeSelection
      * @param {Object} rangeOption - the user-selected time range to load
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 b5533d9..ce133a8 100644
--- a/thirdeye/thirdeye-frontend/app/pods/components/alert-details/template.hbs
+++ b/thirdeye/thirdeye-frontend/app/pods/components/alert-details/template.hbs
@@ -1,208 +1,233 @@
 <div class="alert-details">
 
+  <div class="pull-right">
+    {{bs-button
+      defaultText=(if showPreview "Refresh Preview" "Preview Alert")
+      disabled=disablePreviewButton
+      type="outline-primary"
+      buttonType="refresh"
+      onClick=(action "getPreview")
+      class="te-button te-button--cancel"
+    }}
+  </div>
   {{#unless errorAnomalies}}
     {{#if showPreview}}
       {{#if isLoading}}
         {{ember-spinner scale=0.5 rotate=10 speed='1.1' color='#3498DB'}}Please wait while we compile the data.
-      {{/if}}
-      {{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">
-        <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>
-
-        {{#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 --}}
+      {{else}}
         {{range-pill-selectors
-          title="Baseline"
-          timeRangeOptions=baselineOptions
-          selectAction=(action "onBaselineOptionClick")
+          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">
+          <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>
+
+          {{#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
         }}
-        {{!-- Alert anomaly table --}}
-        <div class="te-block-container">
-          <table class="te-anomaly-table">
-            {{#if anomalies}}
-              <thead>
-                <tr class="te-anomaly-table__row te-anomaly-table__head">
-                  <th class="te-anomaly-table__cell-head te-anomaly-table__cell-head--left">
-                    <a class="te-anomaly-table__cell-link" {{action "toggleSortDirection" "number"}}>#
-                      <i class="te-anomaly-table__icon glyphicon {{if sortColumnNumberUp "glyphicon-menu-down" "glyphicon-menu-up"}}"></i>
-                    </a>
-                  </th>
-                  <th class="te-anomaly-table__cell-head te-anomaly-table__cell-head--left">
-                    <a class="te-anomaly-table__cell-link" {{action "toggleSortDirection" "start"}}>
-                      Start/Duration (PDT)
-                      <i class="te-anomaly-table__icon glyphicon {{if sortColumnStartUp "glyphicon-menu-up" "glyphicon-menu-down"}}"></i>
-                    </a>
-                  </th>
-                  {{#if alertHasDimensions}}
-                    <th class="te-anomaly-table__cell-head te-anomaly-table__cell-head--fixed">Dimensions</th>
-                  {{/if}}
-                  <th class="te-anomaly-table__cell-head">
-                    <a class="te-anomaly-table__cell-link" {{action "toggleSortDirection" "score"}}>
-                      Severity Score
-                      <i class="te-anomaly-table__icon glyphicon {{if sortColumnScoreUp "glyphicon-menu-up" "glyphicon-menu-down"}}"></i>
-                    </a>
-                  </th>
-                  <th class="te-anomaly-table__cell-head">
-                    <a class="te-anomaly-table__cell-link" {{action "toggleSortDirection" "change"}}>
-                      Average Current / Average Predicted
-                      <i class="te-anomaly-table__icon glyphicon {{if sortColumnChangeUp "glyphicon-menu-up" "glyphicon-menu-down"}}"></i>
-                    </a>
-                  </th>
-                  {{#if notPreview}}
+        {{#if anomalies}}
+          {{!-- Baseline type selector --}}
+          {{range-pill-selectors
+            title="Baseline"
+            timeRangeOptions=baselineOptions
+            selectAction=(action "onBaselineOptionClick")
+          }}
+          {{!-- Alert anomaly table --}}
+          <div class="te-block-container">
+            <table class="te-anomaly-table">
+              {{#if anomalies}}
+                <thead>
+                  <tr class="te-anomaly-table__row te-anomaly-table__head">
+                    <th class="te-anomaly-table__cell-head te-anomaly-table__cell-head--left">
+                      <a class="te-anomaly-table__cell-link" {{action "toggleSortDirection" "number"}}>#
+                        <i class="te-anomaly-table__icon glyphicon {{if sortColumnNumberUp "glyphicon-menu-down" "glyphicon-menu-up"}}"></i>
+                      </a>
+                    </th>
+                    <th class="te-anomaly-table__cell-head te-anomaly-table__cell-head--left">
+                      <a class="te-anomaly-table__cell-link" {{action "toggleSortDirection" "start"}}>
+                        Start/Duration (PDT)
+                        <i class="te-anomaly-table__icon glyphicon {{if sortColumnStartUp "glyphicon-menu-up" "glyphicon-menu-down"}}"></i>
+                      </a>
+                    </th>
+                    {{#if alertHasDimensions}}
+                      <th class="te-anomaly-table__cell-head te-anomaly-table__cell-head--fixed">Dimensions</th>
+                    {{/if}}
                     <th class="te-anomaly-table__cell-head">
-                      <a class="te-anomaly-table__cell-link" {{action "toggleSortDirection" "resolution"}}>
-                        Resolution
-                        <i class="te-anomaly-table__icon glyphicon {{if sortColumnResolutionUp "glyphicon-menu-up" "glyphicon-menu-down"}}"></i>
+                      <a class="te-anomaly-table__cell-link" {{action "toggleSortDirection" "change"}}>
+                        Average Current / Average Predicted
+                        <i class="te-anomaly-table__icon glyphicon {{if sortColumnChangeUp "glyphicon-menu-up" "glyphicon-menu-down"}}"></i>
                       </a>
                     </th>
-                    <th class="te-anomaly-table__cell-head"></th>
-                  {{/if}}
-                </tr>
-              </thead>
-            {{/if}}
-            <tbody>
-              {{#each tableAnomalies as |anomaly|}}
-                <tr class="te-anomaly-table__row">
-                   <td class="te-anomaly-table__cell te-anomaly-table__cell--index">{{anomaly.index}}</td>
-                   <td class="te-anomaly-table__cell">
-                    <ul class="te-anomaly-table__list te-anomaly-table__list--left">
-                      <li class="te-anomaly-table__list-item te-anomaly-table__list-item--stronger">
-                        {{#if notPreview}}
-                          <a target="_blank" class="te-anomaly-table__link" href="/app/#/rootcause?anomalyId={{anomaly.anomalyId}}">
-                            {{anomaly.startDateStr}}
-                          </a>
-                        {{else}}
-                          {{anomaly.startDateStr}}
-                        {{/if}}
-                      </li>
-                      <li class="te-anomaly-table__list-item te-anomaly-table__list-item--lighter">{{anomaly.durationStr}}</li>
-                    </ul>
-                   </td>
-                   {{#if alertHasDimensions}}
+                    {{#if notPreview}}
+                      <th class="te-anomaly-table__cell-head">
+                        <a class="te-anomaly-table__cell-link" {{action "toggleSortDirection" "resolution"}}>
+                          Resolution
+                          <i class="te-anomaly-table__icon glyphicon {{if sortColumnResolutionUp "glyphicon-menu-up" "glyphicon-menu-down"}}"></i>
+                        </a>
+                      </th>
+                      <th class="te-anomaly-table__cell-head"></th>
+                    {{/if}}
+                  </tr>
+                </thead>
+              {{/if}}
+              <tbody>
+                {{#each paginatedFilteredAnomalies as |anomaly|}}
+                  <tr class="te-anomaly-table__row">
+                     <td class="te-anomaly-table__cell te-anomaly-table__cell--index">{{anomaly.number}}</td>
                      <td class="te-anomaly-table__cell">
-                      <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>
-                          </li>
-                       {{else}}
-                          -
-                       {{/each}}
+                      <ul class="te-anomaly-table__list te-anomaly-table__list--left">
+                        <li class="te-anomaly-table__list-item te-anomaly-table__list-item--stronger">
+                          {{#if notPreview}}
+                            <a target="_blank" class="te-anomaly-table__link" href="/app/#/rootcause?anomalyId={{anomaly.anomalyId}}">
+                              {{anomaly.startDateStr}}
+                            </a>
+                          {{else}}
+                            {{anomaly.startDateStr}}
+                          {{/if}}
+                        </li>
+                        <li class="te-anomaly-table__list-item te-anomaly-table__list-item--lighter">{{anomaly.durationStr}}</li>
                       </ul>
                      </td>
-                   {{/if}}
-                   <td class="te-anomaly-table__cell">{{anomaly.severityScore}}</td>
-                   <td class="te-anomaly-table__cell">
-                    <ul class="te-anomaly-table__list">
-                      <li>{{anomaly.shownCurrent}} / {{anomaly.shownBaseline}}</li>
-                      <li class="te-anomaly-table__value-label te-anomaly-table__value-label--{{calculate-direction anomaly.shownChangeRate}}">
-                        {{#if (not anomaly.isNullChangeRate)}}
-                          ({{anomaly.shownChangeRate}}%)
-                        {{else}}
-                          (N/A)
-                        {{/if}}
-                      </li>
-                    </ul>
-                   </td>
-                   {{#if notPreview}}
+                     {{#if alertHasDimensions}}
+                       <td class="te-anomaly-table__cell">
+                        <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>
+                            </li>
+                         {{else}}
+                            -
+                         {{/each}}
+                        </ul>
+                       </td>
+                     {{/if}}
                      <td class="te-anomaly-table__cell">
-                        {{#if renderStatusIcon}}
-                          {{#if anomaly.showResponseSaved}}
-                            <i class="te-anomaly-table__icon--status glyphicon glyphicon-ok-circle"></i>
+                      <ul class="te-anomaly-table__list">
+                        <li>{{anomaly.shownCurrent}} / {{anomaly.shownBaseline}}</li>
+                        <li class="te-anomaly-table__value-label te-anomaly-table__value-label--{{calculate-direction anomaly.shownChangeRate}}">
+                          {{#if (not anomaly.isNullChangeRate)}}
+                            ({{anomaly.shownChangeRate}}%)
+                          {{else}}
+                            (N/A)
                           {{/if}}
-                          {{#if anomaly.showResponseFailed}}
-                            <i class="te-anomaly-table__icon--status te-anomaly-table__icon--error glyphicon glyphicon-remove-circle"></i>
+                        </li>
+                      </ul>
+                     </td>
+                     {{#if notPreview}}
+                       <td class="te-anomaly-table__cell">
+                          {{#if renderStatusIcon}}
+                            {{#if anomaly.showResponseSaved}}
+                              <i class="te-anomaly-table__icon--status glyphicon glyphicon-ok-circle"></i>
+                            {{/if}}
+                            {{#if anomaly.showResponseFailed}}
+                              <i class="te-anomaly-table__icon--status te-anomaly-table__icon--error glyphicon glyphicon-remove-circle"></i>
+                            {{/if}}
                           {{/if}}
-                        {{/if}}
 
-                        {{#if anomaly.isUserReported}}
-                          <div class="te-anomaly-table__text te-anomaly-table__text--explore">User Reported</div>
-                          <div class="te-anomaly-table__comment">
-                            <i class="glyphicon glyphicon-th-list"></i>
-                            {{#tooltip-on-element class="te-anomaly-table__tooltip"}}
-                              {{anomaly.anomalyFeedbackComments}}
-                            {{/tooltip-on-element}}
+                          {{#if anomaly.isUserReported}}
+                            <div class="te-anomaly-table__text te-anomaly-table__text--explore">User Reported</div>
+                            <div class="te-anomaly-table__comment">
+                              <i class="glyphicon glyphicon-th-list"></i>
+                              {{#tooltip-on-element class="te-anomaly-table__tooltip"}}
+                                {{anomaly.anomalyFeedbackComments}}
+                              {{/tooltip-on-element}}
+                            </div>
+                          {{else}}
+                            {{#power-select
+                              triggerId=anomaly.anomalyId
+                              triggerClass="te-anomaly-table__select"
+                              options=responseOptions
+                              searchEnabled=false
+                              selected=(get labelMap anomaly.anomalyFeedback)
+                              onchange=(action "onChangeAnomalyResponse" anomaly)
+                              as |response|
+                            }}
+                              {{response}}
+                            {{/power-select}}
+                          {{/if}}
+                       </td>
+                       <td class="te-anomaly-table__cell te-anomaly-table__cell--feedback">
+                          <div class="te-anomaly-table__link-wrapper">
+                            {{#link-to 'rootcause' (query-params anomalyId=anomaly.anomalyId) target="_blank" class="te-anomaly-table__link"}}
+                              Investigate
+                            {{/link-to}}
                           </div>
-                        {{else}}
-                          {{#power-select
-                            triggerId=anomaly.anomalyId
-                            triggerClass="te-anomaly-table__select"
-                            options=responseOptions
-                            searchEnabled=false
-                            selected=(get labelMap anomaly.anomalyFeedback)
-                            onchange=(action "onChangeAnomalyResponse" anomaly)
-                            as |response|
-                          }}
-                            {{response}}
-                          {{/power-select}}
-                        {{/if}}
-                     </td>
-                     <td class="te-anomaly-table__cell te-anomaly-table__cell--feedback">
-                        <div class="te-anomaly-table__link-wrapper">
-                          {{#link-to 'rootcause' (query-params anomalyId=anomaly.anomalyId) target="_blank" class="te-anomaly-table__link"}}
-                            Investigate
-                          {{/link-to}}
-                        </div>
-                     </td>
-                   {{/if}}
-                </tr>
-              {{/each}}
-            </tbody>
-          </table>
-        </div>
+                       </td>
+                     {{/if}}
+                  </tr>
+                {{/each}}
+              </tbody>
+            </table>
+          </div>
 
+          {{!--pagination--}}
+          {{#if (gt pagesNum 1)}}
+            <nav class="text-center" aria-label="Page navigation">
+              <ul class="pagination">
+                <li class={{if (eq currentPage 1) 'active disabled'}} >
+                  <a href="#" {{action "onPaginationClick" 1}} aria-label="First">
+                    <span aria-hidden="true">First</span>
+                  </a>
+                </li>
+                <li class={{if (eq currentPage 1) 'active disabled'}}>
+                  <a href="#" {{action "onPaginationClick" "previous"}} aria-label="Previous">
+                    <span aria-hidden="true">Previous</span>
+                  </a>
+                </li>
+                {{#each viewPages as |page|}}
+                  <li class={{if (eq page currentPage) 'active'}}><a href="#" {{action "onPaginationClick" page}}>{{page}}</a></li>
+                {{/each}}
+                <li class={{if (eq currentPage pagesNum) 'disabled'}} >
+                  <a href="#" {{action "onPaginationClick" "next"}} aria-label="Next">
+                    <span aria-hidden="true">Next</span>
+                  </a>
+                </li>
+                <li class={{if (eq currentPage pagesNum) 'disabled'}} >
+                  <a href="#" {{action "onPaginationClick" pagesNum}} aria-label="Last">
+                    <span aria-hidden="true">Last</span>
+                  </a>
+                </li>
+              </ul>
+            </nav>
+          {{/if}}
+
+        {{/if}}
       {{/if}}
       {{else}}
         {{#if disablePreviewButton}}
-          <p>Please define anomaly detection in YAML to enable preview.</p>
+          <p>Enter YAML configuration to enable preview.</p>
         {{/if}}
     {{/if}}
   {{/unless}}
   <p>{{errorAnomalies}}</p>
-  <div class="pull-right">
-    {{bs-button
-      defaultText=(if showPreview "Refresh Preview" "Get Preview")
-      disabled=disablePreviewButton
-      type="outline-primary"
-      buttonType="refresh"
-      onClick=(action "getPreview")
-      class="te-button te-button--cancel"
-    }}
-  </div>
   {{yield}}
 
 
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/yaml-editor/component.js b/thirdeye/thirdeye-frontend/app/pods/components/yaml-editor/component.js
index c19ab8e..4e90924 100644
--- a/thirdeye/thirdeye-frontend/app/pods/components/yaml-editor/component.js
+++ b/thirdeye/thirdeye-frontend/app/pods/components/yaml-editor/component.js
@@ -241,6 +241,10 @@ export default Component.extend({
   },
 
   actions: {
+    changeAccordion() {
+      set(this, 'toggleCollapsed', !get(this, 'toggleCollapsed'));
+    },
+
     /**
      * resets given yaml field to default value for creation mode and server value for edit mode
      */
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 c442036..dc948c1 100644
--- a/thirdeye/thirdeye-frontend/app/pods/components/yaml-editor/template.hbs
+++ b/thirdeye/thirdeye-frontend/app/pods/components/yaml-editor/template.hbs
@@ -38,10 +38,10 @@
     }}
   </div>
   <div class="col-xs-12">
-    {{#bs-accordion onChange=(action (mut toggleCollapsed)) as |acc|}}
+    {{#bs-accordion onChange=(action "changeAccordion") as |acc|}}
       {{#acc.item value=preview as |aitem|}}
         {{#aitem.title}}
-          <section class="dashboard-container__title">Preview alert
+          <section class="dashboard-container__title">Preview alert {{if toggleCollapsed "/ Enter YAML configuration to preview alert." ""}}
             <span class="pull-right"><i class="glyphicon glyphicon-menu-{{if toggleCollapsed "down" "up"}}"></i></span>
           </section>
         {{/aitem.title}}


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