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
…2634)

1. Added new resolution custom component
2. fixed the icon issue on resolution select for model table
3. Updated styling for the fix in #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
aaronucsd authored and npawar committed Apr 6, 2018
1 parent c3c30a1 commit b9c6008
Show file tree
Hide file tree
Showing 13 changed files with 246 additions and 74 deletions.
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
@@ -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
});
}
}
}
});
@@ -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
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
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
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
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
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

0 comments on commit b9c6008

Please sign in to comment.