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 <harleyy...@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-unsubscr...@pinot.apache.org For additional commands, e-mail: commits-h...@pinot.apache.org