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/28 22:04:05 UTC
[incubator-pinot] branch master updated: Email share (#3753)
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 587c597 Email share (#3753)
587c597 is described below
commit 587c597e70fa5d08d0824c261a161a5f797387d7
Author: Harley Jackson <ha...@gmail.com>
AuthorDate: Mon Jan 28 14:03:58 2019 -0800
Email share (#3753)
* [TE] frontend - harleyjj/share-dashboard - maintains columns and dashboard-level comments in share link
* [TE] frontend - harleyjj/share-dashboard - Align email options with columns after share
---
.../app/pods/home/share-dashboard/controller.js | 238 ++++++++-------------
.../app/pods/home/share-dashboard/route.js | 70 +++++-
.../app/pods/home/share-dashboard/template.hbs | 8 +-
3 files changed, 157 insertions(+), 159 deletions(-)
diff --git a/thirdeye/thirdeye-frontend/app/pods/home/share-dashboard/controller.js b/thirdeye/thirdeye-frontend/app/pods/home/share-dashboard/controller.js
index 5f2e7c8..f676376 100644
--- a/thirdeye/thirdeye-frontend/app/pods/home/share-dashboard/controller.js
+++ b/thirdeye/thirdeye-frontend/app/pods/home/share-dashboard/controller.js
@@ -10,7 +10,6 @@ import $ from 'jquery';
import _ from 'lodash';
import * as anomalyUtil from 'thirdeye-frontend/utils/anomaly';
import { isBlank } from '@ember/utils';
-import { task } from 'ember-concurrency';
import { inject as service } from '@ember/service';
import {
get,
@@ -18,26 +17,28 @@ import {
setProperties,
computed
} from '@ember/object';
-import { appendFilters } from 'thirdeye-frontend/utils/rca-utils';
-import { humanizeFloat, humanizeChange, checkStatus } from 'thirdeye-frontend/utils/utils';
-import floatToPercent from 'thirdeye-frontend/utils/float-to-percent';
+import { reads } from '@ember/object/computed';
const CUSTOMIZE_OPTIONS = [{
id: 0,
label: 'Nothing',
- value: 'Nothing'
+ value: 'Nothing',
+ selected: null
}, {
id: 1,
label: 'WoW',
- value: 'Wow'
+ value: 'Wow',
+ selected: null
}, {
id: 2,
label: 'Wo2W',
- value: 'Wo2w'
+ value: 'Wo2w',
+ selected: null
}, {
id: 3,
label: 'Median4W',
- value: 'Median4w'
+ value: 'Median4w',
+ selected: null
}];
export default Controller.extend({
@@ -46,14 +47,14 @@ export default Controller.extend({
showCopyTooltip: false,
showSharedTooltip: false,
shareUrl: null,
- showWow: false,
- showWo2w: false,
- showMedian4w: false,
- showDashboardSummary: false,
- offsetsMap: {},
- options: [],
- options_two: [],
- colspanNum: 4,
+ showDashboardSummary: reads('tree.firstObject.showDashboardSummary'),
+ showCustomizeEmailTemplate: reads('tree.firstObject.showCustomizeEmailTemplate'),
+ showWow: reads('tree.firstObject.showWow'),
+ showWo2w: reads('tree.firstObject.showWo2w'),
+ showMedian4w: reads('tree.firstObject.showMedian4w'),
+ options: reads('tree.firstObject.options'),
+ options_two: reads('tree.firstObject.options_two'),
+ colspanNum: reads('tree.firstObject.colspanNum'),
init() {
this._super(...arguments);
@@ -65,22 +66,9 @@ export default Controller.extend({
status: 'All Resolutions'
});
set(this, 'anomalyResponseFilterTypes', anomalyResponseFilterTypes);
-
- // Add the options for compare
- set(this, 'options_two', set(this, 'options', CUSTOMIZE_OPTIONS));
},
/**
- * @summary Returns the
- * @return {Array}
- */
- _getAnomalyByOffsetsMapping: task (function * () {
- const applicationAnomalies = get(this, 'model.anomalyMapping');
- const offsetsMapping = yield get(this, '_fetchOffsets').perform(applicationAnomalies);
- return offsetsMapping;
- }).drop(),
-
- /**
* @summary Returns the config object for the custom share template header.
* @return {object} The object of metrics, with array of alerts and array anomalies
* @example
@@ -184,13 +172,13 @@ export default Controller.extend({
if (typeof metric === 'string') {
const metricId = filteredAnomalyMapping[metric].metricId;
const functionId = filteredAnomalyMapping[metric].items[alert].functionId;
- filteredAnomalyMapping[metric].items[alert].viewTreeNode = viewTreeFirstChild.find(metric => metric.id === metricId).children.find(alert => alert.id === functionId);
+ set(filteredAnomalyMapping[metric].items[alert], 'viewTreeNode', viewTreeFirstChild.find(metric => metric.id === metricId).children.find(alert => alert.id === functionId));
}
});
// Keeping a reference to this new tree node for this metric in filteredAnomalyMapping
if (typeof metric === 'string') {
const metricId = filteredAnomalyMapping[metric].metricId;
- filteredAnomalyMapping[metric].viewTreeNode = viewTreeFirstChild.find(metric => metric.id === metricId);
+ set(filteredAnomalyMapping[metric], 'viewTreeNode', viewTreeFirstChild.find(metric => metric.id === metricId));
}
});
return viewTree;
@@ -205,7 +193,15 @@ export default Controller.extend({
isVisible: true,
isChecked: true,
comment: null,
- children: []
+ children: [],
+ showWow: false,
+ showWo2w: false,
+ showMedian4w: false,
+ showDashboardSummary: false,
+ showCustomizeEmailTemplate: false,
+ options: [ ...CUSTOMIZE_OPTIONS],
+ options_two: [ ...CUSTOMIZE_OPTIONS],
+ colspan: 4
}];
viewTreeFirstChild = viewTree.get('firstObject').children;
@@ -226,7 +222,7 @@ export default Controller.extend({
children: []
});
// Keeping a reference to this new tree node for this alert in filteredAnomalyMapping
- filteredAnomalyMapping[metric].items[alert].viewTreeNode = tempChildren[index];
+ set(filteredAnomalyMapping[metric].items[alert], 'viewTreeNode', tempChildren[index]);
});
//add each metric to tree selection
@@ -243,7 +239,7 @@ export default Controller.extend({
children: tempChildren
});
// Keeping a reference to this new tree node for this metric in filteredAnomalyMapping
- filteredAnomalyMapping[metric].viewTreeNode = viewTreeFirstChild[index];
+ set(filteredAnomalyMapping[metric], 'viewTreeNode', viewTreeFirstChild[index]);
}
});
@@ -269,68 +265,6 @@ export default Controller.extend({
});
},
- _fetchOffsets: task (function * (anomalyMapping) {
- if (!anomalyMapping) { return; }
-
- let map = {};
- let index = 1;
- // Iterate through each anomaly
- yield Object.keys(anomalyMapping).some(function(metric) {
- Object.keys(anomalyMapping[metric].items).some(function(alert) {
- anomalyMapping[metric].items[alert].items.forEach(async (item) => {
- const metricName = get(item.anomaly, 'metricName');
- const metricId = get(item.anomaly, 'metricId');
- const functionName = get(item.anomaly, 'functionName');
- const functionId = get(item.anomaly, 'functionId');
-
- const dimensions = get(item.anomaly, 'dimensions');
- const start = get(item.anomaly, 'start');
- const end = get(item.anomaly, 'end');
-
- if (!map[metricName]) {
- map[metricName] = { 'metricId': metricId, items: {}, count: index };
- index++;
- }
-
- if(!map[metricName].items[functionName]) {
- map[metricName].items[functionName] = { 'functionId': functionId, items: [] };
- }
-
- const filteredDimensions = Object.keys(dimensions).map(key => [key, '=', dimensions[key]]);
- //build new urn
- const metricUrn = appendFilters(`thirdeye:metric:${metricId}`, filteredDimensions);
- //Get all in the following order - current,wo2w,median4w
- const offsets = await fetch(`/rootcause/metric/aggregate/batch?urn=${metricUrn}&start=${start}&end=${end}&offsets=wo1w,wo2w,median4w&timezone=America/Los_Angeles`).then(checkStatus).then(res => res);
-
- const current = get(item.anomaly, 'current');
- const wow = humanizeFloat(offsets[0]);
- const wo2w = humanizeFloat(offsets[1]);
- const median4w = humanizeFloat(offsets[2]);
- const wowChange = floatToPercent(Number((current - offsets[0]) / offsets[0]));
- const wo2wChange = floatToPercent(Number((current - offsets[1]) / offsets[1]));
- const median4wChange = floatToPercent(Number((current - offsets[2]) / offsets[2]));
- const wowHumanizeChange = humanizeChange(Number((current - offsets[0]) / offsets[0]));
- const wo2wHumanizeChange = humanizeChange(Number((current - offsets[1]) / offsets[1]));
- const median4wHumanizeChange = humanizeChange(Number((current - offsets[2]) / offsets[2]));
-
- set(item.anomaly, 'offsets', offsets ? {
- 'wow': { value: wow, change: wowChange, humanizedChangeDisplay: wowHumanizeChange },
- 'wo2w': { value: wo2w, change: wo2wChange, humanizedChangeDisplay: wo2wHumanizeChange },
- 'median4w': { value: median4w, change: median4wChange, humanizedChangeDisplay: median4wHumanizeChange },
- } : {
- 'wow': '-',
- 'wo2w': '-',
- 'median4w': '-'
- });
-
- map[metricName].items[functionName].items.push(item);
- });
- });
- });
- // return updated anomalyMapping
- return anomalyMapping;
- }).drop(),
-
/**
* Helper for getting the matching selected response feedback object
* @param {string} text - this could be anything that we want to do a copy to clipboard
@@ -361,45 +295,44 @@ export default Controller.extend({
return text;
},
- async _getOffsets() {
- const map = get(this, 'offsetsMap');
- if (Object.keys(map).length === 0 ) {//Only fetch if empty
- const result = await get(this, '_getAnomalyByOffsetsMapping').perform();
- let index = 1;
- // Iterate through each anomaly
- Object.keys(result).some(function(metric) {
- Object.keys(result[metric].items).some(function(alert) {
- result[metric].items[alert].items.forEach(item => {
- const metricName = get(item.anomaly, 'metricName');
- const metricId = get(item.anomaly, 'metricId');
- const functionName = get(item.anomaly, 'functionName');
- const functionId = get(item.anomaly, 'functionId');
- if (!map[metricName]) {
- map[metricName] = { 'metricId': metricId, items: {}, count: index };
- index++;
- }
-
- if(!map[metricName].items[functionName]) {
- map[metricName].items[functionName] = { 'functionId': functionId, items: [] };
- }
+ /**
+ * Helper for toggling show properties in tree.firstObject
+ * @param {string} property - showWow, showWo2w, showMedian4w, showDashboardSummary, or showCustomizeEmailTemplate
+ * @return {none} - this helper is just a setter
+ */
+ _toggleTreeProperty(property) {
+ let currentState = get(this, 'tree.firstObject');
+ set(currentState, property, !currentState[property]);
+ },
- map[metricName].items[functionName].items.push(item);
- });
- });
- });
- setProperties(this, {
- 'model.anomalyMapping': map,
- 'offsetsMap': map
- });
+ /**
+ * Helper for setting selected in email selectors
+ * @param {string} selectedBaseline - Wow, Wo2w, Median4w
+ * @param {Array} choices - [{}, {}, ...]
+ * @return {none} - this helper is just a setter
+ */
+ _selectOption(choices, selectedBaseline) {
+ const newChoices = [];
+ choices.forEach(choice => {
+ const newObj = { ...choice};
+ if (newObj.value === selectedBaseline) {
+ newObj.selected = 'selected';
+ } else {
+ newObj.selected = null;
}
+ newChoices.push(newObj);
+ });
+ return newChoices;
},
_customizeEmailHelper(option, type) {
//reset both selects' options
- set(this, 'options_two', set(this, 'options', CUSTOMIZE_OPTIONS));
+ set(this, 'tree.firstObject.options', [ ...CUSTOMIZE_OPTIONS]);
+ set(this, 'tree.firstObject.options_two', [ ...CUSTOMIZE_OPTIONS]);
//hide all except if the sibling's value and not `nothing`
- setProperties(this, {
+ let currentState = get(this, 'tree.firstObject');
+ setProperties(currentState, {
'showWow': false,
'showWo2w': false,
'showMedian4w': false
@@ -409,58 +342,56 @@ export default Controller.extend({
const customizeEmail1 = document.getElementById('customizeEmail1').value;
const customizeEmail2 = document.getElementById('customizeEmail2').value;
- const sibingValue = type === 'one' ? customizeEmail2 : customizeEmail1;
- this.toggleProperty(`show${sibingValue}`);
+ const siblingValue = type === 'one' ? customizeEmail2 : customizeEmail1;
+ this._toggleTreeProperty(`show${siblingValue}`);
//Calculates colspan Number
const showCustomizeEmailTemplate = get(this, 'showCustomizeEmailTemplate');
if(showCustomizeEmailTemplate && (customizeEmail1 === 'Nothing' || customizeEmail2 === 'Nothing')) {
- set(this, 'colspanNum', 5);
+ set(this, 'tree.firstObject.colspanNum', 5);
} else if (showCustomizeEmailTemplate) {
- set(this, 'colspanNum', 6);
+ set(this, 'tree.firstObject.colspanNum', 6);
} else {
- set(this, 'colspanNum', 4);
+ set(this, 'tree.firstObject.colspanNum', 4);
}
+ let limitedSelfOptions = this._selectOption([ ...CUSTOMIZE_OPTIONS], option);
+ let limitedSiblingOptions = this._selectOption([ ...CUSTOMIZE_OPTIONS], siblingValue);
+
//limited sibling list to selected choice
- const limitedSiblingOptions = CUSTOMIZE_OPTIONS.filter(function(item){
+ limitedSiblingOptions = limitedSiblingOptions.filter(function(item){
return item.value !== option;
});
//limited current list to sibling's existing selected
- const limitedSelfOptions = CUSTOMIZE_OPTIONS.filter(function(item){
- return item.value !== sibingValue;
+ limitedSelfOptions = limitedSelfOptions.filter(function(item){
+ return item.value !== siblingValue;
});
- if (type === 'one') {
- set(this, 'options_two', limitedSiblingOptions);
- set(this, 'options', limitedSelfOptions);
- } else {
- set(this, 'options', limitedSiblingOptions);
- set(this, 'options_two', limitedSelfOptions);
- }
-
- // fetch base on offset
- if (option !== 'Nothing') {
- this._getOffsets();
- }
-
switch(option) {
case 'Nothing':
//hide accordingly
break;
case 'Wow':
//show wow column and it's sibling
- this.toggleProperty('showWow');
+ this._toggleTreeProperty('showWow');
break;
case 'Wo2w':
//show wo2w column and it's sibling
- this.toggleProperty('showWo2w');
+ this._toggleTreeProperty('showWo2w');
break;
case 'Median4w':
//show median4w column and it's sibling
- this.toggleProperty('showMedian4w');
+ this._toggleTreeProperty('showMedian4w');
break;
}
+
+ if (type === 'one') {
+ set(this, 'tree.firstObject.options_two', limitedSiblingOptions);
+ set(this, 'tree.firstObject.options', limitedSelfOptions);
+ } else {
+ set(this, 'tree.firstObject.options', limitedSiblingOptions);
+ set(this, 'tree.firstObject.options_two', limitedSelfOptions);
+ }
},
actions: {
@@ -529,7 +460,6 @@ export default Controller.extend({
let res = get(this, 'tree.firstObject.children').filter(metric => metric.id === id);
set(res, 'firstObject.comment', userComment);
}
-
},
/**
@@ -552,9 +482,9 @@ export default Controller.extend({
}
if (id === 'dashboard_summary') {
- this.toggleProperty('showDashboardSummary');
+ this._toggleTreeProperty('showDashboardSummary');
} else if (id === 'customize_email') {
- this.toggleProperty('showCustomizeEmailTemplate');
+ this._toggleTreeProperty('showCustomizeEmailTemplate');
}
},
diff --git a/thirdeye/thirdeye-frontend/app/pods/home/share-dashboard/route.js b/thirdeye/thirdeye-frontend/app/pods/home/share-dashboard/route.js
index a3b3625..9953a5d 100644
--- a/thirdeye/thirdeye-frontend/app/pods/home/share-dashboard/route.js
+++ b/thirdeye/thirdeye-frontend/app/pods/home/share-dashboard/route.js
@@ -11,6 +11,9 @@ import {
set,
setProperties
} from '@ember/object';
+import { appendFilters } from 'thirdeye-frontend/utils/rca-utils';
+import { humanizeFloat, humanizeChange, checkStatus } from 'thirdeye-frontend/utils/utils';
+import floatToPercent from 'thirdeye-frontend/utils/float-to-percent';
const queryParamsConfig = {
refreshModel: true
@@ -70,7 +73,7 @@ export default Route.extend(AuthenticatedRouteMixin, {
return new RSVP.Promise(async (resolve, reject) => {
try {
- const anomalyMapping = appName ? await get(this, '_getAnomalyMapping').perform(model) : [];//DEMO:
+ const anomalyMapping = appName ? await get(this, '_getAnomalyMapping').perform(model) : []; //DEMO:
const shareMetaData = shareId ? await get(this, 'shareDashboardApiService').queryShareMetaById(shareId) : [];
const shareTemplateConfig = appName ? await get(this, 'shareTemplateConfigApiService').queryShareTemplateConfigByAppName(appName) : {};
const defaultParams = {
@@ -123,6 +126,71 @@ export default Route.extend(AuthenticatedRouteMixin, {
anomalyMapping[metricName].items[functionName].items.push(get(this, 'anomaliesApiService').getHumanizedEntity(anomaly, humanizedObject));
});
+ anomalyMapping = yield get(this, '_fetchOffsets').perform(anomalyMapping);
+ return anomalyMapping;
+ }).drop(),
+
+ _fetchOffsets: task (function * (anomalyMapping) {
+ if (!anomalyMapping) { return; }
+
+ let map = {};
+ let index = 1;
+ // Iterate through each anomaly
+ yield Object.keys(anomalyMapping).some(function(metric) {
+ Object.keys(anomalyMapping[metric].items).some(function(alert) {
+ anomalyMapping[metric].items[alert].items.forEach(async (item) => {
+
+ const anomaly = item.anomaly;
+ const metricName = get(anomaly, 'metricName');
+ const metricId = get(anomaly, 'metricId');
+ const functionName = get(anomaly, 'functionName');
+ const functionId = get(anomaly, 'functionId');
+
+ const dimensions = get(anomaly, 'dimensions');
+ const start = get(anomaly, 'start');
+ const end = get(anomaly, 'end');
+
+ if (!map[metricName]) {
+ map[metricName] = { 'metricId': metricId, items: {}, count: index };
+ index++;
+ }
+
+ if(!map[metricName].items[functionName]) {
+ map[metricName].items[functionName] = { 'functionId': functionId, items: [] };
+ }
+
+ const filteredDimensions = Object.keys(dimensions).map(key => [key, '=', dimensions[key]]);
+ //build new urn
+ const metricUrn = appendFilters(`thirdeye:metric:${metricId}`, filteredDimensions);
+ //Get all in the following order - current,wo2w,median4w
+ const offsets = await fetch(`/rootcause/metric/aggregate/batch?urn=${metricUrn}&start=${start}&end=${end}&offsets=wo1w,wo2w,median4w&timezone=America/Los_Angeles`).then(checkStatus).then(res => res);
+
+ const current = get(anomaly, 'current');
+ const wow = humanizeFloat(offsets[0]);
+ const wo2w = humanizeFloat(offsets[1]);
+ const median4w = humanizeFloat(offsets[2]);
+ const wowChange = floatToPercent(Number((current - offsets[0]) / offsets[0]));
+ const wo2wChange = floatToPercent(Number((current - offsets[1]) / offsets[1]));
+ const median4wChange = floatToPercent(Number((current - offsets[2]) / offsets[2]));
+ const wowHumanizeChange = humanizeChange(Number((current - offsets[0]) / offsets[0]));
+ const wo2wHumanizeChange = humanizeChange(Number((current - offsets[1]) / offsets[1]));
+ const median4wHumanizeChange = humanizeChange(Number((current - offsets[2]) / offsets[2]));
+
+ set(anomaly, 'offsets', offsets ? {
+ 'wow': { value: wow, change: wowChange, humanizedChangeDisplay: wowHumanizeChange },
+ 'wo2w': { value: wo2w, change: wo2wChange, humanizedChangeDisplay: wo2wHumanizeChange },
+ 'median4w': { value: median4w, change: median4wChange, humanizedChangeDisplay: median4wHumanizeChange }
+ } : {
+ 'wow': '-',
+ 'wo2w': '-',
+ 'median4w': '-'
+ });
+
+ map[metricName].items[functionName].items.push(item);
+ });
+ });
+ });
+ // return updated anomalyMapping
return anomalyMapping;
}).drop(),
diff --git a/thirdeye/thirdeye-frontend/app/pods/home/share-dashboard/template.hbs b/thirdeye/thirdeye-frontend/app/pods/home/share-dashboard/template.hbs
index 804262c..d54f9f3 100644
--- a/thirdeye/thirdeye-frontend/app/pods/home/share-dashboard/template.hbs
+++ b/thirdeye/thirdeye-frontend/app/pods/home/share-dashboard/template.hbs
@@ -54,7 +54,7 @@
<h4 style="color: rgba(0,0,0,0.9);font-size: 18px;font-weight: bold;">Configure summary</h4>
<div>
<div style="margin-left: 15px;display: inline-block;">
- <p><input type="checkbox" {{action 'toggleSelection' "dashboard_summary" on="change"}}> Add dashboard-level comments</p>
+ <p><input type="checkbox" checked={{showDashboardSummary}} {{action 'toggleSelection' "dashboard_summary" on="change"}}> Add dashboard-level comments</p>
{{#if showDashboardSummary}}
<p>
<textarea {{action 'updateComment' "dashboard_summary" on="change"}} value="{{dashboard_summary_comment}}" placeholder="Comment for dashboard summary" name="dashboard_summary" id="dashboard_summary" style="border: none;border-bottom: 1px solid grey;margin-left: 15px;width: 800px;">
@@ -80,20 +80,20 @@
<!-- Customize email template -->
<div>
<div style="margin-left: 15px;display: inline-block;">
- <p><input type="checkbox" {{action 'toggleSelection' "customize_email" on="change"}}> Customize email template</p>
+ <p><input type="checkbox" checked={{showCustomizeEmailTemplate}} {{action 'toggleSelection' "customize_email" on="change"}}> Customize email template</p>
<p style="margin-left: 15px;">
{{#if showCustomizeEmailTemplate}}
{{!-- <select onchange={{action (mut field.value) value="target.value"}} class={{field.className}}> --}}
Compare current with
<select id="customizeEmail1" onchange={{action "onCustomizeEmail1" value="target.value"}}>
{{#each options as |option|}}
- <option value={{option.value}}>{{option.label}}</option>
+ <option value={{option.value}} selected={{option.selected}}>{{option.label}}</option>
{{/each}}
</select>
and
<select id="customizeEmail2" onchange={{action "onCustomizeEmail2" value="target.value"}}>
{{#each options_two as |option|}}
- <option value={{option.value}}>{{option.label}}</option>
+ <option value={{option.value}} selected={{option.selected}}>{{option.label}}</option>
{{/each}}
</select>
{{/if}}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org
For additional commands, e-mail: commits-help@pinot.apache.org