This is an automated email from the ASF dual-hosted git repository.
xhsun 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 1e3e38c [TE] frontend - harleyjj/alert-details - add basic forecast
display capability to Alert Overview (#5236)
1e3e38c is described below
commit 1e3e38c645d969295e7d824f43cfa356ad671352
Author: Harley Jackson <[email protected]>
AuthorDate: Mon Apr 13 10:24:20 2020 -0700
[TE] frontend - harleyjj/alert-details - add basic forecast display
capability to Alert Overview (#5236)
---
.../app/pods/components/alert-details/component.js | 66 ++++++++++++++++++---
.../app/pods/components/alert-details/template.hbs | 11 ++++
thirdeye/thirdeye-frontend/app/styles/app.scss | 1 +
.../app/styles/components/alert-details.scss | 35 +++++++++++
.../app/utils/manage-alert-utils.js | 67 ++++++++++++++++++++--
5 files changed, 167 insertions(+), 13 deletions(-)
diff --git
a/thirdeye/thirdeye-frontend/app/pods/components/alert-details/component.js
b/thirdeye/thirdeye-frontend/app/pods/components/alert-details/component.js
index 4cff2c6..c63c6fc 100644
--- a/thirdeye/thirdeye-frontend/app/pods/components/alert-details/component.js
+++ b/thirdeye/thirdeye-frontend/app/pods/components/alert-details/component.js
@@ -47,6 +47,7 @@ export default Component.extend({
notifications: service('toast'),
timeseries: null,
analysisRange: [moment().subtract(2, 'day').startOf('day').valueOf(),
moment().add(1, 'day').startOf('day').valueOf()],
+ displayRange: [moment().subtract(2, 'day').startOf('day').valueOf(),
moment().add(1, 'day').startOf('day').valueOf()],
isPendingData: false,
colorMapping: colorMapping,
zoom: {
@@ -346,8 +347,16 @@ export default Component.extend({
axis: computed(
'analysisRange',
+ 'displayRange',
+ 'selectedBaseline',
function () {
- const analysisRange = get(this, 'analysisRange');
+ const {
+ analysisRange,
+ displayRange,
+ selectedBaseline
+ } = this.getProperties('analysisRange', 'displayRange',
'selectedBaseline');
+
+ const useRange = (selectedBaseline === 'predicted') ? displayRange :
analysisRange;
return {
y: {
@@ -364,8 +373,8 @@ export default Component.extend({
x: {
type: 'timeseries',
show: true,
- min: analysisRange[0],
- max: analysisRange[1],
+ min: useRange[0],
+ max: useRange[1],
tick: {
fit: false,
format: (d) => {
@@ -444,21 +453,56 @@ export default Component.extend({
}
),
+ isTrainingDisplayed: computed(
+ 'analysisRange',
+ 'displayRange',
+ 'selectedBaseline',
+ function() {
+ const {
+ analysisRange, displayRange, selectedBaseline
+ } = this.getProperties('analysisRange', 'displayRange',
'selectedBaseline');
+ return !(analysisRange[0] === displayRange[0] || selectedBaseline !==
'predicted');
+ }
+ ),
+
+ trainingMessage: computed(
+ 'analysisRange',
+ 'displayRange',
+ 'isTrainingMessage',
+ function() {
+ const {
+ analysisRange, displayRange
+ } = this.getProperties('analysisRange', 'displayRange');
+ return `Training + Forecast
(${moment(displayRange[0]).format(TABLE_DATE_FORMAT)} -
${moment(analysisRange[1]).format(TABLE_DATE_FORMAT)})`;
+ }
+ ),
+
series: computed(
'filteredAnomaliesOld.@each',
'filteredAnomaliesCurrent.@each',
'timeseries',
'baseline',
- 'analysisRange',
'selectedRule',
'metricUrn',
+ 'isTrainingDisplayed',
function () {
const {
- filteredAnomaliesOld, filteredAnomaliesCurrent, timeseries, baseline,
showRules, isPreviewMode
+ filteredAnomaliesOld, filteredAnomaliesCurrent, timeseries, baseline,
+ analysisRange, displayRange, showRules, isPreviewMode,
isTrainingDisplayed
} = getProperties(this, 'filteredAnomaliesOld',
'filteredAnomaliesCurrent',
- 'timeseries', 'baseline', 'showRules', 'isPreviewMode');
+ 'timeseries', 'baseline', 'analysisRange', 'displayRange', 'showRules',
+ 'isPreviewMode', 'isTrainingDisplayed');
+
+ const region = !isTrainingDisplayed ? {} :
+ {
+ timestamps: [displayRange[0], analysisRange[0]],
+ values: [1, 1],
+ type: 'region',
+ axis: 'y2'
+ };
const series = {};
+ series['training-region'] = region;
// Should be displayed in Create Mode of Preview with one set of
anomalies
let anomaliesCurrentLabel = 'Current Settings Anomalies';
let anomaliesOldLabel = 'Current Anomalies';
@@ -783,7 +827,7 @@ export default Component.extend({
uiDateFormat: UI_DATE_FORMAT,
activeRangeStart: moment(startDate).format(DISPLAY_DATE_FORMAT),
activeRangeEnd: moment(endDate).format(DISPLAY_DATE_FORMAT),
- timeRangeOptions: setUpTimeRangeOptions(TIME_RANGE_OPTIONS, duration),
+ timeRangeOptions: setUpTimeRangeOptions(TIME_RANGE_OPTIONS, duration,
!this.get('isPreviewMode')),
timePickerIncrement: TIME_PICKER_INCREMENT,
predefinedRanges
};
@@ -886,6 +930,7 @@ export default Component.extend({
if (!isPreviewMode) {
this.setProperties({
analysisRange: [moment().subtract(timeWindowSize,
'milliseconds').startOf('day').valueOf(), moment().add(1,
'day').startOf('day').valueOf()],
+ displayRange: [moment().subtract(timeWindowSize,
'milliseconds').startOf('day').valueOf(), moment().add(1,
'day').startOf('day').valueOf()],
duration: (timeWindowSize === 172800000) ? '48h' : 'custom',
selectedDimension: 'Choose a dimension',
// For now, we will only show predicted and bounds on daily and
minutely metrics with no dimensions, for the Alert Overview page
@@ -898,6 +943,7 @@ export default Component.extend({
} else {
this.setProperties({
analysisRange: [moment().subtract(timeWindowSize,
'milliseconds').startOf('day').valueOf(), moment().add(1,
'day').startOf('day').valueOf()],
+ displayRange: [moment().subtract(timeWindowSize,
'milliseconds').startOf('day').valueOf(), moment().add(1,
'day').startOf('day').valueOf()],
duration: 'custom',
selectedBaseline: 'predicted'
});
@@ -1120,7 +1166,8 @@ export default Component.extend({
this.setProperties({
timeseries: seriesSet.predictedTimeSeries,
baseline: seriesSet.predictedTimeSeries,
- isLoadingTimeSeries: false
+ isLoadingTimeSeries: false,
+ displayRange: [seriesSet.predictedTimeSeries.timestamp[0] ||
analysisRange[0], analysisRange[1]]
});
} else {
const urlBaseline =
`/rootcause/metric/timeseries?urn=${metricUrn}&start=${analysisRange[0]}&end=${analysisRange[1]}&offset=${selectedBaseline}&timezone=${timeZone}`;
@@ -1130,7 +1177,8 @@ export default Component.extend({
this.setProperties({
timeseries: seriesSet.predictedTimeSeries,
baseline: res,
- isLoadingTimeSeries: false
+ isLoadingTimeSeries: false,
+ displayRange: [seriesSet.predictedTimeSeries.timestamp[0] ||
analysisRange[0], analysisRange[1]]
});
});
}
diff --git
a/thirdeye/thirdeye-frontend/app/pods/components/alert-details/template.hbs
b/thirdeye/thirdeye-frontend/app/pods/components/alert-details/template.hbs
index 5c9aaab..7b1982f 100644
--- a/thirdeye/thirdeye-frontend/app/pods/components/alert-details/template.hbs
+++ b/thirdeye/thirdeye-frontend/app/pods/components/alert-details/template.hbs
@@ -210,6 +210,17 @@
{{/if}}
</div>
+ {{#if isTrainingDisplayed}}
+ <div class="col-xs-12 no-padding">
+ <div class="alert-details-msg-forecast">
+ <p>{{material-design-icon
+ name='error-outline'
+ }} {{trainingMessage}}
+ </p>
+ </div>
+ </div>
+ {{/if}}
+
{{!-- Missing anomaly modal --}}
{{#te-modal
cancelButtonText="Cancel"
diff --git a/thirdeye/thirdeye-frontend/app/styles/app.scss
b/thirdeye/thirdeye-frontend/app/styles/app.scss
index 7139ba0..1c470dd 100644
--- a/thirdeye/thirdeye-frontend/app/styles/app.scss
+++ b/thirdeye/thirdeye-frontend/app/styles/app.scss
@@ -31,6 +31,7 @@ body {
@import 'wrapper/styles';
// Components
+@import 'components/alert-details';
@import 'components/anomaly-id';
@import 'components/anomaly-graph';
@import 'components/te-navbar';
diff --git
a/thirdeye/thirdeye-frontend/app/styles/components/alert-details.scss
b/thirdeye/thirdeye-frontend/app/styles/components/alert-details.scss
new file mode 100644
index 0000000..5ec68b7
--- /dev/null
+++ b/thirdeye/thirdeye-frontend/app/styles/components/alert-details.scss
@@ -0,0 +1,35 @@
+.alert-details {
+ .mdi-error-outline {
+ width: 19px;
+
+ &::before {
+ font-size: 16px;
+ }
+ }
+
+ .alert-details-msg-forecast {
+ color: grey;
+
+ &__icon {
+ font-size: 20px;
+ &--error {
+ padding-right: 5px;
+ }
+ }
+
+ &__tooltip-link {
+ text-decoration: underline;
+
+ &:hover {
+ cursor: pointer;
+ }
+ }
+ }
+
+ .col-xs-12 {
+ &.no-padding {
+ padding-left: 0px;
+ padding-right: 0px;
+ }
+ }
+}
diff --git a/thirdeye/thirdeye-frontend/app/utils/manage-alert-utils.js
b/thirdeye/thirdeye-frontend/app/utils/manage-alert-utils.js
index 24bdf4d..c61e672 100644
--- a/thirdeye/thirdeye-frontend/app/utils/manage-alert-utils.js
+++ b/thirdeye/thirdeye-frontend/app/utils/manage-alert-utils.js
@@ -141,8 +141,8 @@ export function enhanceAnomalies(rawAnomalies,
severityScores) {
* @param {String} duration - the selected time span that is default
* @return {Array}
*/
-export function setUpTimeRangeOptions(datesKeys, duration) {
- const newRangeArr = [];
+export function setUpTimeRangeOptions(datesKeys, duration, forecast=false) {
+ let newRangeArr = [];
const defaultCustomRange = {
name: 'Custom',
@@ -150,11 +150,20 @@ export function setUpTimeRangeOptions(datesKeys,
duration) {
start: null,
isActive: !datesKeys.includes(duration)
};
+ newRangeArr = forecast ? futureAndPast(datesKeys, duration, newRangeArr) :
pastOnly(datesKeys, duration, newRangeArr);
+ newRangeArr.push(defaultCustomRange);
+ return newRangeArr;
+}
+/**
+ * Helper function for setUpTimeRangeOptions when returning past ranges only
+ * @returns {Array}
+ */
+function pastOnly(datesKeys, duration, newRangeArr) {
const dateKeyMap = new Map(
[
[ '1m', ['Last 30 Days', 1, 'month'] ],
- [ '3m', ['3 Months', 3, 'month'] ],
+ [ '3m', ['Last 3 Months', 3, 'month'] ],
[ '2w', ['Last 2 Weeks', 2, 'week'] ],
[ '1w', ['Last Week', 1, 'week'] ],
[ '2d', ['Yesterday', 2, 'day'] ],
@@ -193,8 +202,58 @@ export function setUpTimeRangeOptions(datesKeys, duration)
{
const isActive = duration === value;
newRangeArr.push({ name: label, value, start, end, isActive });
});
+ return newRangeArr;
+}
- newRangeArr.push(defaultCustomRange);
+/**
+ * Helper function for setUpTimeRangeOptions when returning past and future
options
+ * @returns {Array}
+ */
+function futureAndPast(datesKeys, duration, newRangeArr) {
+ const dateKeyMap = new Map(
+ [
+ [ '1m', ['Next 30 Days', 1, 'month'] ],
+ [ '3m', ['Next 3 Months', 3, 'month'] ],
+ [ '2w', ['Next 2 Weeks', 2, 'week'] ],
+ [ '1w', ['Next Week', 1, 'week'] ],
+ [ '2d', ['Tomorrow', 2, 'day'] ],
+ [ '1d', ['Next 24 Hours', 24, 'hour'] ],
+ [ '48h', ['Next 48 Hours', 48, 'hour'] ],
+ [ 'today', ['Today'] ]
+ ]);
+
+ newRangeArr = pastOnly(datesKeys, duration, newRangeArr);
+
+ datesKeys.forEach((value) => {
+ const currVal = dateKeyMap.get(value);
+ const label = currVal[0];
+ let start;
+ let end;
+ // overrides map above
+ switch(label) {
+ case 'Today':
+ start = moment().startOf('day');
+ end = start.add(1, 'days');
+ break;
+ case 'Tomorrow':
+ start = moment().startOf('day');
+ end = moment().add(2, 'day').startOf('day');
+ break;
+ case 'Next 24 Hours':
+ start = moment().startOf('hour');
+ end = moment().add(24, 'hour').startOf('hour');
+ break;
+ case 'Next 48 Hours':
+ start = moment().startOf('hour');
+ end = moment().add(48, 'hour').startOf('hour');
+ break;
+ default:
+ start = moment().startOf('day');
+ end = moment().add(currVal[1], currVal[2]).startOf('day');
+ }
+ const isActive = duration === value;
+ newRangeArr.push({ name: label, value, start, end, isActive });
+ });
return newRangeArr;
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]