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