You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pinot.apache.org by aa...@apache.org on 2019/01/23 23:47:53 UTC

[incubator-pinot] branch master updated: [TE] aaronucsd/new edit basic yaml editor (#3737)

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

aaronucsd 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 086b72b  [TE] aaronucsd/new edit basic yaml editor (#3737)
086b72b is described below

commit 086b72b89131095d23ce018e0531908925a1255f
Author: Long Huynh <lo...@linkedin.com>
AuthorDate: Wed Jan 23 15:47:49 2019 -0800

    [TE] aaronucsd/new edit basic yaml editor (#3737)
---
 .../self-serve-alert-yaml-details/template.hbs     |  58 +++---
 .../app/pods/components/yaml-editor/component.js   | 196 ++++++++++++++-------
 .../app/pods/components/yaml-editor/template.hbs   |  35 ++--
 .../app/pods/manage/yaml/route.js                  | 122 +++++++++----
 .../app/pods/manage/yaml/template.hbs              |  11 +-
 .../app/pods/self-serve/create-alert/template.hbs  |  36 ++--
 .../app/styles/components/yaml-editor.scss         |   6 +
 thirdeye/thirdeye-frontend/app/utils/constants.js  |   6 +-
 8 files changed, 289 insertions(+), 181 deletions(-)

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 e499995..81deb18 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
@@ -1,9 +1,7 @@
 <div class="te-search-results__header">
   <div class="te-search-results__title-group">
     <div class="te-search-results__title">
-      {{#if (eq displayMode "single")}}
-        <span title={{alertData.functionName}}>new {{alertData.functionName}}</span>
-      {{/if}}
+      <span title={{alertData.functionName}}>{{alertData.functionName}}</span>
       <div class="te-search-results__tag {{if (eq displayMode "list") "te-search-results__tag--list"}} {{if alertData.isActive "te-search-results__tag--active"}}">
         {{#if isLoadError}}
           Error
@@ -36,59 +34,45 @@
           </span>
         </div>
       </li>
-      {{#if (eq displayMode "single")}}
-        <li class="te-search-results__row">
-          <div class="te-search-results__option te-search-results__option--{{modeSubClass}} te-search-results__option--left">Granularity</div>
-          <div class="te-search-results__value{{valueClassSuffix}}" title={{alertData.granularity}}>
-            <span class="{{unless alertData.granularity 'te-search-results__prop--missing' 'te-search-results__prop'}}">
-              {{if alertData.granularity alertData.granularity 'N/A'}}
-            </span>
-          </div>
-        </li>
-      {{/if}}
       <li class="te-search-results__row">
-        <div class="te-search-results__option te-search-results__option--{{modeSubClass}} te-search-results__option--left">Application</div>
-        <div class="te-search-results__value{{valueClassSuffix}}" title={{alertData.application}}>
-          <span class="{{unless alertData.application 'te-search-results__prop--missing' 'te-search-results__prop'}}">
-            {{if alertData.application alertData.application 'N/A'}}
+        <div class="te-search-results__option te-search-results__option--{{modeSubClass}} te-search-results__option--left">Filtered By</div>
+        <div class="te-search-results__value{{valueClassSuffix}}" title={{alertData.filters}}>
+          <span class="{{unless alertData.filters 'te-search-results__prop--missing' 'te-search-results__prop'}}">
+            {{if alertData.filters alertData.filters 'N/A'}}
           </span>
         </div>
       </li>
       <li class="te-search-results__row">
-        <div class="te-search-results__option te-search-results__option--{{modeSubClass}} te-search-results__option--left">Alert Owner</div>
-        <div class="te-search-results__value{{valueClassSuffix}}" title={{alertData.createdBy}}>
-          <span class="{{unless alertData.createdBy 'te-search-results__prop--missing' 'te-search-results__prop'}}">
-            {{if alertData.createdBy alertData.createdBy 'N/A'}}
+        <div class="te-search-results__option te-search-results__option--{{modeSubClass}} te-search-results__option--left">Breakdown By</div>
+        <div class="te-search-results__value{{valueClassSuffix}}" title={{alertData.dimensionExploration}}>
+          <span class="{{unless alertData.dimensionExploration 'te-search-results__prop--missing' 'te-search-results__prop'}}">
+            {{if alertData.dimensionExploration alertData.dimensionExploration 'N/A'}}
           </span>
         </div>
       </li>
     </div>
     <div class="col-xs-12 col-sm-7">
       <li class="te-search-results__row">
-        <div class="te-search-results__option te-search-results__option--{{modeSubClass}}">Data Filter</div>
-        <div class="te-search-results__value{{valueClassSuffix}}" title={{alertData.filters}}>
-          <span class="{{unless alertData.filters 'te-search-results__prop--missing' 'te-search-results__prop'}}">
-            {{if alertData.filters alertData.filters 'N/A'}}
+        <div class="te-search-results__option te-search-results__option--{{modeSubClass}} te-search-results__option--left">Application</div>
+        <div class="te-search-results__value{{valueClassSuffix}}" title={{alertData.application}}>
+          <span class="{{unless alertData.application 'te-search-results__prop--missing' 'te-search-results__prop'}}">
+            {{if alertData.application alertData.application 'N/A'}}
           </span>
         </div>
       </li>
       <li class="te-search-results__row">
-        <div class="te-search-results__option te-search-results__option--{{modeSubClass}}">Dimensions</div>
-        <div class="te-search-results__value{{valueClassSuffix}}" title={{alertData.exploreDimensions}}>
-          <span class="{{unless alertData.exploreDimensions 'te-search-results__prop--missing' 'te-search-results__prop'}}">
-            {{if alertData.exploreDimensions alertData.exploreDimensions 'N/A'}}
+        <div class="te-search-results__option te-search-results__option--{{modeSubClass}} te-search-results__option--left">Owner</div>
+        <div class="te-search-results__value{{valueClassSuffix}}" title={{alertData.createdBy}}>
+          <span class="{{unless alertData.createdBy 'te-search-results__prop--missing' 'te-search-results__prop'}}">
+            {{if alertData.createdBy alertData.createdBy 'N/A'}}
           </span>
         </div>
       </li>
       <li class="te-search-results__row">
-        <div class="te-search-results__option te-search-results__option--{{modeSubClass}}">Detection Type</div>
-        <div class="te-search-results__value{{valueClassSuffix}}" title={{alertData.type}}>{{alertData.type}}</div>
-      </li>
-      <li class="te-search-results__row">
-        <div class="te-search-results__option te-search-results__option--{{modeSubClass}}">Subscription Group</div>
-        <div class="te-search-results__value{{valueClassSuffix}}" title={{alertData.group}}>
-          <span class="{{unless alertData.group 'te-search-results__prop--missing' 'te-search-results__prop'}}">
-            {{if alertData.group alertData.group 'N/A'}}
+        <div class="te-search-results__option te-search-results__option--{{modeSubClass}} te-search-results__option--left">Updated By</div>
+        <div class="te-search-results__value{{valueClassSuffix}}" title={{alertData.updatedBy}}>
+          <span class="{{unless alertData.updatedBy 'te-search-results__prop--missing' 'te-search-results__prop'}}">
+            {{if alertData.updatedBy alertData.updatedBy 'N/A'}}
           </span>
         </div>
       </li>
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 d2b2bb9..ed158ad 100644
--- a/thirdeye/thirdeye-frontend/app/pods/components/yaml-editor/component.js
+++ b/thirdeye/thirdeye-frontend/app/pods/components/yaml-editor/component.js
@@ -1,22 +1,24 @@
 /**
- * Component to render pre-set time range selection pills and a 'custom' one using date-range-picker.
- * @module components/range-pill-selectors
- * @property {Object} timeRangeOptions - object containing our range options
- * @property {Number} timePickerIncrement - determines selectable time increment in date-range-picker
- * @property {Date} activeRangeStart - default start date for range picker
- * @property {Date} activeRangeEnd - default end date for range picker
- * @property {String} uiDateFormat - date format specified by parent route (often specific to metric granularity)
- * @property {Action} selectAction - closure action from parent
+ * Component to render the alert and subscription group yaml editors.
+ * @module components/yaml-editor
+ * @property {number} alertId - the alert id
+ * @property {number} subscriptionGroupId - the subscription group id
+ * @property {boolean} isEditMode - to activate the edit mode
+ * @property {boolean} showSettings - to show the subscriber groups yaml editor
+ * @property {Object} subscriptionGroupNames - the list of subscription groups
+ * @property {Object} alertYaml - the alert yaml to display
+ * @property {Object} detectionSettingsYaml - the subscription group yaml to display
  * @example
-  {{yaml-editor
-    alertTitle="New Editor Title"
-    isEditMode=true
-    showSettings=true
-    onYMLSelector=(action "onYMLSelector")
-    saveAlertYaml=(action "saveAlertYaml")
-    cancelAlertYaml=(action "cancelAlertYaml")
-  }}
- * @author
+   {{yaml-editor
+     alertId=model.alertId
+     subscriptionGroupId=model.subscriptionGroupId
+     isEditMode=true
+     showSettings=true
+     subscriptionGroupNames=model.detectionSettingsYaml
+     alertYaml=model.detectionYaml
+     detectionSettingsYaml=model.detectionSettingsYaml
+   }}
+ * @author lohuynh
  */
 
 import Component from '@ember/component';
@@ -39,7 +41,7 @@ export default Component.extend({
   /**
    * Properties we expect to receive for the yaml-editor
    */
-  //isForm: true,
+   //isForm: true,
   currentMetric: null,
   isYamlParseable: true,
   alertTitle: 'Define anomaly detection in YAML',
@@ -52,44 +54,57 @@ export default Component.extend({
   detectionSettingsYaml:  null,   // The YAML for the subscription group
   yamlAlertProps: yamlAlertProps,
   yamlAlertSettings: yamlAlertSettings,
-  subscriptionGroupNames: [],
   showAnomalyModal: false,
   showNotificationModal: false,
   YAMLField: '',
+  currentYamlAlertOriginal: '',
+  currentYamlSettingsOriginal: '',
 
-  /**
-   * params passed to yaml-editor component
-   */
-  async didReceiveAttrs() {
+
+  init() {
     this._super(...arguments);
 
-    // fetch the subscription group list
-    await get(this, '_fetchSubscriptionGroups').perform();
+    if(get(this, 'isEditMode')) {
+      set(this, 'currentYamlAlertOriginal', get(this, 'alertYaml') || get(this, 'yamlAlertProps'));
+      set(this, 'currentYamlSettingsOriginal', get(this, 'detectionSettingsYaml') || get(this, 'yamlAlertSettings'));
+    }
   },
+  /**
+   * sets Yaml value displayed to contents of alertYaml or yamlAlertProps
+   * @method currentYamlAlert
+   * @return {String}
+   */
+  subscriptionGroupNamesDisplay: computed(
+    'subscriptionGroupNames',
+    async function() {
+      const subscriptionGroups = await get(this, '_fetchSubscriptionGroups').perform();
+      return get(this, 'subscriptionGroupNames') || subscriptionGroups;
+    }
+  ),
 
   /**
    * sets Yaml value displayed to contents of alertYaml or yamlAlertProps
-   * @method currentYamlValues
+   * @method currentYamlAlert
    * @return {String}
    */
-  currentYamlValues: computed(
+  currentYamlAlert: computed(
     'alertYaml',
     function() {
-      const inputYaml = this.get('alertYaml');
-      return inputYaml || this.get('yamlAlertProps');
+      const inputYaml = get(this, 'alertYaml');
+      return inputYaml || get(this, 'yamlAlertProps');
     }
   ),
 
   /**
    * sets Yaml value displayed to contents of detectionSettingsYaml or yamlAlertSettings
-   * @method currentYamlValues
+   * @method currentYamlAlert
    * @return {String}
    */
   currentYamlSettings: computed(
     'detectionSettingsYaml',
     function() {
-      const inputYaml = this.get('detectionSettingsYaml');
-      return inputYaml || this.get('yamlAlertSettings');
+      const detectionSettingsYaml = get(this, 'detectionSettingsYaml');
+      return detectionSettingsYaml || get(this, 'yamlAlertSettings');
     }
   ),
 
@@ -97,7 +112,7 @@ export default Component.extend({
   isErrorMsg: computed(
     'errorMsg',
     function() {
-      const errorMsg = this.get('errorMsg');
+      const errorMsg = get(this, 'errorMsg');
       return errorMsg !== '';
     }
   ),
@@ -115,7 +130,8 @@ export default Component.extend({
       const response = yield fetch(url2, postProps2);
       const json = yield response.json();
       //filter subscription groups with yaml
-      set(this, 'subscriptionGroupNames', json.filterBy('yaml'));
+      //set(this, 'subscriptionGroupNames', json.filterBy('yaml'));
+      return json.filterBy('yaml');
     } catch (error) {
       notifications.error('Failed to retrieve subscription groups.', 'Error');
     }
@@ -125,14 +141,14 @@ export default Component.extend({
    * Calls api's for specific metric's autocomplete
    * @method _loadAutocompleteById
    * @return Promise
-  */
-  _loadAutocompleteById(metricId) {
+   */
+   _loadAutocompleteById(metricId) {
     const promiseHash = {
       filters: fetch(selfServeApiGraph.metricFilters(metricId)).then(res => checkStatus(res, 'get', true)),
       dimensions: fetch(selfServeApiGraph.metricDimensions(metricId)).then(res => checkStatus(res, 'get', true))
     };
     return RSVP.hash(promiseHash);
-  },
+   },
 
   /**
    * Get autocomplete suggestions from relevant api
@@ -157,13 +173,11 @@ export default Component.extend({
                 dataset,
                 id: metric.id,
                 completer:{
-                  insertMatch: (editor, data) => {
-                    editor.setValue(yamIt(data.metricname, data.dataset));
-                    editor.metricId = data.id;
-                    //editor.completer.insertMatch({value: data.value});
-                    // editor.insert('abc');
-                  }
-                }};
+                insertMatch: (editor, data) => {
+                  editor.setValue(yamIt(data.metricname, data.dataset));
+                  editor.metricId = data.id;
+                }
+              }};
             });
           }
           return noResultsArray;
@@ -219,19 +233,28 @@ export default Component.extend({
 
   actions: {
     /**
-     * resets given yaml field to default value
+     * resets given yaml field to default value for creation mode and server value for edit mode
      */
     resetYAML(field) {
+      const isEditMode = get(this, 'isEditMode');
       if (field === 'anomaly') {
-        const yamlAlertProps = get(this, 'yamlAlertProps');
-        set(this, 'alertYaml', yamlAlertProps);
+        if(isEditMode) {
+          set(this, 'alertYaml', get(this, 'currentYamlAlertOriginal'));
+        } else {
+          const yamlAlertProps = get(this, 'yamlAlertProps');
+          set(this, 'alertYaml', yamlAlertProps);
+        }
       } else if (field === 'notification') {
-        const yamlAlertSettings = get(this, 'yamlAlertSettings');
-        set(this, 'detectionSettingsYaml', yamlAlertSettings);
+        if(isEditMode) {
+          set(this, 'detectionSettingsYaml', get(this, 'currentYamlSettingsOriginal'));
+        } else {
+          const yamlAlertSettings = get(this, 'yamlAlertSettings');
+          set(this, 'detectionSettingsYaml', yamlAlertSettings);
+        }
       }
     },
 
-    /**
+     /**
      * Brings up appropriate modal, based on which yaml field is clicked
      */
     triggerDocModal(field) {
@@ -291,7 +314,7 @@ export default Component.extend({
     },
 
     /**
-     * Activates 'Create Alert' button and stores YAML content in alertYaml
+     * Activates 'Create changes' button and stores YAML content in alertYaml
      */
     onYMLSelectorAction(value) {
       set(this, 'disableYamlSave', false);
@@ -300,26 +323,21 @@ export default Component.extend({
     },
 
     /**
-     * Activates 'Create Alert' button and stores YAML content in detectionSettingsYaml
+     * Activates 'Create changes' button and stores YAML content in detectionSettingsYaml
      */
     onYMLSettingsSelectorAction(value) {
       set(this, 'disableYamlSave', false);
       set(this, 'detectionSettingsYaml', value);
     },
 
-    cancelAlertYamlAction() {
-      //call the onConfirm property to invoke the passed in action
-      get(this, 'cancelAlertYaml')();
-    },
-
     /**
-     * Fired by save button in YAML UI
+     * Fired by create button in YAML UI
      * Grabs YAML content and sends it
      */
-    saveAlertYamlAction() {
+    createAlertYamlAction() {
       const content = {
         detection: get(this, 'alertYaml'),
-        notification: get(this, 'currentYamlSettings')
+        notification: get(this, 'detectionSettingsYaml')
       };
       const url = '/yaml/create-alert';
       const postProps = {
@@ -327,7 +345,7 @@ export default Component.extend({
         body: JSON.stringify(content),
         headers: { 'content-type': 'application/json' }
       };
-      const notifications = this.get('notifications');
+      const notifications = get(this, 'notifications');
 
       fetch(url, postProps).then((res) => {
         res.json().then((result) => {
@@ -342,6 +360,62 @@ export default Component.extend({
       }).catch((error) => {
         notifications.error('Save alert yaml file failed.', error);
       });
+    },
+
+    /**
+     * Fired by save button in YAML UI
+     * Grabs each yaml (alert and settings) and save them to their respective apis.
+     */
+    async saveEditYamlAction() {
+      const {
+        alertYaml,
+        detectionSettingsYaml,
+        notifications,
+        alertId,
+        subscriptionGroupId
+      } = getProperties(this, 'alertYaml', 'detectionSettingsYaml', 'notifications', 'alertId', 'subscriptionGroupId');
+
+      //PUT alert
+      const alert_url = `/yaml/${alertId}`;
+      const alertPostProps = {
+        method: 'PUT',
+        body: alertYaml,
+        headers: { 'content-type': 'text/plain' }
+      };
+      try {
+        const alert_result = await fetch(alert_url, alertPostProps);
+        const alert_status  = get(alert_result, 'status');
+        const alert_json = await alert_result.json();
+        if (alert_status !== 200) {
+          set(this, 'errorMsg', get(alert_json, 'message'));
+          notifications.error('Save alert yaml file failed.', 'Error');
+        } else {
+          notifications.success('Alert saved successfully', 'Done', alert_json);
+        }
+      } catch (error) {
+        notifications.error('Save alert yaml file failed.', error);
+      }
+
+      //PUT settings
+      const setting_url = `/yaml/notification/${subscriptionGroupId}`;
+      const settingsPostProps = {
+        method: 'PUT',
+        body: detectionSettingsYaml,
+        headers: { 'content-type': 'text/plain' }
+      };
+      try {
+        const settings_result = await fetch(setting_url, settingsPostProps);
+        const settings_status  = get(settings_result, 'status');
+        const settings_json = await settings_result.json();
+        if (settings_status !== 200) {
+          set(this, 'errorMsg', get(settings_json, 'message'));
+          notifications.error('Save settings yaml file failed.', 'Error');
+        } else {
+          notifications.success('Settings saved successfully', 'Done', settings_json);
+        }
+      } catch (error) {
+        notifications.error('Save settings yaml file failed.', error);
+      }
     }
   }
 });
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 a1032ed..dc917c3 100644
--- a/thirdeye/thirdeye-frontend/app/pods/components/yaml-editor/template.hbs
+++ b/thirdeye/thirdeye-frontend/app/pods/components/yaml-editor/template.hbs
@@ -1,9 +1,15 @@
 <fieldset class="te-form__section te-form__section--first row">
   <div class="col-xs-12">
     <legend class="te-form__section-title">{{alertTitle}}</legend>
-    <label for="select-metric" class="control-label te-label te-label--taller required">Can't find your metric?
-      <a class="thirdeye-link-secondary" target="_blank">Import from InGraphs</a>
-    </label>
+  </div>
+  <div class="col-xs-12 {{if isEditMode "bottom-margin"}}">
+    {{#unless isEditMode}}
+      <label for="select-metric" class="control-label te-label te-label--taller required">Can't find your metric?
+        {{#link-to "self-serve.import-metric" class="thirdeye-link-secondary thirdeye-link-secondary--inside"}}
+          Import a Metric From InGraphs
+        {{/link-to}}
+      </label>
+    {{/unless}}
     <div class="pull-right">
       {{bs-button
         defaultText="Reset"
@@ -20,9 +26,11 @@
         class="te-button te-button--cancel"
       }}
     </div>
+  </div>
+  <div class="col-xs-12">
     {{ember-ace
       lines=35
-      value=currentYamlValues
+      value=currentYamlAlert
       suggestCompletions=(action 'yamlSuggestions')
       enableLiveAutocompletion=true
       update=(action "onYMLSelectorAction")
@@ -33,7 +41,6 @@
   <div class="col-xs-12">
     <hr/>
   </div>
-  {{!-- TOD: save for Alert settings --}}
   {{#if showSettings}}
     <div class="col-xs-12">
       <legend class="te-form__section-title">{{alertSettingsTitle}}</legend>
@@ -42,8 +49,8 @@
       <label class="te-label te-label--small">Add this alert to a subscription group</label>
       {{!--  subscription group --}}
       {{#power-select
-        options=subscriptionGroupNames
         placeholder="Create a subscription group"
+        options=subscriptionGroupNamesDisplay
         selected=groupName
         searchField="name"
         onchange=(action 'onYAMLGroupSelectionAction')
@@ -53,9 +60,6 @@
       {{/power-select}}
     </div>
     <div class="col-xs-12">
-      <legend class="te-form__section-title">Configure new subscription group</legend>
-    </div>
-    <div class="col-xs-12">
       <label for="select-metric" class="control-label te-label te-label--taller required">Can't find your team? Contact
         <a class="thirdeye-link-secondary" target="_blank" href="mailto:ask_thirdeye@linkedin.com">ask_thirdeye@linkedin.com</a>
       </label>
@@ -79,7 +83,7 @@
     <div class="col-xs-12">
       {{!-- notification settings editor --}}
       {{ember-ace
-        lines=20
+        lines=25
         value=currentYamlSettings
         update=(action "onYMLSettingsSelectorAction")
         mode="ace/mode/yaml"
@@ -99,18 +103,11 @@
 <fieldset class="te-form__section-submit">
   {{#if isEditMode}}
     {{bs-button
-      defaultText="Cancel"
-      type="outline-primary"
-      buttonType="cancel"
-      onClick=(action "cancelAlertYamlAction")
-      class="te-button te-button--cancel"
-    }}
-    {{bs-button
       defaultText="Save changes"
       type="primary"
       buttonType="submit"
       disabled=disableYamlSave
-      onClick=(action "saveAlertYamlAction")
+      onClick=(action "saveEditYamlAction")
       class="te-button te-button--submit"
     }}
   {{else}}
@@ -119,7 +116,7 @@
       type="primary"
       buttonType="submit"
       disabled=disableYamlSave
-      onClick=(action "saveAlertYamlAction")
+      onClick=(action "createAlertYamlAction")
       class="te-button te-button--submit"
     }}
   {{/if}}
diff --git a/thirdeye/thirdeye-frontend/app/pods/manage/yaml/route.js b/thirdeye/thirdeye-frontend/app/pods/manage/yaml/route.js
index 9101711..915f68c 100644
--- a/thirdeye/thirdeye-frontend/app/pods/manage/yaml/route.js
+++ b/thirdeye/thirdeye-frontend/app/pods/manage/yaml/route.js
@@ -7,60 +7,108 @@ import Route from '@ember/routing/route';
 import RSVP from 'rsvp';
 import { set, get } from '@ember/object';
 import { inject as service } from '@ember/service';
+import yamljs from 'yamljs';
 
 export default Route.extend({
   notifications: service('toast'),
 
   async model(params) {
-    const id = params.alert_id;
-
-    //detection alert fetch
-    const url = `/detection/${id}`;
+    const alertId = params.alert_id;
     const postProps = {
       method: 'get',
       headers: { 'content-type': 'application/json' }
     };
-    const notifications = this.get('notifications');
+    const notifications = get(this, 'notifications');
 
-    await fetch(url, postProps).then((res) => {
-      res.json().then((result) => {
-        if (result && result.yaml) {
-          set(this, 'detectionYaml', result);
+    //detection alert fetch
+    const alertUrl = `/detection/${alertId}`;
+    try {
+      const alert_result = await fetch(alertUrl, postProps);
+      const alert_status  = get(alert_result, 'status');
+      const alert_json = await alert_result.json();
+      if (alert_status !== 200) {
+        notifications.error('Retrieval of alert yaml failed.', 'Error');
+      } else {
+        if (alert_json.yaml) {
+          const yaml = yamljs.parse(alert_json.yaml);
+          Object.assign(yaml, {
+            application: alert_json.name,
+            isActive: alert_json.active,
+            createdBy: alert_json.createdBy,
+            updatedBy: alert_json.updatedBy,
+            functionName: yaml.detectionName,
+            collection: yaml.dataset,
+            type: alert_json.pipelineType,
+            exploreDimensions: alert_json.dimensions,
+            filters: this._formatYamlFilter(yaml.filters),
+            dimensionExploration: this._formatYamlFilter(yaml.dimensionExploration),
+            yaml: alert_json.yaml
+          });
+          set(this, 'detectionYaml', yaml);
         }
-      });
-
-      if (res && res.active) {
-        notifications.success('Save alert yaml successfully.', 'Saved');
       }
-    }).catch((ex) => {
-      notifications.error('Save alert yaml file failed.', 'Error');
-    });
+    } catch (error) {
+      notifications.error('Retrieving alert yaml failed.', error);
+    }
 
     //subscription group fetch
-    const url2 = `/detection/subscription-groups/${id}`;//dropdown of subscription groups
-    const postProps2 = {
-      method: 'get',
-      headers: { 'content-type': 'application/json' }
-    };
-
-    await fetch(url2, postProps2).then((res) => {
-      res.json().then((result) => {
-        if (result && result.yaml) {
-          set(this, 'detectionSettingsYaml', result);
-        }
-      });
-
-      if (res && res.active) {
-        notifications.success('Save alert yaml successfully.', 'Saved');
+    const subUrl = `/detection/subscription-groups/${alertId}`;//dropdown of subscription groups
+    try {
+      const settings_result = await fetch(subUrl, postProps);
+      const settings_status  = get(settings_result, 'status');
+      const settings_json = await settings_result.json();
+      if (settings_status !== 200) {
+        notifications.error('Retrieving subscription groups failed.', 'Error');
+      } else {
+        set(this, 'subscriptionGroups', settings_json);
       }
-    }).catch((ex) => {
-      notifications.error('Save alert yaml file failed.', 'Error');
-    });
+    } catch (error) {
+      notifications.error('Retrieving subscription groups failed.', error);
+    }
 
+    const subscriptionGroupYamlDisplay = typeof get(this, 'subscriptionGroups') === 'object' && get(this, 'subscriptionGroups').length > 0 ? get(this, 'subscriptionGroups')[0].yaml : get(this, 'subscriptionGroups').yaml;
+    const subscriptionGroupId = typeof get(this, 'subscriptionGroups') === 'object' && get(this, 'subscriptionGroups').length > 0 ? get(this, 'subscriptionGroups')[0].id : get(this, 'subscriptionGroups').id;
     return RSVP.hash({
-      id,
-      detectionYaml: get(this, 'detectionYaml'),
-      detectionSettingsYaml: get(this, 'detectionSettingsYaml')
+      alertId,
+      subscriptionGroupId,
+      alertData: get(this, 'detectionYaml'),
+      detectionYaml: get(this, 'detectionYaml').yaml,
+      subscriptionGroups: get(this, 'subscriptionGroups'),
+      subscriptionGroupYamlDisplay
     });
+  },
+
+  /**
+   * The yaml filters formatter. Convert filters in the yaml file in to a legacy filters string
+   * For example, filters = {
+   *   "country": ["us", "cn"],
+   *   "browser": ["chrome"]
+   * }
+   * will be convert into "country=us;country=cn;browser=chrome"
+   *
+   * @method _formatYamlFilter
+   * @param {Map} filters multimap of filters
+   * @return {String} - formatted filters string
+   */
+  _formatYamlFilter(filters) {
+    if (filters){
+      const filterStrings = [];
+      Object.keys(filters).forEach(
+        function(filterKey) {
+          const filter = filters[filterKey];
+          if (typeof filter === 'object') {
+            filter.forEach(
+              function (filterValue) {
+                filterStrings.push(filterKey + '=' + filterValue);
+              }
+            );
+          } else {
+            filterStrings.push(filterKey + '=' + filter);
+          }
+        }
+      );
+      return filterStrings.join(';');
+    }
+    return '';
   }
 });
diff --git a/thirdeye/thirdeye-frontend/app/pods/manage/yaml/template.hbs b/thirdeye/thirdeye-frontend/app/pods/manage/yaml/template.hbs
index 9c7d185..b32d9cf 100644
--- a/thirdeye/thirdeye-frontend/app/pods/manage/yaml/template.hbs
+++ b/thirdeye/thirdeye-frontend/app/pods/manage/yaml/template.hbs
@@ -1,9 +1,8 @@
 <section class="te-page__top te-search-results {{if isEditModeActive "te-search-results--slim"}}">
   <div class="container">
     {{#self-serve-alert-yaml-details
-      detectionYaml=model.detectionYaml
+      alertData=model.alertData
       isLoadError=isLoadError
-      displayMode="single"
     }}
     {{/self-serve-alert-yaml-details}}
   </div>
@@ -18,12 +17,14 @@
         <p class="te-alert-page-pending__text">{{errorText}}</p>
       </div>
     {{else}}
-    {{model.detectionSettingsYaml.yaml}}
       {{yaml-editor
+        alertId=model.alertId
+        subscriptionGroupId=model.subscriptionGroupId
         isEditMode=true
         showSettings=true
-        alertYaml=model.detectionYaml.yaml
-        detectionSettingsYaml=model.detectionSettingsYaml.yaml
+        subscriptionGroupNames=model.subscriptionGroups
+        alertYaml=model.detectionYaml
+        detectionSettingsYaml=model.subscriptionGroupYamlDisplay
       }}
     {{/if}}
   </div>
diff --git a/thirdeye/thirdeye-frontend/app/pods/self-serve/create-alert/template.hbs b/thirdeye/thirdeye-frontend/app/pods/self-serve/create-alert/template.hbs
index c85dafc..467360e 100644
--- a/thirdeye/thirdeye-frontend/app/pods/self-serve/create-alert/template.hbs
+++ b/thirdeye/thirdeye-frontend/app/pods/self-serve/create-alert/template.hbs
@@ -1,23 +1,21 @@
 <h1 class="te-title">Create Alert
-  {{#if isDevEnv}}
-    {{#x-toggle
-      value=isForm
-      classNames="te-toggle te-toggle--form te-toggle--left report-toggle pull-right"
-      theme="ios"
-      id="label-toggle"
-      showLabels=true
-      name="activeToggle"
-      onToggle=(action (mut isForm))
-      as |toggle|}}
-        {{#toggle.label value=isForm}}
-          <span class="te-label te-label--flush">YAML</span>
-        {{/toggle.label}}
-        {{toggle.switch theme='ios' onLabel='diff on' offLabel='diff off'}}
-        {{#toggle.label value=isForm}}
-          <span class="te-label te-label--flush">Form</span>
-        {{/toggle.label}}
-    {{/x-toggle}}
-  {{/if}}
+  {{#x-toggle
+    value=isForm
+    classNames="te-toggle te-toggle--form te-toggle--left report-toggle pull-right"
+    theme="ios"
+    id="label-toggle"
+    showLabels=true
+    name="activeToggle"
+    onToggle=(action (mut isForm))
+    as |toggle|}}
+      {{#toggle.label value=isForm}}
+        <span class="te-label te-label--flush">YAML</span>
+      {{/toggle.label}}
+      {{toggle.switch theme='ios' onLabel='diff on' offLabel='diff off'}}
+      {{#toggle.label value=isForm}}
+        <span class="te-label te-label--flush">Form</span>
+      {{/toggle.label}}
+  {{/x-toggle}}
 </h1>
 <main class="alert-create card-container card-container--padded te-form">
   {{#if isForm}}
diff --git a/thirdeye/thirdeye-frontend/app/styles/components/yaml-editor.scss b/thirdeye/thirdeye-frontend/app/styles/components/yaml-editor.scss
index 4a21320..9268e2e 100644
--- a/thirdeye/thirdeye-frontend/app/styles/components/yaml-editor.scss
+++ b/thirdeye/thirdeye-frontend/app/styles/components/yaml-editor.scss
@@ -13,6 +13,12 @@
   .col-xs-4 {
     margin-bottom: 20px;
   }
+
+  .col-xs-12 {
+    &.bottom-margin {
+      margin-bottom: 10px;
+    }
+  }
 }
 
 .ace_editor.ace_autocomplete {
diff --git a/thirdeye/thirdeye-frontend/app/utils/constants.js b/thirdeye/thirdeye-frontend/app/utils/constants.js
index ca93679..87dfda0 100644
--- a/thirdeye/thirdeye-frontend/app/utils/constants.js
+++ b/thirdeye/thirdeye-frontend/app/utils/constants.js
@@ -144,9 +144,9 @@ rules:
 
 export const yamlAlertSettings = `# Below are all dummy example. Please update accordingly.
 subscriptionGroupName: test_subscription_group
-application: your_application_name
-subscribedDetections: 
-  - your_detection_name
+application: thirdeye-internal
+subscribedDetections:
+  - name_of_the_detection_above
 
 alertSchemes:
 - type: EMAIL


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