Skip to content

Commit

Permalink
[TE] frontend - aaronucsd/added new custom component for Resolution
Browse files Browse the repository at this point in the history
1. Added new resolution custom component
2. fixed the icon issue on resolution select for model table
3. Updated styling for the fix in apache#2
4. Added new method to anomaly util file and moved a few needed anomaly methods from
app/pods/manage/alert/explore/controller.js
5. Moved anomalyResponseObj constant to anomaly util from
app/pods/manage/alert/explore/route.js
6. Updated app/pods/manage/alert/explore/* to use the methods from anomaly util
7. updated anomaly util unit test and ran all tests for sanity
8. Added new api anomaly file and unit test
  • Loading branch information
Long Huynh committed Mar 19, 2018
1 parent a893483 commit acef124
Show file tree
Hide file tree
Showing 13 changed files with 246 additions and 74 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import moment from 'moment';
export default [
{
id: 1,
anomalyId: 26020862,
start: 1491804013000,
end: 1491890413000,
anomalyFeedback: 'True anomaly',
dimensions: {
app: 'company',
country: 'US',
Expand All @@ -22,6 +24,7 @@ export default [
functionName: 'Alert Name 1'
}, {
id: 2,
anomalyId: 33330876,
start: 1491804013000,
end: moment().valueOf(),
dimensions: {
Expand All @@ -38,6 +41,7 @@ export default [
functionName: 'Alert Name 1'
}, {
id: 3,
anomalyId: 33330893,
start: 1491804013000,
end: moment().valueOf(),
dimensions: {
Expand All @@ -54,6 +58,7 @@ export default [
functionName: 'Alert Name 1'
}, {
id: 4,
anomalyId: 33340923,
start: 1491804013000,
end: moment().valueOf(),
severity: 0.86,
Expand All @@ -65,6 +70,7 @@ export default [
functionName: 'Alert Name 1'
}, {
id: 5,
anomalyId: 33381509,
start: 1491804013000,
end: moment().valueOf(),
dimensions: {
Expand All @@ -81,6 +87,7 @@ export default [
functionName: 'Alert Name 1'
}, {
id: 6,
anomalyId: 33381877,
start: 1491804013000,
end: 1491890413000,
dimensions: {
Expand All @@ -97,6 +104,7 @@ export default [
functionName: 'Alert Name 1'
}, {
id: 7,
anomalyId: 33302982,
start: 1491804013000,
end: 1491890413000,
dimensions: {
Expand All @@ -113,6 +121,7 @@ export default [
functionName: 'Alert Name 1'
}, {
id: 8,
anomalyId: 33306049,
start: 1491804013000,
end: 1491890413000,
dimensions: {
Expand All @@ -129,6 +138,7 @@ export default [
functionName: 'Alert Name 2'
}, {
id: 9,
anomalyId: 33306058,
start: 1491804013000,
end: moment().valueOf(),
dimensions: {
Expand All @@ -145,6 +155,24 @@ export default [
functionName: 'Alert Name 2'
}, {
id: 10,
anomalyId: 33314704,
start: 1491804013000,
end: moment().valueOf(),
dimensions: {
country: ['US', 'FR'],
pageName: ['some_page'],
random1: ['partial']
},
severity: 0.86,
current: 1444,
baseline: 1000,
feedback: 'Yes, but New Trend',
metricName: 'Metric Name 2',
metricId: 12345,
functionName: 'Alert Name 2'
}, {
id: 11,
anomalyId: 33314705,
start: 1491804013000,
end: moment().valueOf(),
dimensions: {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/**
* Custom model table component
* Constructs the select box for the resolution
* @module custom/anomalies-table/resolution
*
* @example for usage in models table columns definitions
* {
* propertyName: 'feedback',
* component: 'custom/anomalies-table/resolution',
* title: 'Resolution',
* className: 'anomalies-table__column',
* disableFiltering: true
* },
*/
import Component from "@ember/component";
import { getWithDefault } from '@ember/object';
import * as anomalyUtil from 'thirdeye-frontend/utils/anomaly';
import { set, setProperties } from '@ember/object';
import { getAnomalyDataUrl } from 'thirdeye-frontend/utils/api/anomaly';

export default Component.extend({
tagName: '',//using tagless so i can add my own in hbs
anomalyResponseNames: anomalyUtil.anomalyResponseObj.mapBy('name'),
anomalyDataUrl: getAnomalyDataUrl(),

actions: {
/**
* Handle dynamically saving anomaly feedback responses
* @method onChangeAnomalyResponse
* @param {Object} anomalyRecord - the anomaly being responded to
* @param {String} selectedResponse - user-selected anomaly feedback option
* @param {Object} inputObj - the selection object
*/
onChangeAnomalyResponse: async function(anomalyRecord, selectedResponse, inputObj) {
const responseObj = anomalyUtil.anomalyResponseObj.find(res => res.name === selectedResponse);
set(inputObj, 'selected', selectedResponse);
let res;
try {
// Save anomaly feedback
res = await anomalyUtil.updateAnomalyFeedback(anomalyRecord.anomalyId, responseObj.value)
// We make a call to ensure our new response got saved
res = await anomalyUtil.verifyAnomalyFeedback(anomalyRecord.anomalyId, responseObj.status)
const filterMap = getWithDefault(res, 'searchFilters.statusFilterMap', null);
if (filterMap && filterMap.hasOwnProperty(responseObj.status)) {
setProperties(anomalyRecord, {
anomalyFeedback: selectedResponse,
showResponseSaved: true
});
} else {
return Promise.reject(new Error('Response not saved'));
}
} catch (err) {
setProperties(anomalyRecord, {
showResponseFailed: true,
showResponseSaved: false
});
}
}
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<div class="anomalies-table__column-cell">
{{#if record.showResponseSaved}}
<i class="{{if record.showResponseSaved "te-anomaly-table__icon--status-no-margin" "te-anomaly-table__icon--hidden"}} glyphicon glyphicon-ok-circle" ></i>
{{else}}
<i class="{{if record.showResponseFailed "te-anomaly-table__icon--status-no-margin" "te-anomaly-table__icon--hidden"}} glyphicon glyphicon-remove-circle" ></i>
{{/if}}

{{#if record.isUserReported}}
<span class="te-anomaly-table__text">User Reported</span>
{{else}}
{{#power-select
triggerId=record.anomalyId
triggerClass="te-anomaly-table__select te-anomaly-table__select--margin-left"
options=anomalyResponseNames
searchEnabled=false
selected=record.anomalyFeedback
onchange=(action "onChangeAnomalyResponse" record)
as |response|
}}
{{response}}
{{/power-select}}
{{/if}}
</div>
1 change: 0 additions & 1 deletion thirdeye/thirdeye-frontend/app/pods/home/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ export default Controller.extend({
),

actions: {

/**
* Sets the selected application property based on user selection
* @param {Object} selectedApplication - object that represents selected application
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
setDuration
} from 'thirdeye-frontend/utils/manage-alert-utils';
import floatToPercent from 'thirdeye-frontend/utils/float-to-percent';
import * as anomalyUtil from 'thirdeye-frontend/utils/anomaly';

export default Controller.extend({
/**
Expand Down Expand Up @@ -398,30 +399,6 @@ export default Controller.extend({
});
}),

/**
* Update feedback status on any anomaly
* @method updateAnomalyFeedback
* @param {Number} anomalyId - the id of the anomaly to update
* @param {String} feedbackType - key for feedback type
* @return {Ember.RSVP.Promise}
*/
updateAnomalyFeedback(anomalyId, feedbackType) {
const url = `/anomalies/updateFeedback/${anomalyId}`;
const data = { feedbackType, comment: '' };
return fetch(url, postProps(data)).then((res) => checkStatus(res, 'post'));
},

/**
* Fetch a single anomaly record for verification
* @method verifyAnomalyFeedback
* @param {Number} anomalyId
* @return {undefined}
*/
verifyAnomalyFeedback(anomalyId) {
const anomalyUrl = this.get('anomalyDataUrl') + anomalyId;
return fetch(anomalyUrl).then(checkStatus);
},

/**
* Send a POST request to the report anomaly API (2-step process)
* http://go/te-ss-alert-flow-api
Expand Down Expand Up @@ -504,29 +481,30 @@ export default Controller.extend({
* @param {String} selectedResponse - user-selected anomaly feedback option
* @param {Object} inputObj - the selection object
*/
onChangeAnomalyResponse(anomalyRecord, selectedResponse, inputObj) {
const responseObj = this.get('anomalyResponseObj').find(res => res.name === selectedResponse);
onChangeAnomalyResponse: async function(anomalyRecord, selectedResponse, inputObj) {
const responseObj = anomalyUtil.anomalyResponseObj.find(res => res.name === selectedResponse);
set(inputObj, 'selected', selectedResponse);

// Save anomaly feedback
this.updateAnomalyFeedback(anomalyRecord.anomalyId, responseObj.value)
.then((res) => {
// We make a call to ensure our new response got saved
this.verifyAnomalyFeedback(anomalyRecord.anomalyId, responseObj.status)
.then((res) => {
const filterMap = res.searchFilters ? res.searchFilters.statusFilterMap : null;
if (filterMap && filterMap.hasOwnProperty(responseObj.status)) {
set(anomalyRecord, 'anomalyFeedback', selectedResponse);
set(anomalyRecord, 'showResponseSaved', true);
} else {
return Promise.reject(new Error('Response not saved'));
}
}); // verifyAnomalyFeedback
}) // updateAnomalyFeedback
.catch((err) => {
set(anomalyRecord, 'showResponseFailed', true);
set(anomalyRecord, 'showResponseSaved', false);
let res;
try {
// Save anomaly feedback
res = await anomalyUtil.updateAnomalyFeedback(anomalyRecord.anomalyId, responseObj.value)
// We make a call to ensure our new response got saved
res = await anomalyUtil.verifyAnomalyFeedback(anomalyRecord.anomalyId, responseObj.status)
const filterMap = getWithDefault(res, 'searchFilters.statusFilterMap', null);
if (filterMap && filterMap.hasOwnProperty(responseObj.status)) {
setProperties(anomalyRecord, {
anomalyFeedback: selectedResponse,
showResponseSaved: true
});
} else {
return Promise.reject(new Error('Response not saved'));
}
} catch (err) {
setProperties(anomalyRecord, {
showResponseFailed: true,
showResponseSaved: false
});
}
},

/**
Expand Down Expand Up @@ -670,6 +648,7 @@ export default Controller.extend({
this.transitionToRoute({ queryParams: { duration, startDate, endDate }});
},


/**
* Load tuning sub-route and properly toggle alert nav button
*/
Expand Down
29 changes: 4 additions & 25 deletions thirdeye/thirdeye-frontend/app/pods/manage/alert/explore/route.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import {
buildMetricDataUrl,
extractSeverity
} from 'thirdeye-frontend/utils/manage-alert-utils';
import { anomalyResponseObj } from 'thirdeye-frontend/utils/anomaly';
import { getAnomalyDataUrl } from 'thirdeye-frontend/utils/api/anomaly';

/**
* Shorthand for setting date defaults
Expand Down Expand Up @@ -55,28 +57,6 @@ const defaultDurationObj = {
endDate: moment()
};

/**
* Response type options for anomalies
*/
const anomalyResponseObj = [
{ name: 'Not reviewed yet',
value: 'NO_FEEDBACK',
status: 'Not Resolved'
},
{ name: 'True anomaly',
value: 'ANOMALY',
status: 'Confirmed Anomaly'
},
{ name: 'False alarm',
value: 'NOT_ANOMALY',
status: 'False Alarm'
},
{ name: 'Confirmed - New Trend',
value: 'ANOMALY_NEW_TREND',
status: 'New Trend'
}
];

/**
* Build WoW array from basic options
*/
Expand Down Expand Up @@ -229,7 +209,7 @@ export default Route.extend({

// Load endpoints for projected metrics. TODO: consolidate into CP if duplicating this logic
const qsParams = `start=${baseStart.utc().format(dateFormat)}&end=${baseEnd.utc().format(dateFormat)}&useNotified=true`;
const anomalyDataUrl = `/anomalies/search/anomalyIds/${startStamp}/${endStamp}/1?anomalyIds=`;
const anomalyDataUrl = getAnomalyDataUrl(startStamp, endStamp);
const metricsUrl = `/data/autocomplete/metric?name=${dataset}::${metricName}`;
const anomaliesUrl = `/dashboard/anomaly-function/${alertId}/anomalies?${qsParams}`;

Expand Down Expand Up @@ -303,7 +283,6 @@ export default Route.extend({
DEFAULT_SEVERITY,
anomalyDataUrl,
baselineOptions,
anomalyResponseObj,
alertEvalMetrics,
anomaliesLoaded: false,
isMetricDataInvalid: false,
Expand Down Expand Up @@ -462,7 +441,7 @@ export default Route.extend({
// Process anomaly records to make them template-ready
const anomalyData = yield enhanceAnomalies(rawAnomalies, severityScores);
// Prepare de-duped power-select option array for anomaly feedback
resolutionOptions.push(...new Set(anomalyData.map(record => record.anomalyFeedback)));
//resolutionOptions.push(...new Set(anomalyData.map(record => record.anomalyFeedback)));
// Populate dimensions power-select options if dimensions exist
if (hasDimensions) {
dimensionOptions.push(...new Set(anomalyData.map(anomaly => anomaly.dimensionString)));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@
{{else}}
{{#power-select
triggerId=anomaly.anomalyId
triggerClass="te-anomaly-table__select"
triggerClass="te-anomaly-table__select te-anomaly-table__select--margin-right"
options=responseOptions
searchEnabled=false
selected=anomaly.anomalyFeedback
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export default [
},
{
propertyName: 'feedback',
component: 'custom/anomalies-table/resolution',
title: 'Resolution',
className: 'anomalies-table__column',
disableFiltering: true
Expand Down
Loading

0 comments on commit acef124

Please sign in to comment.