You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pinot.apache.org by ji...@apache.org on 2019/02/06 22:09:05 UTC
[incubator-pinot] branch master updated: [TE] frontend -
harleyjj/yaml-editor - implements simple graph for preview (#3787)
This is an automated email from the ASF dual-hosted git repository.
jihao 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 280c192 [TE] frontend - harleyjj/yaml-editor - implements simple graph for preview (#3787)
280c192 is described below
commit 280c192a86f6f66a75a3c4884f864d6bf4be1347
Author: Harley Jackson <ha...@gmail.com>
AuthorDate: Wed Feb 6 14:08:58 2019 -0800
[TE] frontend - harleyjj/yaml-editor - implements simple graph for preview (#3787)
implements simple graph for preview
adds graph and table, limits yaml/preview calls
---
.../app/pods/components/alert-details/component.js | 378 +++++++++++++++++++--
.../app/pods/components/alert-details/template.hbs | 218 +++++++++++-
.../app/pods/components/anomaly-graph/component.js | 95 +-----
.../app/pods/components/yaml-editor/component.js | 9 +-
.../app/pods/components/yaml-editor/template.hbs | 4 +-
5 files changed, 582 insertions(+), 122 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 95d7e23..34259fa 100644
--- a/thirdeye/thirdeye-frontend/app/pods/components/alert-details/component.js
+++ b/thirdeye/thirdeye-frontend/app/pods/components/alert-details/component.js
@@ -14,13 +14,19 @@
*/
import Component from '@ember/component';
-import { computed, observer, setProperties, set, get } from '@ember/object';
+import { computed, observer, set, get, getProperties } from '@ember/object';
+import { later } from '@ember/runloop';
+import { checkStatus, humanizeFloat } from 'thirdeye-frontend/utils/utils';
+import { colorMapping, toColor, makeTime } from 'thirdeye-frontend/utils/rca-utils';
import { inject as service } from '@ember/service';
import { task } from 'ember-concurrency';
import floatToPercent from 'thirdeye-frontend/utils/float-to-percent';
import { setUpTimeRangeOptions } from 'thirdeye-frontend/utils/manage-alert-utils';
import moment from 'moment';
+import _ from 'lodash';
+import d3 from 'd3';
+const TABLE_DATE_FORMAT = 'MMM DD, hh:mm A'; // format for anomaly table
const TIME_PICKER_INCREMENT = 5; // tells date picker hours field how granularly to display time
const DEFAULT_ACTIVE_DURATION = '1m'; // setting this date range selection as default (Last 24 Hours)
const UI_DATE_FORMAT = 'MMM D, YYYY hh:mm a'; // format for date picker to use (usually varies by route or metric)
@@ -31,24 +37,203 @@ export default Component.extend({
anomaliesApiService: service('services/api/anomalies'),
notifications: service('toast'),
anomalyMapping: {},
+ timeseries: null,
+ isLoading: false,
analysisRange: [moment().subtract(1, 'month').startOf('hour').valueOf(), moment().startOf('hour').valueOf()],
displayRange: [moment().subtract(2, 'month').startOf('hour').valueOf(), moment().startOf('hour').valueOf()],
isPendingData: false,
+ colorMapping: colorMapping,
+ zoom: {
+ enabled: true,
+ rescale: true
+ },
- alertYamlChanged: observer('alertYaml', 'analysisRange', 'disableYamlSave', async function() {
- set(this, 'isPendingData', true);
- // deal with the change
- const alertYaml = get(this, 'alertYaml');
- if(alertYaml) {
- try {
- const anomalyMapping = await this.get('_getAnomalyMapping').perform(alertYaml);
- set(this, 'isPendingData', false);
- set(this, 'anomalyMapping', anomalyMapping);
- } catch (error) {
- throw new Error(`Unable to retrieve anomaly data. ${error}`);
+ legend: {
+ show: true,
+ position: 'right'
+ },
+ errorTimeseries: null,
+ metricUrn: null,
+ errorBaseline: null,
+ compareMode: 'wo1w',
+ baseline: null,
+ errorAnomalies: null,
+ showPreview: false,
+ componentId: 'timeseries-chart',
+ anomalies: null,
+ baselineOptions: [
+ { name: 'wo1w', isActive: true},
+ { name: 'wo2w', isActive: false},
+ { name: 'wo3w', isActive: false},
+ { name: 'wo4w', isActive: false},
+ { name: 'mean4w', isActive: false},
+ { name: 'median4w', isActive: false},
+ { name: 'min4w', isActive: false},
+ { name: 'max4w', isActive: false},
+ { name: 'none', isActive: false}
+ ],
+ sortColumnStartUp: false,
+ sortColumnScoreUp: false,
+ sortColumnChangeUp: false,
+ sortColumnNumberUp: true,
+ sortColumnResolutionUp: false,
+ selectedSortMode: '',
+ selectedBaseline: 'wo1w',
+
+ // alertYamlChanged: observer('alertYaml', 'analysisRange', 'disableYamlSave', async function() {
+ // set(this, 'isPendingData', true);
+ // // deal with the change
+ // const alertYaml = get(this, 'alertYaml');
+ // if(alertYaml) {
+ // try {
+ // const anomalyMapping = await this.get('_getAnomalyMapping').perform(alertYaml);
+ // set(this, 'isPendingData', false);
+ // set(this, 'anomalyMapping', anomalyMapping);
+ // debugger;
+ // } catch (error) {
+ // throw new Error(`Unable to retrieve anomaly data. ${error}`);
+ // }
+ // }
+ // }),
+
+ disablePreviewButton: computed(
+ 'alertYaml',
+ 'isLoading',
+ function() {
+ return (get(this, 'alertYaml') === null || get(this, 'isLoading') === true);
+ }
+ ),
+
+ axis: computed(
+ 'displayRange',
+ function () {
+ const displayRange = getProperties(this, 'displayRange');
+
+ return {
+ y: {
+ show: true,
+ tick: {
+ format: function(d){return humanizeFloat(d);}
+ }
+ },
+ y2: {
+ show: false,
+ min: 0,
+ max: 1
+ },
+ x: {
+ type: 'timeseries',
+ show: true,
+ min: displayRange[0],
+ max: displayRange[1],
+ tick: {
+ fit: false,
+ format: (d) => {
+ const t = makeTime(d);
+ if (t.valueOf() === t.clone().startOf('day').valueOf()) {
+ return t.format('MMM D (ddd)');
+ }
+ return t.format('h:mm a');
+ }
+ }
+ }
+ };
+ }
+ ),
+
+ series: computed(
+ 'anomalies',
+ 'timeseries',
+ 'baseline',
+ 'analysisRange',
+ 'displayRange',
+ function () {
+ const {
+ metricUrn, anomalies, timeseries, baseline, analysisRange, displayRange
+ } = getProperties(this, 'metricUrn', 'anomalies', 'timeseries',
+ 'baseline', 'analysisRange', 'displayRange');
+
+ const series = {};
+
+ if (!_.isEmpty(anomalies)) {
+
+ anomalies
+ .filter(anomaly => anomaly.metricUrn === metricUrn)
+ .forEach(anomaly => {
+ const key = this._formatAnomaly(anomaly);
+ series[key] = {
+ timestamps: [anomaly.startTime, anomaly.endTime],
+ values: [1, 1],
+ type: 'line',
+ color: 'teal',
+ axis: 'y2'
+ };
+ series[key + '-region'] = Object.assign({}, series[key], {
+ type: 'region',
+ color: 'orange'
+ });
+ });
}
+
+ if (timeseries && !_.isEmpty(timeseries.value)) {
+ series['current'] = {
+ timestamps: timeseries.timestamp,
+ values: timeseries.value,
+ type: 'line',
+ color: toColor(metricUrn)
+ };
+ }
+
+ if (baseline && !_.isEmpty(baseline.value)) {
+ series['baseline'] = {
+ timestamps: baseline.timestamp,
+ values: baseline.value,
+ type: 'line',
+ color: 'light-' + toColor(metricUrn)
+ };
+ }
+
+ // detection range
+ if (timeseries && !_.isEmpty(timeseries.value)) {
+ series['pre-detection-region'] = {
+ timestamps: [displayRange[0], analysisRange[0]],
+ values: [1, 1],
+ type: 'region',
+ color: 'grey'
+ };
+ }
+
+ return series;
+ }
+ ),
+
+ /**
+ * formats anomalies for table
+ * @method tableAnomalies
+ * @return {Array}
+ */
+ tableAnomalies: computed(
+ 'anomalies',
+ function() {
+ const anomalies = get(this, 'anomalies');
+ let tableData = [];
+ let i = 1;
+
+ anomalies.forEach(a => {
+ let tableRow = {
+ index: i,
+ startDateStr: this._formatAnomaly(a),
+ severityScore: a.score,
+ shownCurrent: humanizeFloat(a.avgCurrentVal),
+ shownBaseline: humanizeFloat(a.avgBaselineVal),
+ shownChangeRate: humanizeFloat(((a.avgCurrentVal/a.avgBaselineVal - 1.0) * 100.0))
+ };
+ tableData.push(tableRow);
+ i++;
+ });
+ return tableData;
}
- }),
+ ),
/**
* Stats to display in cards
@@ -116,7 +301,7 @@ export default Component.extend({
* @type {Object[]} - array of objects, each of which represents each date pill
*/
pill: computed(
- 'analysisRange', 'startDate', 'endDate' ,'duration',
+ 'analysisRange', 'startDate', 'endDate', 'duration',
function() {
const analysisRange = get(this, 'analysisRange');
const startDate = Number(analysisRange[0]) || Number(get(this, 'startDate'));
@@ -151,9 +336,10 @@ export default Component.extend({
const notifications = get(this, 'notifications');
//detection alert fetch
- const start = analysisRange[0] || '1548489600000';
- const end = analysisRange[1] || '1548748800000';
- const alertUrl = `yaml/preview?start=${start}&end=${end}&tuningStart=0&tuningEnd=0`;
+ const start = analysisRange[0];
+ const end = analysisRange[1];
+ const alertUrl = `/yaml/preview?start=${start}&end=${end}&tuningStart=0&tuningEnd=0`;
+ let anomalies;
try {
const alert_result = yield fetch(alertUrl, postProps);
const alert_status = get(alert_result, 'status');
@@ -162,7 +348,9 @@ export default Component.extend({
if (alert_status !== 200 && applicationAnomalies.message) {
notifications.error(applicationAnomalies.message, 'Preview alert failed');
} else {
- const anomalies = applicationAnomalies.anomalies;
+ anomalies = applicationAnomalies.anomalies;
+ set(this, 'metricUrn', Object.keys(applicationAnomalies.diagnostics['0'])[0]);
+
if (anomalies && anomalies.length > 0) {
const humanizedObject = {
queryDuration: '1m',
@@ -187,9 +375,109 @@ export default Component.extend({
notifications.error('Preview alert failed', error);
}
- return anomalyMapping;
+ return {
+ anomalyMapping,
+ anomalies
+ };
}).drop(),
+ didRender(){
+ this._super(...arguments);
+
+ later(() => {
+ this._buildSliderButton();
+ });
+ },
+
+ // Helper function that builds the subchart region buttons
+ _buildSliderButton() {
+ const componentId = this.get('componentId');
+ const resizeButtons = d3.select(`.${componentId}`).selectAll('.resize');
+
+ resizeButtons.append('circle')
+ .attr('cx', 0)
+ .attr('cy', 30)
+ .attr('r', 10)
+ .attr('fill', '#0091CA');
+ resizeButtons.append('line')
+ .attr('class', 'anomaly-graph__slider-line')
+ .attr("x1", 0)
+ .attr("y1", 27)
+ .attr("x2", 0)
+ .attr("y2", 33);
+
+ resizeButtons.append('line')
+ .attr('class', 'anomaly-graph__slider-line')
+ .attr("x1", -5)
+ .attr("y1", 27)
+ .attr("x2", -5)
+ .attr("y2", 33);
+
+ resizeButtons.append('line')
+ .attr('class', 'anomaly-graph__slider-line')
+ .attr("x1", 5)
+ .attr("y1", 27)
+ .attr("x2", 5)
+ .attr("y2", 33);
+ },
+
+ _formatAnomaly(anomaly) {
+ return `${moment(anomaly.startTime).format(TABLE_DATE_FORMAT)}`;
+ },
+
+ _filterAnomalies(rows) {
+ return rows.filter(row => (row.startTime && row.endTime && !row.child));
+ },
+
+ _fetchTimeseries() {
+ const {
+ metricUrn,
+ displayRange,
+ selectedBaseline
+ } = this.getProperties('metricUrn', 'displayRange', 'selectedBaseline');
+ const granularity = '15_MINUTES';
+ const timezone = moment.tz.guess();
+
+ set(this, 'errorTimeseries', null);
+
+ const urlCurrent = `/rootcause/metric/timeseries?urn=${metricUrn}&start=${displayRange[0]}&end=${displayRange[1]}&offset=current&granularity=${granularity}&timezone=${timezone}`;
+ fetch(urlCurrent)
+ .then(checkStatus)
+ .then(res => {
+ this.setProperties({
+ timeseries: res,
+ isLoading: false
+ });
+ });
+
+ set(this, 'errorBaseline', null);
+
+ const urlBaseline = `/rootcause/metric/timeseries?urn=${metricUrn}&start=${displayRange[0]}&end=${displayRange[1]}&offset=${selectedBaseline}&granularity=${granularity}&timezone=${timezone}`;
+ fetch(urlBaseline)
+ .then(checkStatus)
+ .then(res => set(this, 'baseline', res));
+ },
+
+ _fetchAnomalies() {
+ set(this, 'errorAnomalies', null);
+
+ try {
+ const content = get(this, 'alertYaml');
+ this.get('_getAnomalyMapping').perform(content)
+ .then(results => {
+ this.setProperties({
+ anomalyMapping: results.anomalyMapping,
+ anomalies: results.anomalies,
+ isLoading: false
+ });
+ this._fetchTimeseries();
+ });
+ } catch (error) {
+ set(this, 'isLoading', false);
+ throw new Error(`Unable to retrieve anomaly data. ${error}`);
+ }
+ },
+
actions: {
/**
* Sets the new custom date range for anomaly coverage
@@ -207,7 +495,57 @@ export default Component.extend({
const endDate = moment(end).valueOf();
//Update the time range option selected
set(this, 'analysisRange', [startDate, endDate]);
- set(this, 'duration', duration)
+ set(this, 'duration', duration);
+ },
+
+ /**
+ * triggered by preview button
+ */
+ getPreview() {
+ this.setProperties({
+ isLoading: true,
+ showPreview: true
+ });
+ this._fetchAnomalies();
+ },
+
+ /**
+ * Handle display of selected baseline options
+ * @param {Object} clicked - the baseline selection
+ */
+ onBaselineOptionClick(clicked) {
+ const baselineOptions = get(this, 'baselineOptions');
+ const isValidSelection = !clicked.isActive;
+ let newOptions = baselineOptions.map((val) => {
+ return { name: val.name, isActive: false };
+ });
+
+ // Set active option
+ newOptions.find((val) => val.name === clicked.name).isActive = true;
+ this.set('baselineOptions', newOptions);
+
+ if(isValidSelection) {
+ set(this, 'selectedBaseline', clicked.name);
+ this._fetchTimeseries();
+ }
+ },
+
+ /**
+ * Handle sorting for each sortable table column
+ * @param {String} sortKey - stringified start date
+ */
+ toggleSortDirection(sortKey) {
+ const propName = 'sortColumn' + sortKey.capitalize() + 'Up' || '';
+
+ this.toggleProperty(propName);
+ if (this.get(propName)) {
+ this.set('selectedSortMode', sortKey + ':up');
+ } else {
+ this.set('selectedSortMode', sortKey + ':down');
+ }
+
+ //On sort, set table to first pagination page
+ this.set('currentPage', 1);
},
refreshPreview(){
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 ac752de..b5533d9 100644
--- a/thirdeye/thirdeye-frontend/app/pods/components/alert-details/template.hbs
+++ b/thirdeye/thirdeye-frontend/app/pods/components/alert-details/template.hbs
@@ -1,5 +1,218 @@
<div class="alert-details">
- {{#if isPendingData}}
+
+ {{#unless errorAnomalies}}
+ {{#if showPreview}}
+ {{#if isLoading}}
+ {{ember-spinner scale=0.5 rotate=10 speed='1.1' color='#3498DB'}}Please wait while we compile the data.
+ {{/if}}
+ {{range-pill-selectors
+ title="Showing"
+ uiDateFormat=pill.uiDateFormat
+ activeRangeEnd=pill.activeRangeEnd
+ activeRangeStart=pill.activeRangeStart
+ timeRangeOptions=pill.timeRangeOptions
+ timePickerIncrement=pill.timePickerIncrement
+ predefinedRanges=pill.predefinedRanges
+ selectAction=(action "onRangeSelection")
+ }}
+ <div class="te-horizontal-cards">
+ <h4 class="te-self-serve__block-title">
+ <label for="select-dimension" class="control-label te-label">
+ Alert Performance
+ <span>
+ <i class="glyphicon glyphicon-question-sign"></i>
+ {{#tooltip-on-element class="te-tooltip"}}
+ All estimated performance numbers are based on reviewed anomalies.
+ {{/tooltip-on-element}}
+ </span>
+ </label>
+ </h4>
+ <div class="te-horizontal-cards__container">
+ {{!-- Alert anomaly stats cards --}}
+ {{stats-cards stats=stats}}
+ </div>
+
+ {{#if repRunStatus}}
+ <p class="te-self-serve__block-subtext te-self-serve__block-subtext--normal">Replay in progress. Please check back later...</p>
+ {{/if}}
+ </div>
+ {{timeseries-chart
+ series=series
+ colorMapping=colorMapping
+ axis=axis
+ zoom=zoom
+ legend=legend
+ }}
+ {{#if anomalies}}
+ {{!-- Baseline type selector --}}
+ {{range-pill-selectors
+ title="Baseline"
+ timeRangeOptions=baselineOptions
+ selectAction=(action "onBaselineOptionClick")
+ }}
+ {{!-- Alert anomaly table --}}
+ <div class="te-block-container">
+ <table class="te-anomaly-table">
+ {{#if anomalies}}
+ <thead>
+ <tr class="te-anomaly-table__row te-anomaly-table__head">
+ <th class="te-anomaly-table__cell-head te-anomaly-table__cell-head--left">
+ <a class="te-anomaly-table__cell-link" {{action "toggleSortDirection" "number"}}>#
+ <i class="te-anomaly-table__icon glyphicon {{if sortColumnNumberUp "glyphicon-menu-down" "glyphicon-menu-up"}}"></i>
+ </a>
+ </th>
+ <th class="te-anomaly-table__cell-head te-anomaly-table__cell-head--left">
+ <a class="te-anomaly-table__cell-link" {{action "toggleSortDirection" "start"}}>
+ Start/Duration (PDT)
+ <i class="te-anomaly-table__icon glyphicon {{if sortColumnStartUp "glyphicon-menu-up" "glyphicon-menu-down"}}"></i>
+ </a>
+ </th>
+ {{#if alertHasDimensions}}
+ <th class="te-anomaly-table__cell-head te-anomaly-table__cell-head--fixed">Dimensions</th>
+ {{/if}}
+ <th class="te-anomaly-table__cell-head">
+ <a class="te-anomaly-table__cell-link" {{action "toggleSortDirection" "score"}}>
+ Severity Score
+ <i class="te-anomaly-table__icon glyphicon {{if sortColumnScoreUp "glyphicon-menu-up" "glyphicon-menu-down"}}"></i>
+ </a>
+ </th>
+ <th class="te-anomaly-table__cell-head">
+ <a class="te-anomaly-table__cell-link" {{action "toggleSortDirection" "change"}}>
+ Average Current / Average Predicted
+ <i class="te-anomaly-table__icon glyphicon {{if sortColumnChangeUp "glyphicon-menu-up" "glyphicon-menu-down"}}"></i>
+ </a>
+ </th>
+ {{#if notPreview}}
+ <th class="te-anomaly-table__cell-head">
+ <a class="te-anomaly-table__cell-link" {{action "toggleSortDirection" "resolution"}}>
+ Resolution
+ <i class="te-anomaly-table__icon glyphicon {{if sortColumnResolutionUp "glyphicon-menu-up" "glyphicon-menu-down"}}"></i>
+ </a>
+ </th>
+ <th class="te-anomaly-table__cell-head"></th>
+ {{/if}}
+ </tr>
+ </thead>
+ {{/if}}
+ <tbody>
+ {{#each tableAnomalies as |anomaly|}}
+ <tr class="te-anomaly-table__row">
+ <td class="te-anomaly-table__cell te-anomaly-table__cell--index">{{anomaly.index}}</td>
+ <td class="te-anomaly-table__cell">
+ <ul class="te-anomaly-table__list te-anomaly-table__list--left">
+ <li class="te-anomaly-table__list-item te-anomaly-table__list-item--stronger">
+ {{#if notPreview}}
+ <a target="_blank" class="te-anomaly-table__link" href="/app/#/rootcause?anomalyId={{anomaly.anomalyId}}">
+ {{anomaly.startDateStr}}
+ </a>
+ {{else}}
+ {{anomaly.startDateStr}}
+ {{/if}}
+ </li>
+ <li class="te-anomaly-table__list-item te-anomaly-table__list-item--lighter">{{anomaly.durationStr}}</li>
+ </ul>
+ </td>
+ {{#if alertHasDimensions}}
+ <td class="te-anomaly-table__cell">
+ <ul class="te-anomaly-table__list">
+ {{#each anomaly.dimensionList as |dimension|}}
+ <li class="te-anomaly-table__list-item te-anomaly-table__list-item--smaller" title="{{dimension.dimensionVal}}">
+ {{dimension.dimensionKey}}: <span class="stronger">{{dimension.dimensionVal}}</span>
+ </li>
+ {{else}}
+ -
+ {{/each}}
+ </ul>
+ </td>
+ {{/if}}
+ <td class="te-anomaly-table__cell">{{anomaly.severityScore}}</td>
+ <td class="te-anomaly-table__cell">
+ <ul class="te-anomaly-table__list">
+ <li>{{anomaly.shownCurrent}} / {{anomaly.shownBaseline}}</li>
+ <li class="te-anomaly-table__value-label te-anomaly-table__value-label--{{calculate-direction anomaly.shownChangeRate}}">
+ {{#if (not anomaly.isNullChangeRate)}}
+ ({{anomaly.shownChangeRate}}%)
+ {{else}}
+ (N/A)
+ {{/if}}
+ </li>
+ </ul>
+ </td>
+ {{#if notPreview}}
+ <td class="te-anomaly-table__cell">
+ {{#if renderStatusIcon}}
+ {{#if anomaly.showResponseSaved}}
+ <i class="te-anomaly-table__icon--status glyphicon glyphicon-ok-circle"></i>
+ {{/if}}
+ {{#if anomaly.showResponseFailed}}
+ <i class="te-anomaly-table__icon--status te-anomaly-table__icon--error glyphicon glyphicon-remove-circle"></i>
+ {{/if}}
+ {{/if}}
+
+ {{#if anomaly.isUserReported}}
+ <div class="te-anomaly-table__text te-anomaly-table__text--explore">User Reported</div>
+ <div class="te-anomaly-table__comment">
+ <i class="glyphicon glyphicon-th-list"></i>
+ {{#tooltip-on-element class="te-anomaly-table__tooltip"}}
+ {{anomaly.anomalyFeedbackComments}}
+ {{/tooltip-on-element}}
+ </div>
+ {{else}}
+ {{#power-select
+ triggerId=anomaly.anomalyId
+ triggerClass="te-anomaly-table__select"
+ options=responseOptions
+ searchEnabled=false
+ selected=(get labelMap anomaly.anomalyFeedback)
+ onchange=(action "onChangeAnomalyResponse" anomaly)
+ as |response|
+ }}
+ {{response}}
+ {{/power-select}}
+ {{/if}}
+ </td>
+ <td class="te-anomaly-table__cell te-anomaly-table__cell--feedback">
+ <div class="te-anomaly-table__link-wrapper">
+ {{#link-to 'rootcause' (query-params anomalyId=anomaly.anomalyId) target="_blank" class="te-anomaly-table__link"}}
+ Investigate
+ {{/link-to}}
+ </div>
+ </td>
+ {{/if}}
+ </tr>
+ {{/each}}
+ </tbody>
+ </table>
+ </div>
+
+ {{/if}}
+ {{else}}
+ {{#if disablePreviewButton}}
+ <p>Please define anomaly detection in YAML to enable preview.</p>
+ {{/if}}
+ {{/if}}
+ {{/unless}}
+ <p>{{errorAnomalies}}</p>
+ <div class="pull-right">
+ {{bs-button
+ defaultText=(if showPreview "Refresh Preview" "Get Preview")
+ disabled=disablePreviewButton
+ type="outline-primary"
+ buttonType="refresh"
+ onClick=(action "getPreview")
+ class="te-button te-button--cancel"
+ }}
+ </div>
+ {{yield}}
+
+
+
+
+
+
+
+
+ <!-- {{#if isPendingData}}
<div>
{{ember-spinner scale=0.5 rotate=10 speed='1.1' color='#3498DB'}}Please wait while we compiled the data.
</div>
@@ -31,6 +244,7 @@
{{!-- Alert anomaly stats cards --}}
{{stats-cards stats=stats}}
</div>
+
{{#if repRunStatus}}
<p class="te-self-serve__block-subtext te-self-serve__block-subtext--normal">Replay in progress. Please check back later...</p>
{{/if}}
@@ -42,5 +256,5 @@
</label>
{{/if}}
{{/if}}
- {{yield}}
+ {{yield}} -->
</div>
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/anomaly-graph/component.js b/thirdeye/thirdeye-frontend/app/pods/components/anomaly-graph/component.js
index 396d001..3ac6d93 100644
--- a/thirdeye/thirdeye-frontend/app/pods/components/anomaly-graph/component.js
+++ b/thirdeye/thirdeye-frontend/app/pods/components/anomaly-graph/component.js
@@ -26,7 +26,8 @@ const COLOR_MAPPING = {
export default Component.extend({
init() {
this._super(...arguments);
-
+ const subChartStart = this.get('subChartStart');
+ const subChartEnd = this.get('subChartEnd');
this.setProperties({
_subchartStart: Number(this.get('subchartStart')),
_subchartEnd: Number(this.get('subchartEnd'))
@@ -65,94 +66,6 @@ export default Component.extend({
.attr("y2", 33);
},
- buildAnomalyRegionSlider(start, end) {
- const {
- componentId,
- regionStart,
- regionEnd,
- _subchartStart: subchartStart,
- _subchartEnd: subchartEnd
- } = this.getProperties(
- 'componentId',
- 'regionStart',
- 'regionEnd',
- '_subchartStart',
- '_subchartEnd');
-
- start = start || subchartStart;
- end = end || subchartEnd;
-
- d3.select(`#${componentId} .anomaly-graph__region-slider`).remove();
- if (componentId !== 'main-graph') {return;}
-
- const focus = d3.select(`#${componentId}.c3-chart-component .c3-chart`);
- const { height, width } = d3.select(`#${componentId} .c3-chart .c3-event-rects`).node().getBoundingClientRect();
- const dates = this.get('primaryMetric.timeBucketsCurrent');
- const min = start ? moment(start).valueOf() : d3.min(dates);
- const max = end ? moment(end).valueOf() : d3.max(dates);
-
- const x = d3.time.scale()
- .domain([min, max])
- .range([0, width]);
-
- const brush = d3.svg.brush()
- .on("brushend", brushed.bind(this))
- .x(x)
- .extent([+regionStart, +regionEnd]);
-
- function brushed() {
- const e = brush.extent();
- const [ start, end ] = e;
-
- const regionStart = moment(start).valueOf();
- const regionEnd = moment(end).valueOf();
- const subchartStart = this.get('_subchartStart');
- const subchartEnd = this.get('_subchartEnd');
-
- this.setProperties({
- regionStart,
- regionEnd,
- subchartStart,
- subchartEnd
- });
- }
-
- focus.append('g')
- .attr('class', 'anomaly-graph__region-slider x brush')
- .call(brush)
- .selectAll('rect')
- .attr('y', 0)
- .attr('height', height);
-
- const resizeButton = focus.selectAll('.resize');
- const sliderHeight = height/2;
- resizeButton.append('circle')
- .attr('cx', 0)
- .attr('cy', sliderHeight)
- .attr('r', 10)
- .attr('fill', '#E55800');
- resizeButton.append('line')
- .attr('class', 'anomaly-graph__slider-line')
- .attr("x1", 0)
- .attr("y1", sliderHeight - 3)
- .attr("x2", 0)
- .attr("y2", sliderHeight + 3);
-
- resizeButton.append('line')
- .attr('class', 'anomaly-graph__slider-line')
- .attr("x1", -5)
- .attr("y1", sliderHeight - 3)
- .attr("x2", -5)
- .attr("y2", sliderHeight + 3);
-
- resizeButton.append('line')
- .attr('class', 'anomaly-graph__slider-line')
- .attr("x1", 5)
- .attr("y1", sliderHeight - 3)
- .attr("x2", 5)
- .attr("y2", sliderHeight + 3);
- },
-
// Builds the Current/Expected legend for the graph
buildCustomLegend() {
const componentId = this.get('componentId');
@@ -213,8 +126,6 @@ export default Component.extend({
later(() => {
this.buildSliderButton();
- // hiding this feature until fully fleshed out
- // this.buildAnomalyRegionSlider();
this.buildCustomLegend().then(() => {
this.notifyPhantomJS();
});
@@ -529,8 +440,6 @@ export default Component.extend({
onSubchartBrush && onSubchartBrush(dates);
}
- // hiding this feature until fully fleshed out
- // this.buildAnomalyRegionSlider(start, end);
},
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 1ef8267..fe6e51b 100644
--- a/thirdeye/thirdeye-frontend/app/pods/components/yaml-editor/component.js
+++ b/thirdeye/thirdeye-frontend/app/pods/components/yaml-editor/component.js
@@ -35,6 +35,7 @@ import {
import { inject as service } from '@ember/service';
import { task } from 'ember-concurrency';
+
export default Component.extend({
classNames: ['yaml-editor'],
notifications: service('toast'),
@@ -58,7 +59,8 @@ export default Component.extend({
YAMLField: '',
currentYamlAlertOriginal: '',
currentYamlSettingsOriginal: '',
- toggleCollapsed: false,
+ toggleCollapsed: true,
+
init() {
@@ -68,6 +70,7 @@ export default Component.extend({
set(this, 'currentYamlSettingsOriginal', get(this, 'detectionSettingsYaml') || get(this, 'yamlAlertSettings'));
}
},
+
/**
* sets Yaml value displayed to contents of alertYaml or yamlAlertProps
* @method currentYamlAlert
@@ -239,10 +242,6 @@ export default Component.extend({
},
actions: {
- getPreview(){
- set(this, 'alertYaml', get(this, 'currentYamlAlert')),
- this.toggleProperty('toggleCollapsed');
- },
/**
* resets given yaml field to default value for creation mode and server value for edit mode
*/
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 fcf4f1d..56bb47f 100644
--- a/thirdeye/thirdeye-frontend/app/pods/components/yaml-editor/template.hbs
+++ b/thirdeye/thirdeye-frontend/app/pods/components/yaml-editor/template.hbs
@@ -38,10 +38,10 @@
}}
</div>
<div class="col-xs-12">
- {{#bs-accordion onChange=(action 'getPreview') as |acc|}}
+ {{#bs-accordion onChange=(action (mut toggleCollapsed)) as |acc|}}
{{#acc.item value=preview as |aitem|}}
{{#aitem.title}}
- <section class="dashboard-container__title">Preview alert {{#unless disableYamlSave}} / Alert configuration has changed.{{/unless}}
+ <section class="dashboard-container__title">Preview alert
<span class="pull-right"><i class="glyphicon glyphicon-menu-{{if toggleCollapsed "down" "up"}}"></i></span>
</section>
{{/aitem.title}}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org
For additional commands, e-mail: commits-help@pinot.apache.org