You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pinot.apache.org by xh...@apache.org on 2020/05/29 20:36:18 UTC
[incubator-pinot] branch master updated: [TE] frontend -
harleyjj/components - remove dead components (#5466)
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 2807584 [TE] frontend - harleyjj/components - remove dead components (#5466)
2807584 is described below
commit 2807584edfefc710d7c084747a0a509526205587
Author: Harley Jackson <hj...@linkedin.com>
AuthorDate: Fri May 29 13:36:04 2020 -0700
[TE] frontend - harleyjj/components - remove dead components (#5466)
---
.../app/pods/components/alert-details/template.hbs | 1 +
.../components/alert-report-modal/template.hbs | 6 +
.../app/pods/components/anomaly-graph/component.js | 764 ---------------------
.../app/pods/components/anomaly-graph/template.hbs | 120 ----
.../app/pods/components/anomaly-id/component.js | 37 -
.../app/pods/components/anomaly-id/template.hbs | 15 -
.../components/anomaly-stats-block/component.js | 21 -
.../components/anomaly-stats-block/template.hbs | 53 --
.../pods/components/dimension-heatmap/component.js | 199 ------
.../pods/components/dimension-heatmap/template.hbs | 16 -
.../pods/components/dimension-summary/component.js | 5 -
.../pods/components/dimension-summary/template.hbs | 16 -
.../app/pods/components/events-header/component.js | 86 ---
.../app/pods/components/events-header/template.hbs | 26 -
.../app/pods/components/events-table/component.js | 134 ----
.../app/pods/components/events-table/template.hbs | 16 -
.../modals/manage-groups-modal/component.js | 716 -------------------
.../modals/manage-groups-modal/template.hbs | 239 -------
.../components/performance-tooltip/component.js | 5 -
.../components/performance-tooltip/template.hbs | 17 -
.../self-serve-alert-yaml-details/component.js | 2 +-
.../pods/components/self-serve-graph/component.js | 114 ---
.../pods/components/self-serve-graph/template.hbs | 38 -
.../pods/components/thirdeye-chart/component.js | 8 -
.../pods/components/thirdeye-chart/template.hbs | 1 -
.../pods/custom/anomalies-table/rule/template.hbs | 2 +-
.../app/pods/example/controller.js | 10 -
.../thirdeye-frontend/app/pods/example/route.js | 32 -
.../app/pods/example/template.hbs | 23 -
.../pods/manage/alerts/performance/controller.js | 101 ---
.../app/pods/manage/alerts/performance/route.js | 348 ----------
.../pods/manage/alerts/performance/template.hbs | 140 ----
.../app/pods/self-serve/create-alert/template.hbs | 15 -
thirdeye/thirdeye-frontend/app/router.js | 2 +-
thirdeye/thirdeye-frontend/app/styles/app.scss | 4 -
.../app/styles/components/anomaly-graph.scss | 151 ----
.../app/styles/components/anomaly-id.scss | 32 -
.../app/styles/components/dimension-heatmap.scss | 69 --
.../app/styles/components/dimension-summary.scss | 30 -
.../app/styles/pods/manage/alerts-performance.scss | 20 -
.../components/anomaly-graph/component-test.js | 23 -
.../pods/components/anomaly-id/component-test.js | 55 --
.../components/thirdeye-chart/component-test.js | 26 -
43 files changed, 10 insertions(+), 3728 deletions(-)
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 b622e43..9760ad6 100644
--- a/thirdeye/thirdeye-frontend/app/pods/components/alert-details/template.hbs
+++ b/thirdeye/thirdeye-frontend/app/pods/components/alert-details/template.hbs
@@ -247,6 +247,7 @@
isMetricDataLoading=isMetricDataLoading
isMetricDataInvalid=isMetricDataInvalid
inputAction=(action "onInputMissingAnomaly")
+ isReportFailure=isReportFailure
}}
{{else}}
{{ember-spinner}}
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/alert-report-modal/template.hbs b/thirdeye/thirdeye-frontend/app/pods/components/alert-report-modal/template.hbs
index 8bb3444..08e85fb 100644
--- a/thirdeye/thirdeye-frontend/app/pods/components/alert-report-modal/template.hbs
+++ b/thirdeye/thirdeye-frontend/app/pods/components/alert-report-modal/template.hbs
@@ -47,6 +47,12 @@
{{/if}}
</fieldset>
+ {{#if isReportFailure}}
+ {{#bs-alert type="danger" class="te-form__banner te-form__banner--failure"}}
+ <strong>Error:</strong> Failed to save reported anomaly. Did you select dates and times?
+ {{/bs-alert}}
+ {{/if}}
+
<fieldset class="te-form__section row">
<div class="form-group col-xs-6">
<legend class="te-report-title">Mark the Anomaly Region</legend>
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/anomaly-graph/component.js b/thirdeye/thirdeye-frontend/app/pods/components/anomaly-graph/component.js
deleted file mode 100644
index 3ac6d93..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/components/anomaly-graph/component.js
+++ /dev/null
@@ -1,764 +0,0 @@
-import $ from 'jquery';
-import { set, computed } from '@ember/object';
-import { later } from '@ember/runloop';
-import Component from '@ember/component';
-import moment from 'moment';
-import d3 from 'd3';
-import { humanizeFloat } from 'thirdeye-frontend/utils/utils';
-
-const COLOR_MAPPING = {
- blue: '#33AADA',
- orange: '#EF7E37',
- teal: '#17AFB8',
- purple: '#9896F2',
- red: '#FF6C70',
- green: '#6BAF49',
- pink: '#FF61b6',
- light_blue: '#65C3E8',
- light_orange: '#F6A16C',
- light_teal: '#68C5CD',
- light_purple: '#B2B0FA',
- light_red: '#FF999A',
- light_green: '#91C475',
- light_pink: '#FF91CF'
-};
-
-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'))
- });
- },
-
- // Helper function that builds the subchart region buttons
- buildSliderButton() {
- const componentId = this.get('componentId');
- const resizeButtons = d3.select(`#${componentId}.c3-chart-component`).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);
- },
-
- // Builds the Current/Expected legend for the graph
- buildCustomLegend() {
- const componentId = this.get('componentId');
- const chart = d3.select(`#${componentId}.c3-chart-component`);
- const legendText = this.get('legendText');
-
- const {
- solid = { text: 'current', color: 'blue' }
- } = legendText;
-
- chart.insert('div', '.chart').attr('class', 'anomaly-graph__legend').selectAll('span')
- .data([solid])
- .enter().append('svg')
- .attr('class', 'anomaly-graph__legend-item')
- .attr('width', 80)
- .attr('height', 20)
- .attr('data-id', function (el) { return el.text; })
- .each(function (el) {
- const element = d3.select(this);
-
- element.append('text')
- .attr('x', 35)
- .attr('y', 12)
- .text(el.text);
-
- element.append('line')
- .attr('class', function(el) {
- return `anomaly-graph__legend-line anomaly-graph__legend-line--${el.color}`;
- })
- .attr('x1', 0)
- .attr('y1', 10)
- .attr('x2', 30)
- .attr('y2', 10)
- .attr('stroke-dasharray', () => {
- const dasharrayNum = 'none';
- return dasharrayNum;
- });
- });
- // Necessary so that it is 'thenable'
- return Promise.resolve();
- },
-
- willDestroyElement() {
- this._super(...arguments);
-
- const subchartStart = this.get('_subchartStart');
- const subchartEnd = this.get('_subchartEnd');
-
-
- this.setProperties({
- subchartStart,
- subchartEnd
- });
- },
-
- didRender(){
- this._super(...arguments);
-
- later(() => {
- this.buildSliderButton();
- this.buildCustomLegend().then(() => {
- this.notifyPhantomJS();
- });
- });
- },
-
- /**
- * Checks if the page is being viewed from phantomJS
- * and notifies it that the page is rendered and ready
- * for a screenshot
- */
- notifyPhantomJS() {
- if (typeof window.callPhantom === 'function') {
- window.callPhantom({message: 'ready'});
- }
- },
-
- /**
- * Maps each metric and event to a color / class
- */
- didReceiveAttrs() {
- this._super(...arguments);
-
- const colors = {};
- const primaryMetric = this.get('primaryMetric');
- const relatedMetric = this.get('relatedMetrics') || [];
- const selectedMetrics = this.get('selectedMetrics') || [];
- const selectedDimensions = this.get('selectedDimensions') || [];
- const events = this.get('holidayEvents') || [];
-
- // This check is necessary so that it is only set once
- if (primaryMetric.isSelected === undefined) {
- set(primaryMetric, 'isSelected', true);
- }
-
- const data = [
- primaryMetric,
- ...relatedMetric,
- ...selectedMetrics,
- ...selectedDimensions
- ];
-
- data.forEach((datum) => {
- const name = datum.metricName || datum.name;
- const { color } = datum;
- colors[`${name}-current`] = COLOR_MAPPING[color || 'blue'];
- colors[`${name}-expected`] = COLOR_MAPPING[color || 'orange'];
- });
-
- events.forEach((event) => {
- const { displayColor = 'blue'} = event;
- colors[event.displayLabel] = COLOR_MAPPING[displayColor];
- });
-
- this.set('colors', colors);
- },
-
- tagName: 'div',
- classNames: ['anomaly-graph'],
- primaryMetric: {},
- relatedMetrics: [],
- selectedMetrics: [],
- dimensions: [],
- selectedDimensions: [],
-
- showGraphLegend: false,
- colors: {},
- showSubChart: false,
- subchartStart: null,
- subchartEnd: null,
-
- _subchartStart: 0,
- _subchartEnd: 0,
-
- analysisStart: 0,
- analysisEnd: 0,
-
- showLegend: false,
- // contains copy for the legend
- // currently supports 'dotted' and 'solid'
- legendText: {},
-
- showTitle: false,
- height: 0,
- componentId: 'main-graph',
-
- initStart: null,
- initEnd: null,
- anomalyRegionStart: 0,
- anomalyRegionEnd: 0,
- regionStart: 0,
- regionEnd: 0,
-
- showEvents: false,
- showDimensions: false,
- showMetrics: false,
- events: [],
-
- enableZoom: false,
-
- // padding for the anomaly graph (optional)
- padding: null,
-
- // dd for primary metric
- primaryMetricId: computed('componentId', function() {
- return this.get('componentId') + '-primary-metric-';
- }),
-
- // id for related metrics
- relatedMetricId: computed('componentId', function() {
- return this.get('componentId') + '-related-metric-';
- }),
-
- // id for dimension
- dimensionId: computed('componentId', function() {
- return this.get('componentId') + '-dimension-';
- }),
-
- // filtered events for graph
- holidayEvents: computed('events', function() {
- return this.get('events');
- // const events = this.get('events');
- // const hiddenEvents = [];
- // return events.filter((event) => {
- // return !hiddenEvents.includes(event.eventType);
- // });
- }),
-
- holidayEventsColumn: computed(
- 'holidayEvents',
- function() {
- const events = this.get('holidayEvents');
-
- return events.map((event) => {
- const {
- // start,
- // end,
- displayScore,
- displayLabel
- } = event;
-
- // const scores = (!end || start === end)
- // ? [score, score]
- // : [score];
- return [displayLabel, displayScore];
- });
- }
- ),
-
- holidayEventsDatesColumn: computed(
- 'holidayEvents',
- function() {
- const holidays = this.get('holidayEvents');
-
- return holidays.map((holiday) => {
- const { displayStart, displayEnd } = holiday;
-
- const start = displayStart;
- const end = displayEnd;
-
- const date = !end ? [end] : [start];
-
- return [`${holiday.displayLabel}-date`, date];
- });
- }
- ),
-
- /**
- * Graph Legend config
- */
- legend: computed('showGraphLegend', function() {
- return {
- position: 'inset',
- show: false
- };
- }),
-
- /**
- * Graph Zoom config
- */
- zoom: computed(
- 'onSubchartChange',
- 'enableZoom',
- function() {
- const onSubchartBrush = this.get('onSubchartChange');
- return {
- enabled: this.get('enableZoom'),
- onzoomend: onSubchartBrush,
- rescale: true
- };
- }
- ),
-
- /**
- * Graph Point Config
- */
- point: computed(
- 'showGraphLegend',
- function() {
- return {
- show: true,
- r: function(data) {
- const { id } = data;
- if (id.includes('current') || id.includes('expected')) {
- return 0;
- }
-
- return 5;
- }
- };
- }
- ),
-
- /**
- * Graph axis config
- */
- axis: computed(
- 'chartDates',
- 'primaryMetric',
- 'subchartStart',
- 'subchartEnd',
- 'showEvents',
- 'minDate',
- 'maxDate',
- function() {
- const [ _, ...dates ] = this.get('chartDates');
- const subchartStart = this.get('_subchartStart')
- || this.get('subchartStart');
- const subchartEnd = this.get('_subchartEnd')
- || this.get('subchartEnd');
- const min = dates.get('firstObject');
- const max = dates.get('lastObject');
- const extentStart = Math.max(min, moment(subchartStart).valueOf());
- const extentEnd = Math.min(max, moment(subchartEnd).valueOf());
-
- const extentRange = (subchartStart && subchartEnd)
- ? [extentStart, extentEnd]
- : null;
-
- return {
- y: {
- show: true,
- // min: 0,
- tick: {
- format: function(d){return humanizeFloat(d);}
- }
- },
- y2: {
- show: false,
- label: 'events score',
- min: 0,
- max: 1,
- padding: {
- bottom: 0
- },
- tick: {
- values: [0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1]
- }
- },
- x: {
- type: 'timeseries',
- show: true,
- padding: 0,
- min: this.get('minDate') || min,
- max: this.get('maxDate') || max,
- tick: {
- fit: false
- // format: function (x) { return new Date(x).toString(); }
- },
- extent: extentRange
- }
- };
- }
- ),
-
- /**
- * Graph Subchart Config
- */
- subchart: computed(
- 'showLegend',
- 'showSubchart',
- 'showGraphLegend',
- function() {
- const showSubchart = this.get('showGraphLegend') || this.get('showSubchart');
- return {
- show: showSubchart,
- onbrush: this.get('onbrush').bind(this)
- };
- }
- ),
-
- /**
- * Callback that handles the anomaly brush event
- */
- onbrush: function(dates) {
- const [ start, end ] = dates;
- const onSubchartBrush = this.get('onSubchartChange');
- const [ , ...graphDates ] = this.get('chartDates');
- const min = graphDates.get('firstObject');
- const max = graphDates.get('lastObject');
-
- if ((moment(start).valueOf() == min) && (moment(end).valueOf() == max)) {
- this.setProperties({
- _subchartStart: 0,
- _subchartEnd: 0
- });
- } else {
- this.setProperties({
- _subchartStart: moment(start).valueOf(),
- _subchartEnd: moment(end).valueOf()
- });
-
- onSubchartBrush && onSubchartBrush(dates);
- }
-
- },
-
- /**
- * Graph Height Config
- */
- size: computed(
- 'showLegend',
- 'height',
- function() {
- const height = this.get('height') || 400;
- return {
- height
- };
- }
- ),
-
- /**
- * Data massages primary Metric into a Column
- */
- primaryMetricColumn: computed(
- 'primaryMetric',
- 'primaryMetric.isSelected',
- function() {
- const primaryMetric = this.get('primaryMetric');
-
- // Return data only when it's selected
- if (primaryMetric.isSelected) {
- const { currentValues } = primaryMetric.subDimensionContributionMap['All'];
- return [
- [`${primaryMetric.metricName}-current`, ...currentValues]
- ];
- }
- return [
- [`${primaryMetric.metricName}-current`]
- ];
- }
- ),
-
- /**
- * Data massages relatedMetrics into Columns
- */
- selectedMetricsColumn: computed(
- 'selectedMetrics',
- 'selectedMetrics.@each',
- function() {
- const columns = [];
- const selectedMetrics = this.get('selectedMetrics') || [];
-
- selectedMetrics.forEach((metric) => {
- if (!metric) { return; }
-
- const { currentValues } = metric.subDimensionContributionMap['All'];
- columns.push([`${metric.metricName}-current`, ...currentValues]);
- });
- return columns;
- }
- ),
-
- /**
- * Data massages dimensions into Columns
- */
- selectedDimensionsColumn: computed(
- 'selectedDimensions',
- function() {
- const columns = [];
- const selectedDimensions = this.get('selectedDimensions') || [];
-
- selectedDimensions.forEach((dimension) => {
- const { currentValues } = dimension;
- columns.push([`${dimension.name}-current`, ...currentValues]);
- });
- return columns;
- }
- ),
- /**
- * Derives x axis from the primary metric
- */
- chartDates: computed(
- 'primaryMetric.timeBucketsCurrent',
- function() {
- return ['date', ...this.get('primaryMetric.timeBucketsCurrent')];
- }
- ),
-
- /**
- * Aggregates data for chart
- */
- data: computed(
- 'primaryMetricColumn',
- 'selectedMetricsColumn',
- 'selectedDimensionsColumn',
- 'holidayEventsColumn',
- 'holidayEventsDatesColumn',
- 'chartDates',
- 'colors',
- 'onEventClick',
- function() {
- const {
- primaryMetricColumn = [],
- selectedMetricsColumn = [],
- selectedDimensionsColumn = [],
- holidayEventsColumn = [],
- holidayEventsDatesColumn = []
- } = this.getProperties(
- 'primaryMetricColumn',
- 'selectedMetricsColumn',
- 'selectedDimensionsColumn',
- 'holidayEventsDatesColumn',
- 'holidayEventsColumn');
-
- const columns = [
- ...primaryMetricColumn,
- ...selectedMetricsColumn,
- ...selectedDimensionsColumn
- ];
-
- const holidayAxis = holidayEventsColumn
- .map(column => column[0])
- .reduce((hash, columnName) => {
- hash[columnName] = `${columnName}-date`;
-
- return hash;
- }, {});
-
- const holidayAxes = holidayEventsColumn
- .map(column => column[0])
- .reduce((hash, columnName) => {
- hash[columnName] = 'y2';
-
- return hash;
- }, {});
-
- const xAxis = columns
- .map(column => column[0])
- .reduce((hash, columnName) => {
- hash[columnName] = 'date';
-
- return hash;
- }, {});
-
- return {
- xs: Object.assign({}, xAxis, holidayAxis),
- axes: Object.assign({ y2: 'y2'}, holidayAxes),
- columns: [
- this.get('chartDates'),
- ...columns,
- ...holidayEventsColumn,
- ...holidayEventsDatesColumn
- ],
- type: 'line',
- xFormat: '%Y-%m-%d %H:%M',
- colors: this.get('colors'),
- onclick: this.get('onEventClick')
- };
- }
- ),
-
- /**
- * Data massages Primary Metric's region
- * and assigns color class
- */
- primaryRegions: computed('primaryMetric', function() {
- const primaryMetric = this.get('primaryMetric') || {};
- const {
- regions,
- color = 'orange'
- } = primaryMetric;
-
- if (!regions) { return []; }
-
- return regions.map((region) => {
- return {
- axis: 'x',
- start: region.start,
- end: region.end,
- tick: {
- format: '%m %d %Y'
- },
- class: `c3-region--${color}`
- };
-
- });
- }),
-
- /**
- * Data massages the main anomaly region
- */
- anomalyRegion: computed(
- 'analysisStart',
- 'analysisEnd',
- function() {
- const start = this.get('analysisStart');
- const end = this.get('analysisEnd');
-
- if (!(start && end)) { return []; }
-
- const region = {
- axis: 'x',
- start: Number(start),
- end: Number(end),
- tick: {
- format: '%m %d %Y'
- },
- class: `c3-region--dark-orange`
- };
-
- return [region];
- }
- ),
-
- /**
- * Data massages Primary Metric's region
- * and assigns color class
- */
- relatedRegions: computed(
- 'selectedMetrics',
- 'selectedMetrics.@each',
- function() {
- const selectedMetrics = this.get('selectedMetrics') || [];
- const regions = [];
- selectedMetrics.forEach((metric)=> {
-
- if (!metric.regions) { return; }
-
- const metricRegions = metric.regions.map((region) => {
- return {
- axis: 'x',
- start: region.start,
- end: region.end,
- tick: {
- format: '%m %d %Y'
- },
- class: `c3-region--${metric.color}`
- };
- });
- regions.push(...metricRegions);
- });
-
- return regions;
- }
- ),
-
- /**
- * Config for tooltip
- */
- tooltip: {
- format: {
- title: function(d) {
- return moment(d).format('MM/DD hh:mm a');
- },
- value: function(val, ratio, id) {
- const isMetric = ['current', 'expected'].some((category) => {
- return id.includes(category);
- });
-
- if (isMetric) {
- return d3.format('.3s')(val);
- } else {
- // do not return values if data point is an event
-
- // NOTE: eventWeightMapping code removed on rca v1 deprecation
-
- return '';
- }
- }
- }
- },
-
-
- /**
- * Aggregates chart regions
- */
- regions: computed(
- 'primaryRegions',
- 'relatedRegions',
- 'anomalyRegion',
- function() {
- return [
- ...this.get('primaryRegions'),
- ...this.get('relatedRegions'),
- ...this.get('anomalyRegion')
- ];
- }
- ),
-
- actions: {
- /**
- * Shows/Hides the primary metric
- */
- onPrimaryMetricToggle() {
- if (!this.attrs.onPrimaryClick) {
- this.toggleProperty('primaryMetric.isSelected');
- } else {
- this.attrs.onPrimaryClick(...arguments);
- }
- },
-
- /**
- * Handles graph item selection
- */
- onSelection() {
- this.attrs.onSelection(...arguments);
- },
-
- /**
- * Shows/Hides the graph legend
- */
- onToggle() {
- this.toggleProperty('showGraphLegend');
- },
-
- /**
- * Scrolls to the appropriate tab on click
- */
- scrollToSection() {
- later(() => {
- $('#root-cause-analysis').get(0).scrollIntoView();
- });
- }
- }
-});
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/anomaly-graph/template.hbs b/thirdeye/thirdeye-frontend/app/pods/components/anomaly-graph/template.hbs
deleted file mode 100644
index ee68870..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/components/anomaly-graph/template.hbs
+++ /dev/null
@@ -1,120 +0,0 @@
-{{#if showLegend}}
- <section class="anomaly-graph__left-panel">
- <div class="anomaly_graph__filters">
- <h5 class="legend-title">Primary Metric</h5>
- <ul class="anomaly-graph__filter-group">
- <li class="anomaly-graph__filter-item">
- {{input
- type="checkbox"
- id=(concat primaryMetricId primaryMetric.metricId)
- change=(action "onPrimaryMetricToggle")
- checked=primaryMetric.isSelected}}
- <label class="anomaly-graph__filter-label anomaly-graph__filter-label--{{primaryMetric.color}}" for="{{concat primaryMetricId primaryMetric.metricId}}" title={{primaryMetric.metricName}}> {{primaryMetric.metricName}} </label>
- </li>
- </ul>
-
- {{#if showEvents}}
- <h5 class="legend-title">Related Events ({{holidayEvents.length}})
- <a class="pull-right legend-cta" {{action (toggle "isEventsHidden" this)}}>
- <i class="glyphicon {{if isEventsHidden "glyphicon-chevron-down" "glyphicon-chevron-up"}}"></i>
- </a>
- </h5>
- <ul class="anomaly-graph__filter-group {{if isEventsHidden "anomaly-graph__filter-group--hidden"}}">
-
- {{#each holidayEvents as |event|}}
- <li class="anomaly-graph__filter-item">
- {{input
- type="checkbox"
- change=(action "onSelection" event.urn)
- id=(concat relatedMetricId event.urn)
- checked=event.isSelected}}
- <label class="anomaly-graph__filter-label anomaly-graph__filter-label--{{event.color}}" for="{{concat relatedMetricId event.urn}}" title={{event.label}}> {{event.label}} </label>
- </li>
- {{else}}
- No Related Events.
- {{#if (eq componentId "main-graph")}}
- {{#link-to 'rca.details.events' class="thirdeye-link"}} <a {{action "scrollToSection" bubbles=true}}> (Find an event) </a>{{/link-to}}
- {{/if}}
- {{/each}}
-
- </ul>
- {{/if}}
-
- {{#if showDimensions}}
- <h5 class="legend-title">Dimensions ({{dimensions.length}})
- <a class="pull-right legend-cta" {{action (toggle "isDimensionsHidden" this)}}>
- <i class="glyphicon {{if isDimensionsHidden "glyphicon-chevron-down" "glyphicon-chevron-up"}}"></i>
- </a>
- </h5>
- <ul class="anomaly-graph__filter-group {{if isDimensionsHidden "anomaly-graph__filter-group--hidden"}}">
- {{#each dimensions as |subdimension index|}}
- <li class="anomaly-graph__filter-item">
- {{input
- type="checkbox"
- id=(concat dimensionId index)
- change=(action "onSelection" subdimension)
- checked=subdimension.isSelected}}
- <label class="anomaly-graph__filter-label anomaly-graph__filter-label--{{subdimension.color}}" for="{{concat dimensionId index}}" title={{subdimension.name}}> {{subdimension.name}} </label>
- </li>
- {{else}}
- No Dimensions.
- {{#if (eq componentId "main-graph")}}
- {{#link-to 'rca.details.dimensions' class="thirdeye-link"}} <a {{action "scrollToSection" bubbles=true}}> (Find a dimension) </a>{{/link-to}}
- {{/if}}
- {{/each}}
- </ul>
- {{/if}}
-
- {{#if showMetrics}}
- <h5 class="legend-title">Related Metrics ({{relatedMetrics.length}})
- <a class="pull-right legend-cta" {{action (toggle "isMetricsHidden" this)}}>
- <i class="glyphicon {{if isMetricsHidden "glyphicon-chevron-down" "glyphicon-chevron-up"}}"></i>
- </a>
- </h5>
- <ul class="anomaly-graph__filter-group {{if isMetricsHidden "anomaly-graph__filter-group--hidden"}}">
- {{#each relatedMetrics as |metric index|}}
- <li class="anomaly-graph__filter-item">
- {{input
- type="checkbox"
- change=(action "onSelection" metric checked)
- id=(concat relatedMetricId index)
- checked=metric.isSelected
- }}
- <label class="anomaly-graph__filter-label anomaly-graph__filter-label--{{metric.color}}" for="{{concat relatedMetricId index}}" title={{metric.metricName}}> {{metric.metricName}} </label>
- </li>
- {{else}}
- No Related Metrics.
- {{#if (eq componentId "main-graph")}}
- {{#link-to 'rca.details.metrics' class="thirdeye-link"}} <a {{action "scrollToSection" bubbles=true}}> (Find a metric) </a>{{/link-to}}
- {{/if}}
- {{/each}}
- </ul>
- {{/if}}
-
-
- </div>
- </section>
-{{/if}}
-
-<section class="anomaly-graph__right-panel">
- {{#if showTitle}}
- <h3 class="anomaly-graph__title">{{primaryMetric.metricName}}</h3>
- {{/if}}
- {{#if isLoading}}
- {{ember-spinner}}
- {{/if}}
- {{thirdeye-chart
- data=data
- axis=axis
- legend=legend
- regions=regions
- size=size
- color=color
- zoom=zoom
- point=point
- id=componentId
- subchart=subchart
- tooltip=tooltip
- padding=padding
- }}
-</section>
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/anomaly-id/component.js b/thirdeye/thirdeye-frontend/app/pods/components/anomaly-id/component.js
deleted file mode 100644
index a78babd..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/components/anomaly-id/component.js
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * Handles display of anomaly ID and associated metadata
- * @module components/anomaly-id
- * @exports anomaly-id
- */
-import { computed } from '@ember/object';
-import Component from '@ember/component';
-import floatToPercent from 'thirdeye-frontend/utils/float-to-percent';
-
-export default Component.extend({
- /**
- * Component's tag name
- */
- tagName: 'ul',
-
- /**
- * List of associated classes
- */
- classNames: ['anomaly-id'],
-
- /**
- * Calculate the difference between the start value and end value for the currently loaded anomaly.
- * Note: data frequency is 5min, hourly, or daily
- * @method anomalyChangeRate
- * @return {Number} - total % change from baseline
- */
- anomalyChangeRate: computed('anomaly.{current,baseline}', function() {
- const currentValue = this.get('anomaly.current') || 0;
- const baselineValue = this.get('anomaly.baseline') || 0;
-
- if (baselineValue !== 0) {
- return floatToPercent((currentValue - baselineValue) / baselineValue);
- } else {
- return 0;
- }
- })
-});
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/anomaly-id/template.hbs b/thirdeye/thirdeye-frontend/app/pods/components/anomaly-id/template.hbs
deleted file mode 100644
index b6bb853..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/components/anomaly-id/template.hbs
+++ /dev/null
@@ -1,15 +0,0 @@
-<div class="container">
- <li class="anomaly-id__item anomaly-id__item--title">
- <span class="anomaly-id__title">Anomaly ID #</span>
- <span class="anomaly-id__id">{{anomaly.anomalyIds}}</span>
- </li>
- <li class="anomaly-id__item">
- <span class="anomaly-id__subtitle">Metric:</span>
- <span class="anomaly-id__name">{{anomaly.anomalyFunctionName}}</span>
- </li>
- <li class="anomaly-id__item anomaly-id__item--value">
- <span class="anomaly-id__total">{{anomaly.current}}</span>
- <span class="anomaly-id__percent">({{anomalyChangeRate}}%)</span>
- <span class="anomaly-id__text">WoW</span>
- </li>
-</div>
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/anomaly-stats-block/component.js b/thirdeye/thirdeye-frontend/app/pods/components/anomaly-stats-block/component.js
deleted file mode 100644
index a37be11..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/components/anomaly-stats-block/component.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * Anomaly-Stats-Block Component
- * Displays a row of cards, each of which contains stats, depending on the anomalyStats that are passed to the component
- * @module components/anomaly-stats-block
- * @property {boolean} isTunePreviewActive - [optional] flag for whether tuning preview is active
- * @property {string} displayMode - [optional] mode of display (i.e. "explore")
- * @property {object[]} anomalyStats - [required] array of stats object that specify what to display on each card
- *
- * @example
- * {{anomaly-stats-block
- * isTunePreviewActive=isTunePreviewActive
- * displayMode="explore"
- * anomalyStats=anomalyStats}}
- *
- * @exports anomaly-stats-block
- */
-import Component from '@ember/component';
-
-export default Component.extend({
- classNames: ['te-horizontal-cards__container']
-});
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/anomaly-stats-block/template.hbs b/thirdeye/thirdeye-frontend/app/pods/components/anomaly-stats-block/template.hbs
deleted file mode 100644
index ea9208f..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/components/anomaly-stats-block/template.hbs
+++ /dev/null
@@ -1,53 +0,0 @@
-{{#each anomalyStats as |card|}}
- <ul class="te-horizontal-cards__card">
-
- <li class="te-horizontal-cards">
- <div class="te-horizontal-cards__card-title">{{card.title}}</div>
- {{#if card.tooltip}}
- <div class="te-horizontal-cards__card-tooltip">
- <span>
- <i class="glyphicon glyphicon-question-sign"></i>
- {{#tooltip-on-element}}{{card.text}}{{/tooltip-on-element}}
- </span>
- </div>
- {{else}}
- <div class="te-horizontal-cards__card-text">{{card.text}}</div>
- {{/if}}
- </li>
-
- <li class="te-horizontal-cards__card-value">
- <div class="te-horizontal-cards__val-group">
- {{#if isTunePreviewActive}}
- <div class="te-horizontal-cards__card-subt">Current</div>
- {{/if}}
- <div class="te-horizontal-cards__card-number">
- {{card.value}}
- {{#if card.valueUnits}}
- <span class="te-horizontal-cards__card-units">{{card.valueUnits}}</span>
- {{/if}}
- </div>
- {{#if card.showProjected}}
- <div class="te-horizontal-cards__card-subt {{if card.hideProjected "te-horizontal-cards--hidden"}}">Estimated: <span class="te-horizontal-cards__card-subt--stronger">{{card.projected}}{{if card.projectedUnits card.projectedUnits}}</span></div>
- {{/if}}
- </div>
- {{#if isTunePreviewActive}}
- <div class="te-horizontal-cards__val-group">
- <i class="te-horizontal-cards__val-glyph--middle glyphicon glyphicon-menu-right"></i>
- </div>
- <div class="te-horizontal-cards__val-group">
- <div class="te-horizontal-cards__card-subt">New</div>
- <div class="te-horizontal-cards__card-number">
- {{#if card.showDirectionIcon}}
- <i class="te-horizontal-cards__val-glyph--right glyphicon glyphicon-triangle-{{card.direction}}"></i>
- {{/if}}
- {{card.projected}}
- {{#if card.projectedUnits}}
- <span class="te-horizontal-cards__card-units">{{card.projectedUnits}}</span>
- {{/if}}
- </div>
- </div>
- {{/if}}
- </li>
-
- </ul>
-{{/each}}
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/dimension-heatmap/component.js b/thirdeye/thirdeye-frontend/app/pods/components/dimension-heatmap/component.js
deleted file mode 100644
index 510689c..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/components/dimension-heatmap/component.js
+++ /dev/null
@@ -1,199 +0,0 @@
-import $ from 'jquery';
-import { computed } from '@ember/object';
-import { alias } from '@ember/object/computed';
-import Component from '@ember/component';
-import d3 from 'd3';
-
-export default Component.extend({
- heatMapData: {},
- dimensions: alias('heatMapData.dimensions'),
- metricName: alias('heatMapData.metrics.firstObject'),
- inverseMetric:alias('heatMapData.inverseMetric'),
- classNames: ['dimension-heatmap'],
- heatmapMode: 'Change in Contribution',
-
- // Copy pasted code from all Thirdeye UI
- treeMapData: computed(
- 'dimensions',
- 'dimensions.@each',
- 'heatMapData',
- 'metricName',
- function() {
- const dimensions = this.get('dimensions');
- const heatMapData = this.get('heatMapData');
- const metricName= this.get('metricName');
- const treeMapData = [];
- for (var i in dimensions) {
- var dimension = dimensions[i];
- var dataKey = `${metricName}.${dimension}`;
- var row = {"t": "0", "children": []};
- if (heatMapData.data && heatMapData.data[dataKey]) {
- const {
- dimensionValue: dimensionValueIndex,
- percentageChange: percentageChangeIndex,
- currentValue: currentValueIndex,
- baselineValue: baselineValueIndex,
- baselineContribution: baselineContributionIndex,
- contributionToOverallChange: contributionToOverallChangeIndex,
- currentContribution: currentContributionIndex,
- contributionDifference: contributionChangeIndex
- } = heatMapData.data[dataKey].schema.columnsToIndexMapping;
-
- for (var j in heatMapData.data[dataKey].responseData) {
- var record = heatMapData.data[dataKey].responseData[j];
- var item = {
- t: record[dimensionValueIndex],
- value: record[currentValueIndex],
- baselineValue: record[baselineValueIndex],
- currentContribution: record[currentContributionIndex],
- baselineContribution: record[baselineContributionIndex],
- contributionChange: record[contributionChangeIndex],
- percentageChange: record[percentageChangeIndex],
- contributionToOverallChange: record[contributionToOverallChangeIndex]
- };
- if (item.t) {
- row.children.push(item);
- }
- }
- }
- treeMapData.push(row);
- }
- return treeMapData;
- }
- ),
-
- didUpdateAttrs() {
- this._super(...arguments);
-
- d3.select('.dimension-heatmap').selectAll('svg').remove();
- },
-
- willRender() {
- this._super(...arguments);
-
- d3.select('.dimension-heatmap').selectAll('svg').remove();
- },
-
- didRender() {
- this._super(...arguments);
-
- // Copy pasted code from all Thirdeye UI
- const heatmapMode = this.get('heatmapMode');
- const inverseMetric = this.get('inverseMetric');
-
- var getChangeFactor = function (dataRow) {
- var factor = dataRow.percentageChange;
- if (heatmapMode === 'Change in Contribution') {
- factor = dataRow.contributionChange;
- }
- if (heatmapMode === 'Contribution to Overall Change') {
- factor = dataRow.contributionToOverallChange;
- }
- return factor;
- };
-
- var getBackgroundColor = function (factor) {
- var opacity = Math.abs(factor / 25);
- if((factor > 0 && !inverseMetric) || (factor < 0 && inverseMetric)){
- return "rgba(0,0,234," + opacity + ")";
- } else{
- return "rgba(234,0,0," + opacity + ")" ;
- }
- };
-
- var getTextColor = function (factor) {
- var opacity = Math.abs(factor / 25);
- if(opacity < 0.5){
- return "#000000";
- } else{
- return "#ffffff" ;
- }
- };
-
- const dimensions = this.get('dimensions');
- const treeMapData = this.get('treeMapData');
-
- if (!dimensions) { return; }
-
- for (var i = 0; i < dimensions.length; i++) {
- var data = treeMapData[i];
- var dimension = dimensions[i];
- var dimensionPlaceHolderId = '#' + dimension + '-heatmap-placeholder';
- var height = $(dimensionPlaceHolderId).height();
- var width = $(dimensionPlaceHolderId).width();
- var treeMap = d3.layout.treemap().size([ width, height ]).sort(function(a, b) {
- return a.value - b.value;
- });
-
- var div = d3.select(dimensionPlaceHolderId).attr("class", "heatmap")
- .append("svg:svg").attr("width", width).attr("height", height).append("svg:g").attr("transform", "translate(.5,.5)");
-
- var nodes = treeMap.nodes(data).filter(function(d) {
- return !d.children;
- });
- var cell = div.selectAll("g").data(nodes).enter().append("svg:g").attr("class", "cell").attr("transform", function(d) {
- return "translate(" + d.x + "," + d.y + ")";
- // }).on("click", function(d) {
- // return zoom(node == d.parent ? root : d.parent);
- }).on("mousemove", function(d) {
-
- if (!d.percentageChange) { return; }
- const tooltipWidth = 200;
- const xPosition = d3.event.pageX - (tooltipWidth + 20);
- const yPosition = d3.event.pageY + 5;
- d3.select("#tooltip")
- .style("left", xPosition + "px")
- .style("top", yPosition + "px");
- d3.select("#tooltip #heading")
- .text(d.t);
- d3.select("#tooltip #percentageChange")
- .text(`${d.percentageChange}%`);
- d3.select("#tooltip #currentValue")
- .text(d.value);
- d3.select("#tooltip #contributionChange")
- .text(`${d.contributionChange}%`);
- d3.select("#tooltip #currentContribution")
- .text(d.currentContribution);
- d3.select("#tooltip #baselineContribution")
- .text(d.baselineContribution);
- d3.select("#tooltip #baselineValue")
- .text(d.baselineValue);
- d3.select("#tooltip").classed("hidden", false);
- }).on("mouseout", function() {
- d3.select("#tooltip").classed("hidden", true);
- });
-
- cell.append("svg:rect").attr("width", function(d) {
- return Math.max(d.dx - 1, 0);
- }).attr("height", function(d) {
- return Math.max(d.dy - 1, 0);
- }).style("fill", function(d) {
- var factor = getChangeFactor(d);
- return getBackgroundColor(factor);
- });
-
- cell.append('svg:text').attr("x", function(d) {
- return d.dx / 2;
- }).attr("y", function(d) {
- return d.dy / 2;
- }).attr("dy", ".35em").attr("text-anchor", "middle").text(function(d) {
- var factor = getChangeFactor(d);
- var text = d.t + '(' + factor + ')';
-
- //each character takes up 7 pixels on an average
- var estimatedTextLength = text.length * 7;
- if(estimatedTextLength > d.dx) {
- return text.substring(0, d.dx/7) + "..";
- } else {
- return text;
- }
- }).style('opacity', function(d) {
- d.w = this.getComputedTextLength();
- return d.dx > d.w ? 1 : 0;
- }).style('fill', function(d){
- var factor = getChangeFactor(d);
- return getTextColor(factor);
- });
- }
- }
-});
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/dimension-heatmap/template.hbs b/thirdeye/thirdeye-frontend/app/pods/components/dimension-heatmap/template.hbs
deleted file mode 100644
index ce3235e..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/components/dimension-heatmap/template.hbs
+++ /dev/null
@@ -1,16 +0,0 @@
-<div class="row">
- <div class="col-xs-12">
- <table class="table table-borderless dimension-heatmap__table">
- <tbody>
- {{#each dimensions as |dimension|}}
- <tr>
- <td class="col-xs-1" style="vertical-align: middle" class="label-medium-light">{{dimension}}</td>
- <td class="col-xs-11">
- <div id="{{dimension}}-heatmap-placeholder" style="height: 50px; width: 100%"></div>
- </td>
- </tr>
- {{/each}}
- </tbody>
- </table>
- </div>
-</div>
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/dimension-summary/component.js b/thirdeye/thirdeye-frontend/app/pods/components/dimension-summary/component.js
deleted file mode 100644
index 507e904..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/components/dimension-summary/component.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import Component from '@ember/component';
-
-export default Component.extend({
- classNames: ['dimension-summary card-container card-container--padded']
-});
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/dimension-summary/template.hbs b/thirdeye/thirdeye-frontend/app/pods/components/dimension-summary/template.hbs
deleted file mode 100644
index ec89715..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/components/dimension-summary/template.hbs
+++ /dev/null
@@ -1,16 +0,0 @@
- <div class="dimension-summary__item">
- <label class="dimension-summary__label">Current Total</label>
- <span class="dimension-summary__data">{{format-number data.currentTotal}}</span>
- </div>
- <div class="dimension-summary__item">
- <label class="dimension-summary__label">Baseline Total</label>
- <span class="dimension-summary__data">{{format-number data.baselineTotal}}</span>
- </div>
- <div class="dimension-summary__item">
- <label class="dimension-summary__label">Change Value</label>
- <span class="dimension-summary__data dimension-summary__data--{{color-delta data.deltaChange}}">{{format-number data.deltaChange}}</span>
- </div>
- <div class="dimension-summary__item">
- <label class="dimension-summary__label">% Change</label>
- <span class="dimension-summary__data dimension-summary__data--{{color-delta data.deltaPercentage}}">{{data.deltaPercentage}} %</span>
- </div>
\ No newline at end of file
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/events-header/component.js b/thirdeye/thirdeye-frontend/app/pods/components/events-header/component.js
deleted file mode 100644
index 3fa7afa..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/components/events-header/component.js
+++ /dev/null
@@ -1,86 +0,0 @@
-import { alias } from '@ember/object/computed';
-import { computed } from '@ember/object';
-import Component from '@ember/component';
-
-export default Component.extend({
- events: [],
- onTabChange: null,
-
- // default active tab
- activeTab: 'all',
-
-
- /**
- * Holiday Events
- */
- holidays: computed(
- 'events.@each',
- function() {
- return this.get('events')
- .filter(event => event.eventType === 'holiday');
- }
- ),
-
- /**
- * GCN events
- */
- gcn: computed(
- 'events.@each',
- function() {
- return this.get('events')
- .filter(event => event.eventType === 'gcn');
- }
- ),
-
- /**
- * anomaly events
- */
- anomaly: computed(
- 'events.@each',
- function() {
- return this.get('events')
- .filter(event => event.eventType === 'anomaly');
- }
- ),
-
-
- /**
- * Informed events
- */
- informed: computed(
- 'events.@each',
- function() {
- return this.get('events')
- .filter(event => event.eventType === 'informed');
- }
- ),
-
-
- /**
- * Lix events
- */
- lix: computed(
- 'events.@each',
- function() {
- return this.get('events')
- .filter(event => event.eventType === 'lix');
- }
- ),
-
- /**
- * Count of events
- */
- allCount: alias('events.length'),
- holidayCount: alias('holidays.length'),
- gcnCount: alias('gcn.length'),
- informedCount: alias('informed.length'),
- lixCount: alias('lix.length'),
- anomalyCount: alias('anomaly.length'),
-
- actions: {
- // Handles tab change on click
- onTabClick(tab) {
- this.attrs.onTabChange(tab);
- }
- }
-});
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/events-header/template.hbs b/thirdeye/thirdeye-frontend/app/pods/components/events-header/template.hbs
deleted file mode 100644
index 9f77c9e..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/components/events-header/template.hbs
+++ /dev/null
@@ -1,26 +0,0 @@
-<div class="events-summary">
- <div class="events-summary__item {{if (eq activeTab 'all') 'events-summary__item--active'}}" {{action "onTabClick" "all"}}>
- <span class="events-summary__number">{{allCount}}</span>
- <span>All</span>
- </div>
- <div class="events-summary__item events-summary__item--green {{if (eq activeTab 'holiday') 'events-summary__item--active'}}" {{action "onTabClick" "holiday"}}>
- <span class="events-summary__number">{{holidayCount}}</span>
- <span>Holiday</span>
- </div>
- <div class="events-summary__item events-summary__item--teal {{if (eq activeTab 'anomaly') 'events-summary__item--active'}}" {{action "onTabClick" "anomaly"}}>
- <span class="events-summary__number">{{anomalyCount}}</span>
- <span>Past Anomaly</span>
- </div>
- <div class="events-summary__item events-summary__item--orange {{if (eq activeTab 'gcn') 'events-summary__item--active'}}" {{action "onTabClick" "gcn"}}>
- <span class="events-summary__number">{{gcnCount}}</span>
- <span>GCN</span>
- </div>
- <div class="events-summary__item events-summary__item--purple {{if (eq activeTab 'lix') 'events-summary__item--active'}}" {{action "onTabClick" "lix"}}>
- <span class="events-summary__number">{{lixCount}}</span>
- <span>Lix</span>
- </div>
- <div class="events-summary__item events-summary__item--red {{if (eq activeTab 'informed') 'events-summary__item--active'}}" {{action "onTabClick" "informed"}}>
- <span class="events-summary__number">{{informedCount}}</span>
- <span>Deployment</span>
- </div>
-</div>
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/events-table/component.js b/thirdeye/thirdeye-frontend/app/pods/components/events-table/component.js
deleted file mode 100644
index 5813c34..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/components/events-table/component.js
+++ /dev/null
@@ -1,134 +0,0 @@
-import { later } from '@ember/runloop';
-import { computed } from '@ember/object';
-import Component from '@ember/component';
-
-export default Component.extend({
- events: [],
- selectedTab: 'all',
-
- start: null,
- end: null,
-
- /**
- * Returns event based on the selected tab
- */
- filteredEvents: computed(
- 'eventsInRange.@each.type',
- 'selectedTab',
- function() {
- const events = this.get('eventsInRange');
- const selectedTab = this.get('selectedTab');
-
- if (selectedTab === 'all') { return events; }
- return events
- .filter(event => (event.eventType === selectedTab))
- .sortBy('score')
- .reverse();
- }
- ),
-
- /**
- * Returns events in a range
- */
- eventsInRange: computed(
- 'events',
- 'start',
- 'end',
- function() {
- const events = this.get('events');
- const start = this.get('start');
- const end = this.get('end');
-
- if (!(start && end)) { return events; }
-
- return events.filter((event) => {
- const {
- displayStart,
- displayEnd } = event;
-
- return (displayStart <= end) && (displayEnd >= start);
- });
- }
- ),
-
- // Require to display a loader for long rendering
- didUpdateAttrs() {
- later(() => {
- this._super(...arguments);
- });
- },
-
- init() {
- this._super(...arguments);
-
- /**
- * Columns required by ember-models-table
- */
- const columns = [
- {
- template: 'custom/checkbox',
- useFilter: false,
- mayBeHidden: false,
- className: 'events-table__column--checkbox'
- },
- {
- propertyName: 'displayLabel',
- template: 'custom/eventLabel',
- title: 'Event Name',
- className: 'events-table__column'
- },
- {
- propertyName: 'eventType',
- title: 'Type',
- filterWithSelect: true,
- sortFilterOptions: true,
- className: 'events-table__column--compact'
- },
- {
- propertyName: 'humanRelStart',
- title: 'Start',
- className: 'events-table__column--compact',
- sortedBy: 'relStart',
- disableFiltering: true
- },
- {
- propertyName: 'humanDuration',
- title: 'Duration',
- className: 'events-table__column--compact',
- sortedBy: 'duration',
- disableFiltering: true
- }
- // {
- // propertyName: 'score',
- // title: 'Score',
- // disableFiltering: true,
- // className: 'events-table__column--compact',
- // sortDirection: 'desc'
- // }
- ];
- this.set('columns', columns);
- },
-
- actions: {
- /**
- * Handles tab selection
- * @param {String} tab String of the new selected tab
- */
- onTabChange(tab) {
- const currentTab = this.get('selectedTab');
-
- if (currentTab !== tab) {
- this.set('selectedTab', tab);
- }
- },
-
- /**
- * Handles event selectiion
- * @param {Object} event The new event Object
- */
- onSelection(event) {
- this.attrs.onSelection(event.urn);
- }
- }
-});
-
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/events-table/template.hbs b/thirdeye/thirdeye-frontend/app/pods/components/events-table/template.hbs
deleted file mode 100644
index ed52290..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/components/events-table/template.hbs
+++ /dev/null
@@ -1,16 +0,0 @@
-{{events-header
- events=eventsInRange
- onTabChange=(action "onTabChange")
- activeTab=selectedTab
-}}
-
-{{models-table
- data=filteredEvents
- columns=columns
- showColumnsDropdown=false
- showGlobalFilter=false
- filteringIgnoreCase=true
- multipleExpand=true
- expandedRowTemplate='custom/expanded-row'
- onSelection='onSelection'
-}}
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/modals/manage-groups-modal/component.js b/thirdeye/thirdeye-frontend/app/pods/components/modals/manage-groups-modal/component.js
deleted file mode 100644
index 6a3e196..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/components/modals/manage-groups-modal/component.js
+++ /dev/null
@@ -1,716 +0,0 @@
-/**
- * Component for selecting and managing subscription groups in a modal
- *
- * Supports
- * - search groups via application and name,
- * - search anomaly functions from db
- * - group creation, copying and editing
- * - transactional cancel or save
- *
- * @module components/modals/manage-groups-modal
- * @property {Function} onSubmit - closure action saving group changes
- * @property {Function} onCancel - closure action cancelling the modal
- * @property {int} preselectedGroupId - preselected group id (optional)
- * @property {int} preselectedFunctionId - preselected group id (optional)
- * @example
- {{modals/manage-groups-modal
- showManageGroupsModal
- }}
- * @exports manage-groups-modal
- * @author apucher
- */
-
-import Component from '@ember/component';
-import { computed, get, set, getProperties, setProperties } from '@ember/object';
-import { checkStatus } from 'thirdeye-frontend/utils/utils';
-import fetch from 'fetch';
-import _ from 'lodash';
-import RSVP from 'rsvp';
-
-export default Component.extend({
-
- /**
- * Custom classes to be applied
- */
- classes: Object.freeze({
- theadCell: "te-modal__table-header"
- }),
-
- /**
- * display flag for modal
- * @type {boolean}
- */
- showManageGroupsModal: false,
-
- /**
- * id of preselected group
- * @type {int}
- */
- preselectedGroupId: null,
-
- /**
- * id of preselected function
- * @type {int}
- */
- preselectedFunctionId: null,
-
- /**
- * Action for save/confirm. Passes selected group as argument
- * @type {Function}
- */
- onSave: null,
-
- /**
- * Action for cancellation.
- * @type {Function}
- */
- onExit: null,
-
- /**
- * Cache for current group
- * @type {object}
- */
- changeCacheCurrent: null,
-
- /**
- * Cache for all changed groups
- * @type {Set}
- */
- changeCache: null,
-
- /**
- * Cache for existing group names
- * @type {Set}
- */
- groupNameCache: computed('groupOptionsRaw', function () {
- const groupOptionsRaw = get(this, 'groupOptionsRaw');
- return new Set(groupOptionsRaw.map(opt => opt.name));
- }),
-
- /**
- * Handle init of properties
- */
- didReceiveAttrs() {
- this._super(...arguments);
-
- // TODO use ember data API for applications
- fetch('/thirdeye/entity/APPLICATION')
- .then(checkStatus)
- .then(res => this._makeApplicationOptions(res))
- .then(options => set(this, 'applicationOptions', options));
-
- // TODO use ember data API for alert configs
- // TODO support incremental backend search
- fetch('/thirdeye/entity/ALERT_CONFIG')
- .then(checkStatus)
- .then(res => this._makeGroupOptions(res))
- .then(options => {
- this._handlePreselection(options, get(this, 'preselectedGroupId'));
- return options;
- })
- .then(options => set(this, 'groupOptionsRaw', options));
-
- // TODO use ember data API for anomaly functions
- // TODO support incremental backend search
- fetch('/thirdeye/entity/ANOMALY_FUNCTION')
- .then(checkStatus)
- .then(res => this._makeFunctionOptions(res))
- .then(options => set(this, 'functionOptions', options));
-
- // TODO optimize reverse lookup of options via dict if necessary
-
- set(this, 'changeCache', new Set());
- },
-
- /**
- * Non-editable flag for components dependent on application selection
- * @type {boolean}
- */
- cannotSelect: computed('application', function () {
- return _.isEmpty(get(this, 'application'));
- }),
-
- /**
- * Non-editable flag for components dependent on group selection
- * @type {boolean}
- */
- cannotEdit: computed('group', function () {
- return _.isEmpty(get(this, 'group'));
- }),
-
- /**
- * Preselected function name, resolved via functionOptions
- * @type {string}
- */
- functionName: computed('functionOptions', 'preselectedFunctionId', function () {
- const { functionOptions, preselectedFunctionId } =
- getProperties(this, 'functionOptions', 'preselectedFunctionId');
-
- if (!_.isNumber(preselectedFunctionId)) { return; }
-
- const opt = functionOptions.find(opt => opt.id === preselectedFunctionId);
-
- if (_.isEmpty(opt)) { return; }
-
- return opt.name;
- }),
-
- /**
- * Flag for preselected function
- * @type {boolean}
- */
- hasFunction: computed('functionName', function () {
- return _.isNumber(get(this, 'preselectedFunctionId'));
- }),
-
- /**
- * Flag for add function shortcut
- * @type {boolean}
- */
- hasFunctionShortcut: computed('preselectedFunctionId', 'group', function () {
- const { preselectedFunctionId, group } =
- getProperties(this, 'preselectedFunctionId', 'group');
-
- if (_.isEmpty(group) || !_.isNumber(preselectedFunctionId)) { return false; }
-
- if (group.emailConfig.functionIds.includes(preselectedFunctionId)) {
- return false;
- }
-
- return true;
- }),
-
- /**
- * Footer text tracking change cache
- * @type {string}
- */
- footerText: computed('changeCache', function () {
- const changeCache = get(this, 'changeCache');
- if (_.isEmpty(changeCache)) {
- return '';
- }
- if (changeCache.size === 1) {
- return '(1 group will be modified)';
- }
- return `(${changeCache.size} groups will be modified)`;
- }),
-
- /**
- * Error message container for group name
- * @type {string}
- */
- groupNameMessage: null,
-
- /**
- * Error message container for to-recipients
- * @type {string}
- */
- toAddrWarning: null,
-
- /**
- * Temp storage for recipients(to) from text input
- * @type {String}
- */
- toAddresses: null,
-
- /**
- * Temp storage for recipients(cc) from text input
- * @type {String}
- */
- ccAddresses: null,
-
- /**
- * Temp storage for recipients(bcc) from text input
- * @type {String}
- */
- BccAddresses: null,
-
- /**
- * Group options available in database
- * @type {Array}
- */
- groupOptionsRaw: [],
-
- /**
- * Group options available for selection (and search)
- * @type {Array}
- */
- groupOptions: computed('application', 'groupOptionsRaw', function () {
- const { application, groupOptionsRaw } = getProperties(this, 'application', 'groupOptionsRaw');
- const options = groupOptionsRaw.filter(opt => opt.application === null || opt.application === application || opt.id === null);
- options[0].application = application; // set application for "new" template
- return options;
- }),
-
- /**
- * Shortcut header for groups an alert is already part of
- * @type {Array}
- */
- groupShortcuts: computed('preselectedFunctionId', 'groupOptionsRaw', function () {
- const { preselectedFunctionId, groupOptionsRaw } =
- getProperties(this, 'preselectedFunctionId', 'groupOptionsRaw');
-
- return groupOptionsRaw.filter((group) => {
- if (group.emailConfig && group.emailConfig.functionIds) {
- return group.emailConfig.functionIds.includes(preselectedFunctionId);
- }
- });
- }),
-
- /**
- * Currently selected group
- * @type {object}
- */
- group: null,
-
- /**
- * Currently selected application
- * @type {object}
- */
- application: null,
-
- /**
- * Application options available for selection (and search)
- * @type {Array}
- */
- applicationOptions: [],
-
- /**
- * Currently selected application option
- * @type {object}
- */
- applicationOptionSelected: computed('application', function () {
- const { applicationOptions, application } = getProperties(this, 'applicationOptions', 'application');
- if (_.isEmpty(application)) { return; }
- return applicationOptions.find(opt => opt.application === application);
- }).readOnly(),
-
- /**
- * Cron options available for selection
- * @type {Array}
- */
- cronOptionsRaw: [
- { name: 'immediately', cron: '0 0/5 * * * ? *' },
- { name: 'every 15 min', cron: '0 0/15 * * * ? *' },
- { name: 'every hour', cron: '0 0 * * * ? *' },
- { name: 'every 3 hours', cron: '0 0 0/3 * * ? *' },
- { name: 'every 6 hours', cron: '0 0 0/6 * * ? *' },
- { name: 'daily', cron: '0 0 0 * * ? *' },
- { name: 'weekly', cron: '0 0 0 * * SUN *' }
- ],
-
- /**
- * Cron options including an optional custom, pre-existing option
- * @type {Array}
- */
- cronOptions: computed('group', 'cronOptionsRaw', function () {
- const { group, cronOptionsRaw } = getProperties(this, 'group', 'cronOptionsRaw');
-
- if (_.isEmpty(group)) { return cronOptionsRaw; }
-
- if (_.isEmpty(cronOptionsRaw.find(opt => opt.cron === group.cronExpression))) {
- return [...cronOptionsRaw].concat([{ name: `custom setting ("${group.cronExpression}")`, cron: group.cronExpression }]);
- }
-
- return cronOptionsRaw;
- }),
-
- /**
- * Currently selected cron option
- * @type {object}
- */
- cronOptionSelected: computed('group.cronExpression', function () {
- const { cronOptions, group } = getProperties(this, 'cronOptions', 'group');
- if (_.isEmpty(group)) { return; }
- return cronOptions.find(opt => opt.cron === group.cronExpression);
- }).readOnly(),
-
- /**
- * SubjectType options available for selection
- * @type {Array}
- */
- subjectTypeOptions: [
- { name: 'group name only', subjectType: 'ALERT' },
- { name: 'with metric name', subjectType: 'METRICS' },
- { name: 'with dataset name', subjectType: 'DATASETS' }
- ],
-
- /**
- * Currently selected subjectType option
- * @type {object}
- */
- subjectTypeOptionSelected: computed('group.subjectType', function () {
- const { subjectTypeOptions, group } = getProperties(this, 'subjectTypeOptions', 'group');
- if (_.isEmpty(group)) { return; }
- return subjectTypeOptions.find(opt => opt.subjectType === group.subjectType);
- }).readOnly(),
-
- /**
- * Function options available for selection (and search)
- * @type {Array}
- */
- functionOptions: [],
-
- /**
- * Cached functionIds parsed from currently selected group
- * @type {Set}
- */
- functionOptionsSelectedIds: computed('group.emailConfig.functionIds', function () {
- const functionIds = get(this, 'group.emailConfig.functionIds');
- if (_.isEmpty(functionIds)) { return []; }
- return new Set(functionIds);
- }),
-
- /**
- * Currently selected function ids
- * @type {Array}
- */
- functionOptionsSelected: computed('functionOptionsSelectedIds', function () {
- const { functionOptions, functionOptionsSelectedIds } = getProperties(this, 'functionOptions', 'functionOptionsSelectedIds');
- if (_.isEmpty(functionOptionsSelectedIds)) { return []; }
- return functionOptions.filter(opt => functionOptionsSelectedIds.has(opt.id));
- }).readOnly(),
-
- /**
- * Parses application entities into power-select options
- *
- * @param res {Array} APPLICATION entities
- * @returns {Array} application options
- * @private
- */
- _makeApplicationOptions (res) {
- return res.map(r => Object.assign({}, { name: r.application, application: r.application })).sortBy('name');
- },
-
- /**
- * Parses alert group entities into power-select options
- *
- * @param res {Array} ALERT_CONFIG entities
- * @returns {Array} groups
- * @private
- */
- _makeGroupOptions (res) {
- return [{
- id: null,
- name: '(new group)',
- active: true,
- application: null,
- cronExpression: get(this, 'cronOptions')[0].cron,
- subjectType: get(this, 'subjectTypeOptions')[0].subjectType,
- emailConfig: {
- functionIds: []
- }
- }].concat(res.sortBy('name'));
- },
-
- /**
- * Parses anomaly function entities into power-select options
- *
- * @param res {Array} ANOMALY_FUNCTION entities
- * @returns {Array} function options
- * @private
- */
- _makeFunctionOptions (res) {
- return res.map(f => Object.assign({}, { name: f.functionName, id: f.id })).sortBy('name');
- },
-
- /**
- * Selects the group with given id
- *
- * @param groupOptions {Array} available groups
- * @param groupId {int} preselected group id
- * @private
- */
- _handlePreselection(groupOptions, groupId) {
- if (_.isEmpty(groupId)) { return; }
-
- const group = groupOptions.find(opt => opt.id === groupId);
- if (_.isEmpty(group)) { return; }
-
- setProperties(this, { group, application: group.application });
- },
-
- /**
- * Stage a newly selected group for caching if not already tracked in change cache
- *
- * @param group {object} group
- * @private
- */
- _makeChangeCacheCurrent(group) {
- const changeCache = get(this, 'changeCache');
-
- if (_.isEmpty(group)) { return; }
-
- if (changeCache.has(group)) {
- set(this, 'changeCacheCurrent', group);
- return;
- }
-
- set(this, 'changeCacheCurrent', _.cloneDeep(group));
- },
-
- /**
- * Checks for changes of the selected group and adds it to the change cache if verified
- * // TODO trigger this (debounced) on every edit?
- *
- * @private
- */
- _updateChangeCache() {
- const { changeCacheCurrent, changeCache, group } =
- getProperties(this, 'changeCacheCurrent', 'changeCache', 'group');
-
- if (_.isEmpty(group)) { return; }
-
- if (!changeCache.has(group) && !_.isEqual(changeCacheCurrent, group)) {
- const newChangeCache = new Set([...changeCache].concat([group]));
- set(this, 'changeCache', newChangeCache);
- }
- },
-
- /**
- * Validate the group name for validity and uniqueness and display warning if necessary.
- *
- * @param group {object} group
- * @private
- */
- _validateGroupName(group) {
- const { groupNameCache, changeCacheCurrent } =
- getProperties(this, 'groupNameCache', 'changeCacheCurrent');
-
- if (_.isEmpty(group)) { return; }
- if (_.isEmpty(groupNameCache)) { return; }
-
- const inUse = new Set(groupNameCache);
- if (!_.isEmpty(changeCacheCurrent)) {
- inUse.delete(changeCacheCurrent.name);
- }
-
- if (_.isEmpty(group.name) || group.name.startsWith('(') || inUse.has(group.name)) {
- set(this, 'groupNameMessage', 'group name invalid or already in use');
- } else {
- set(this, 'groupNameMessage', null);
- }
- },
-
- /**
- * Check for at least one recipient
- *
- * @param toAddr {String} comma separated email addresses
- * @private
- */
- _validateRecipient(toAddr) {
- if (!_.isEmpty(toAddr)) {
- var emailArray = toAddr.split(',');
- for (var index = 0; index < emailArray.length; index++) {
- if (this._validateEmail(emailArray[index].trim())) {
- set(this, 'toAddrWarning', null);
- return;
- }
- }
- }
-
- set(this, 'toAddrWarning', 'Please enter at least one valid recipient');
- },
-
- /**
- * Verify if string is a valid email address
- *
- * @param email {String} email address
- * @private
- */
- _validateEmail(email) {
- var re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
- return re.test(String(email).toLowerCase());
- },
-
- actions: {
- /**
- * Handles recipient updates
- */
- onToAddresses () {
- const toAddresses = get(this, 'toAddresses');
- this._validateRecipient(toAddresses);
-
- set(this, 'group.receiverAddresses.to', toAddresses.replace(/[^!-~]+/g, '').replace(/,+/g, ',').split(','));
- },
- onCcAddresses () {
- const ccAddresses = get(this, 'ccAddresses');
- set(this, 'group.receiverAddresses.cc', ccAddresses.replace(/[^!-~]+/g, '').replace(/,+/g, ',').split(','));
- },
- onBccAddresses () {
- const bccAddresses = get(this, 'bccAddresses');
- set(this, 'group.receiverAddresses.bcc', bccAddresses.replace(/[^!-~]+/g, '').replace(/,+/g, ',').split(','));
- },
-
- /**
- * Handles functionIds selection
- * @param functionOptions {Array} function options
- */
- onFunctionIds (functionOptions) {
- const prevFunctionIds = get(this, 'group.emailConfig.functionIds');
- const fid = get(this, 'preselectedFunctionId');
-
- const functionIds = functionOptions.map(opt => opt.id);
- set(this, 'group.emailConfig.functionIds', functionIds);
-
- // trigger group shortcut compute (instead of deep nested listener)
- if (_.isNumber(fid) && (prevFunctionIds.includes(fid) || functionIds.includes(fid))) {
- this.notifyPropertyChange('preselectedFunctionId');
- }
- },
-
- /**
- * Handles adding preselected function id to selected function ids
- */
- onFunctionShortcut () {
- const { preselectedFunctionId, group } =
- getProperties(this, 'preselectedFunctionId', 'group');
-
- if (!_.isNumber(preselectedFunctionId)) { return; }
- if (_.isEmpty(group)) { return; }
-
- const functionIds = new Set(group.emailConfig.functionIds);
- functionIds.add(preselectedFunctionId);
-
- set(this, 'group.emailConfig.functionIds', [...functionIds]);
-
- // trigger group shortcut compute (instead of deep nested listener)
- this.notifyPropertyChange('preselectedFunctionId');
- },
-
- /**
- * Handles the close event
- */
- onCancel () {
- const onExit = get(this, 'onExit');
-
- setProperties(this, {
- application: null,
- group: null,
- toAddresses: null,
- ccAddresses: null,
- bccAddresses: null,
- showManageGroupsModal: false,
- changeCache: new Set(),
- groupNameMessage: null,
- toAddrWarning: null
- });
-
- if (onExit) { onExit(); }
- },
-
- /**
- * Handles save event
- */
- onSubmit () {
- this._updateChangeCache();
-
- const { group, onSave, changeCache } = getProperties(this, 'group', 'onSave', 'changeCache');
-
- const promises = [...changeCache].map(group => {
- fetch('/thirdeye/entity?entityType=ALERT_CONFIG', {method: 'POST', body: JSON.stringify(group)})
- .then(checkStatus);
- });
-
- // TODO use ember data API for alert configs
- RSVP.allSettled(promises)
- .then(res => setProperties(this, {
- application: null,
- group: null,
- toAddresses: null,
- ccAddresses: null,
- bccAddresses: null,
- showManageGroupsModal: false,
- changeCache: new Set(),
- groupNameMessage: null,
- toAddrWarning: null
- }))
- .then(res => {
- if (onSave) { onSave(group); }
- })
- .catch(err => set(this, 'message', err));
- },
-
- /**
- * Handles group selection
- * @param group
- */
- onGroup (group) {
- this._updateChangeCache();
- this._makeChangeCacheCurrent(group);
-
- setProperties(this, {
- application: group.application, // in case not set
- group,
- groupFunctionIds: (group.emailConfig.functionIds || []).join(', '),
- toAddresses: (group.receiverAddresses.to || []).join(', '),
- ccAddresses: (group.receiverAddresses.cc || []).join(', '),
- bccAddresses: (group.receiverAddresses.bcc || []).join(', ')
- });
-
- this._validateGroupName(group);
- },
-
- /**
- * Handles copy button
- */
- onCopy () {
- const { group, groupOptions, groupOptionsRaw } = getProperties(this, 'group', 'groupOptions', 'groupOptionsRaw');
-
- if (_.isEmpty(group) || group.id === null) { return; }
-
- const newGroup = Object.assign(_.cloneDeep(group), {
- id: null,
- name: `Copy of ${group.name}`
- });
-
- // push options directly rather than triggering re-compute
- groupOptionsRaw.pushObject(newGroup);
- groupOptions.pushObject(newGroup);
-
- setProperties(this, { group: newGroup, changeCacheCurrent: group });
- this._validateGroupName(newGroup);
- },
-
- /**
- * Handles cron selection
- * @param cronOption {object} cron option
- */
- onCron (cronOption) {
- set(this, 'group.cronExpression', cronOption.cron);
- },
-
- /**
- * Handles subjectType selection
- * @param subjectOption {object} subjectType option
- */
- onSubjectType (subjectOption) {
- set(this, 'group.subjectType', subjectOption.subjectType);
- },
-
- /**
- * Handles application selection
- * @param applicationOption {object} application option
- */
- onApplication (applicationOption) {
- this._updateChangeCache();
- setProperties(this, {
- application: applicationOption.application,
- group: null,
- toAddresses: null,
- ccAddresses: null,
- bccAddresses: null,
- groupNameMessage: null,
- toAddrWarning: null
- });
- },
-
- /**
- * Handle group name edit
- */
- onName () {
- const group = get(this, 'group');
- this._validateGroupName(group);
- }
- }
-});
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/modals/manage-groups-modal/template.hbs b/thirdeye/thirdeye-frontend/app/pods/components/modals/manage-groups-modal/template.hbs
deleted file mode 100644
index eab485e..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/components/modals/manage-groups-modal/template.hbs
+++ /dev/null
@@ -1,239 +0,0 @@
-{{#te-modal
- headerText="Manage Subscription Groups"
- footerText=footerText
- isShowingModal=showManageGroupsModal
- isInvalid=isInvalid
- cancelAction=(action "onCancel")
- submitAction=(action "onSubmit")
- hasFooter=true
-}}
-
- {{#if hasFunction}}
- <div class="row te-modal__settings">
- <div class="col-md-2">
- <span class="te-label te-label--bold te-label--dark">Group shortcuts</span>
- </div>
- <div class="col-md-10">
- {{#each groupShortcuts as |group index| }}
- {{#if index}}, {{/if}}
- <a {{action "onGroup" group}}>{{group.name}}</a>
- {{/each}}
- </div>
- </div>
-
- <hr/>
- {{/if}}
-
- <div class="row te-modal__settings">
- <div class="col-md-2">
- <span class="te-label te-label--bold te-label--dark">Find Group</span>
- </div>
- <div class="col-md-3">
- {{#power-select
- class="te-modal__input"
- triggerClass="te-modal__filter-select te-modal__filter-select--flushed"
- selected=applicationOptionSelected
- options=applicationOptions
- renderInPlace=true
- searchField="name"
- triggerId="application-selection"
- placeholder="Select application"
- onchange=(action "onApplication")
- as |option|
- }}
- {{option.name}}
- {{/power-select}}
- </div>
-
- <div class="col-md-5">
- {{#power-select
- triggerClass="te-modal__filter-select te-modal__filter-select--flushed"
- selected=group
- options=groupOptions
- searchField="name"
- renderInPlace=true
- triggerId="group-selection"
- placeholder="Search subscription group"
- disabled=cannotSelect
- onchange=(action "onGroup")
- as |group|
- }}
- {{group.name}}
- {{/power-select}}
- </div>
- <div class="col-md-2">
- <button id="button-new" onclick={{action "onCopy"}} disabled={{cannotEdit}}>Create copy</button>
- </div>
- </div>
-
- <hr/>
-
- <div class="row te-modal__settings">
- <div class="col-md-2">
- <span class="te-label te-label--bold te-label--dark">Group name</span>
- </div>
- <div class="col-md-10">
- {{input
- type="text"
- id="name"
- value=group.name
- class="te-modal__input te-modal__input--fullwidth"
- disabled=cannotEdit
- key-up=(action "onName")
- }}
- {{#if groupNameMessage}}
- ({{groupNameMessage}})
- {{/if}}
- </div>
- </div>
-
- <div class="row te-modal__settings">
- <div class="col-md-2">
- <span class="te-label te-label--bold te-label--dark">Alerts</span>
- </div>
- <div class="col-md-10">
- {{#power-select-multiple
- triggerClass="te-modal__filter-select te-modal__filter-select--flushed"
- selected=functionOptionsSelected
- options=functionOptions
- renderInPlace=true
- searchField="name"
- triggerId="function-selection"
- disabled=cannotEdit
- onchange=(action "onFunctionIds")
- as |option|
- }}
- {{option.name}}
- {{/power-select-multiple}}
- {{#if hasFunctionShortcut}}
- (add <a {{action "onFunctionShortcut"}}>{{functionName}}</a> to alerts)
- {{/if}}
- </div>
- </div>
-
- <div class="row te-modal__settings">
- <div class="col-md-2">
- <span class="te-label te-label--bold te-label--dark">Schedule</span>
- </div>
- <div class="col-md-8">
- {{#power-select
- triggerClass="te-modal__filter-select te-modal__filter-select--flushed"
- selected=cronOptionSelected
- options=cronOptions
- renderInPlace=true
- searchEnabled=false
- triggerId="cron-selection"
- disabled=cannotEdit
- onchange=(action "onCron")
- as |option|
- }}
- {{option.name}}
- {{/power-select}}
- </div>
- <div class="col-md-2">
- <input
- type="checkbox"
- id="active"
- checked={{group.active}}
- disabled={{cannotEdit}}
- />
- <label for="active">Enabled</label>
- </div>
- </div>
-
- <div class="row te-modal__settings">
- <div class="col-md-2">
- <span class="te-label te-label--bold te-label--dark">Email subject</span>
- </div>
- <div class="col-md-10">
- {{#power-select
- triggerClass="te-modal__filter-select te-modal__filter-select--flushed"
- selected=subjectTypeOptionSelected
- options=subjectTypeOptions
- renderInPlace=true
- searchEnabled=false
- triggerId="subject-type-selection"
- disabled=cannotEdit
- onchange=(action "onSubjectType")
- as |option|
- }}
- {{option.name}}
- {{/power-select}}
- </div>
- </div>
-
- <div class="row te-modal__settings">
- <div class="col-md-2">
- <span class="te-label te-label--bold te-label--dark">Sender</span>
- </div>
- <div class="col-md-10">
- {{input
- type="text"
- id="from-address"
- value=group.fromAddress
- class="te-modal__input te-modal__input--fullwidth"
- disabled=cannotEdit
- }}
- </div>
- </div>
-
- <div class="row te-modal__settings">
- <div class="col-md-2">
- <span class="te-label te-label--bold te-label--dark">To</span>
- </div>
- <div class="col-md-10">
- {{textarea-autosize
- cols=80
- rows=3
- placeholder="Enter recipients (comma separated). E.g., user1@linkedin.com, user2@linkedin.com"
- type="text"
- id="to-addresses"
- value=toAddresses
- class="te-modal__input te-modal__input--fullwidth"
- disabled=cannotEdit
- key-up=(action "onToAddresses")
- }}
- {{#if toAddrWarning}}
- ({{toAddrWarning}})
- {{/if}}
- </div>
- </div>
-
- <div class="row te-modal__settings">
- <div class="col-md-2">
- <span class="te-label te-label--bold te-label--dark">Cc</span>
- </div>
- <div class="col-md-10">
- {{textarea-autosize
- cols=80
- rows=1
- placeholder="Enter recipients (comma separated). E.g., user1@linkedin.com, user2@linkedin.com"
- type="text"
- id="cc-addresses"
- value=ccAddresses
- class="te-modal__input te-modal__input--fullwidth"
- disabled=cannotEdit
- change=(action "onCcAddresses")
- }}
- </div>
- </div>
-
- <div class="row te-modal__settings">
- <div class="col-md-2">
- <span class="te-label te-label--bold te-label--dark">Bcc</span>
- </div>
- <div class="col-md-10">
- {{textarea-autosize
- cols=80
- rows=1
- placeholder="Enter recipients (comma separated). E.g., user1@linkedin.com, user2@linkedin.com"
- type="text"
- id="bcc-addresses"
- value=bccAddresses
- class="te-modal__input te-modal__input--fullwidth"
- disabled=cannotEdit
- change=(action "onBccAddresses")
- }}
- </div>
- </div>
-{{/te-modal}}
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/performance-tooltip/component.js b/thirdeye/thirdeye-frontend/app/pods/components/performance-tooltip/component.js
deleted file mode 100644
index 692740d..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/components/performance-tooltip/component.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import Component from '@ember/component';
-
-export default Component.extend({
- classNames: ['te-performance-tooltip']
-});
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/performance-tooltip/template.hbs b/thirdeye/thirdeye-frontend/app/pods/components/performance-tooltip/template.hbs
deleted file mode 100644
index dbd65d3..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/components/performance-tooltip/template.hbs
+++ /dev/null
@@ -1,17 +0,0 @@
-{{#if (not-eq data.tot 0)}}
- <a class="te-anomaly-table__link" href="#">
- {{if viewTotals data.tot data.avg}}
- {{#tooltip-on-element}}
- {{category}} for <span class="te-performance-tooltip__title">{{data.name}}</span><br>
- <ul class="te-performance-tooltip__list">
- <li class="te-performance-tooltip__item"><span class="te-performance-tooltip__category">Total: </span>{{data.tot}}</li>
- <li class="te-performance-tooltip__item"><span class="te-performance-tooltip__category">Avg: </span>{{data.avg}}</li>
- <li class="te-performance-tooltip__item"><span class="te-performance-tooltip__category">Min: </span>{{data.min}}</li>
- <li class="te-performance-tooltip__item"><span class="te-performance-tooltip__category">Max: </span>{{data.max}}</li>
- <li class="te-performance-tooltip__item"><span class="te-performance-tooltip__category">Standard deviation: </span>{{data.std}}</li>
- </ul>
- {{/tooltip-on-element}}
- </a>
-{{else}}
- {{if viewTotals data.tot data.avg}}
-{{/if}}
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/self-serve-alert-yaml-details/component.js b/thirdeye/thirdeye-frontend/app/pods/components/self-serve-alert-yaml-details/component.js
index 95e8a09..8b5aebb 100644
--- a/thirdeye/thirdeye-frontend/app/pods/components/self-serve-alert-yaml-details/component.js
+++ b/thirdeye/thirdeye-frontend/app/pods/components/self-serve-alert-yaml-details/component.js
@@ -2,7 +2,7 @@
* This component displays an alert summary section for users to see alert properties at a glance.
* Initially used for consistency in both alert index page and single alert details page.
* We use slightly different sub class names for positioning based on use case.
- * @module components/self-serve-alert-details
+ * @module components/self-serve-alert-yaml-details
* @property {Object} alertData - alert properties
* @property {Boolean} isLoadError - was there an error loading the data
* @property {String} displayMode - is the use case part of a list or standalone? 'list' || 'single'
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/self-serve-graph/component.js b/thirdeye/thirdeye-frontend/app/pods/components/self-serve-graph/component.js
deleted file mode 100644
index da87a9b..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/components/self-serve-graph/component.js
+++ /dev/null
@@ -1,114 +0,0 @@
-/**
- * Wrapper component for the anomaly-graph component as used in the self-serve flow.
- * It handles presentation of the graph under various loading and error conditions.
- * @module components/self-serve-graph
- * @property {Boolean} isMetricDataLoading - is primary metric data still loading
- * @property {Boolean} isMetricDataInvalid - has the metric data been found to be not graphable
- * @property {Boolean} isDimensionFetchDone - are we done preparing dimension data
- * @property {Boolean} isSecondaryDataLoading - loads spinner if peripheral data load is made
- * @property {Boolean} removeGraphMargin - render with or without extra margins
- * @property {Object} metricData - primary metric data
- * @property {Array} topDimensions - top x dimensions to load aside from primary metric
- * @property {String} componentId - id for the graph wrapper element
- * @example
- {{self-serve-graph
- isMetricDataLoading=false
- isMetricDataInvalid=false
- isDimensionFetchDone=false
- metricData=metricData
- topDimensions=topDimensions
- componentId='create-alert'
- }}
- * @exports self-serve-graph
- * @author smcclung
- */
-
-import Component from '@ember/component';
-import { computed, set } from '@ember/object';
-
-export default Component.extend({
- classNames: ['col-xs-12', 'te-graph-container'],
- classNameBindings: ['removeGraphMargin:te-graph-container--marginless'],
- isMetricDataLoading: true,
- isMetricDataInvalid: false,
- isDimensionFetchDone: false,
- isSecondaryDataLoading: false,
- metricData: {},
- topDimensions: [],
- componentId: '',
-
- /**
- * Standard legend settings for graph
- */
- legendText: {
- dotted: {
- text: 'WoW'
- },
- solid: {
- text: 'Observed'
- }
- },
-
- /**
- * All selected dimensions to be loaded into graph
- * @returns {Array}
- */
- selectedDimensions: computed(
- 'topDimensions',
- 'topDimensions.@each.isSelected',
- function() {
- const topDimensions = this.get('topDimensions');
- return topDimensions ? this.get('topDimensions').filterBy('isSelected') : [];
- }
- ),
-
- /**
- * Determines pending state of graph
- * @returns {Boolean}
- */
- isMetricDataPending: computed(
- 'isMetricSelected',
- 'isMetricDataLoading',
- 'isMetricDataInvalid',
- function() {
- const {
- isMetricSelected,
- isMetricDataLoading
- } = this.getProperties('isMetricSelected', 'isMetricDataLoading');
- return !this.get('isMetricSelected') || this.get('isMetricDataLoading') || this.get('isMetricDataInvalid');
- }
- ),
-
- /**
- * Determines whether peripheral data for the graph is loading
- * @returns {Boolean}
- */
- isAnythingLoading: computed.or('isMetricDataLoading', 'isSecondaryDataLoading'),
-
- /**
- * Sets the message text over the graph placeholder before data is loaded
- * @method graphMessageText
- * @return {String} the appropriate graph placeholder text
- */
- graphMessageText: computed(
- 'isMetricDataInvalid',
- function() {
- const defaultMsg = 'Graph will appear here when data is loaded...';
- const invalidMsg = 'Sorry, I\'m not able to load data for this metric';
- return this.get('isMetricDataInvalid') ? invalidMsg : defaultMsg;
- }
- ),
-
- actions: {
- /**
- * Enable reaction to dimension toggling in graph legend component
- * @method onSelection
- * @return {undefined}
- */
- onSelection(selectedDimension) {
- const { isSelected } = selectedDimension;
- set(selectedDimension, 'isSelected', !isSelected);
- }
- }
-
-});
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/self-serve-graph/template.hbs b/thirdeye/thirdeye-frontend/app/pods/components/self-serve-graph/template.hbs
deleted file mode 100644
index 05146d6..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/components/self-serve-graph/template.hbs
+++ /dev/null
@@ -1,38 +0,0 @@
-<div class="te-graph-alert {{if isMetricDataPending 'te-graph-alert--pending'}}">
- {{#if (and (or isFetchingDimensions isDimensionFetchDone) isTopDimensionsAllowed)}}
- {{#if isDimensionError}}
- <div class="te-form__super-label">... error loading subDimensions for <span class="stronger">{{selectedDimension}}</span></div>
- {{else}}
- <div class="te-form__super-label">...{{if isDimensionFetchDone 'Displaying' 'Loading'}} top {{topDimensions.length}} contributing subDimensions for <span class="stronger">{{selectedDimension}}</span></div>
- {{/if}}
- {{/if}}
- {{#if isAnythingLoading}} <div class="spinner-wrapper-self-serve">{{ember-spinner}}</div> {{/if}}
- {{#if (or isMetricDataPending isMetricDataInvalid)}}
- <div class="te-graph-alert__content">
- <div class="glyphicon glyphicon-{{if isMetricDataInvalid 'alert' 'equalizer'}} te-graph-alert__icon{{if isMetricDataInvalid '--warning'}}"></div>
- <p class="te-graph-alert__pre-text">{{graphMessageText}}</p>
- </div>
- {{else}}
- {{#if (not isMetricDataInvalid)}}
- {{anomaly-graph
- primaryMetric=metricData
- selectedDimensions=selectedDimensions
- dimensions=topDimensions
- showDimensions=false
- isLoading=loading
- showSubchart=true
- showLegend=false
- enableZoom=true
- legendText=legendText
- componentId=componentId
- showGraphLegend=false
- onSelection=(action "onSelection")
- }}
- {{/if}}
- {{/if}}
-</div>
-{{#if (or isMetricDataInvalid isMetricSelected)}}
- <div class="te-form__note">
- NOTE: If you find the metric shown above is inconsistent, please email <a class="thirdeye-link-secondary" target="_blank" href="{{graphMailtoLink}}">ask_thirdeye</a>.
- </div>
-{{/if}}
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/thirdeye-chart/component.js b/thirdeye/thirdeye-frontend/app/pods/components/thirdeye-chart/component.js
deleted file mode 100644
index de8e728..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/components/thirdeye-chart/component.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import chartComponent from 'ember-c3/components/c3-chart';
-
-/**
- * Extended the c3-chart component so that we will have access to
- * the chart and its internal API
- */
-export default chartComponent.extend({
-});
diff --git a/thirdeye/thirdeye-frontend/app/pods/components/thirdeye-chart/template.hbs b/thirdeye/thirdeye-frontend/app/pods/components/thirdeye-chart/template.hbs
deleted file mode 100644
index 889d9ee..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/components/thirdeye-chart/template.hbs
+++ /dev/null
@@ -1 +0,0 @@
-{{yield}}
diff --git a/thirdeye/thirdeye-frontend/app/pods/custom/anomalies-table/rule/template.hbs b/thirdeye/thirdeye-frontend/app/pods/custom/anomalies-table/rule/template.hbs
index 82a260b..4329fa8 100644
--- a/thirdeye/thirdeye-frontend/app/pods/custom/anomalies-table/rule/template.hbs
+++ b/thirdeye/thirdeye-frontend/app/pods/custom/anomalies-table/rule/template.hbs
@@ -9,7 +9,7 @@
}}
{{#if isDeleteSuccess}}
{{#bs-alert type="success" class="te-form__banner te-form__banner--success"}}
- <strong>Success:</strong> Anomaly reported. Refresh page to see new anomalies...
+ <strong>Success:</strong> Anomaly deleted. Refresh page to see new anomalies...
{{/bs-alert}}
{{/if}}
diff --git a/thirdeye/thirdeye-frontend/app/pods/example/controller.js b/thirdeye/thirdeye-frontend/app/pods/example/controller.js
deleted file mode 100644
index 095d5d6..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/example/controller.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import Controller from '@ember/controller';
-
-export default Controller.extend({
- splitView: false,
- actions: {
- onToggleSplitView() {
- this.toggleProperty('splitView');
- }
- }
-});
diff --git a/thirdeye/thirdeye-frontend/app/pods/example/route.js b/thirdeye/thirdeye-frontend/app/pods/example/route.js
deleted file mode 100644
index 803e0d4..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/example/route.js
+++ /dev/null
@@ -1,32 +0,0 @@
-import { inject as service } from '@ember/service';
-import Route from '@ember/routing/route';
-import { Actions as AnomalyActions } from 'thirdeye-frontend/actions/anomaly';
-
-export default Route.extend({
- redux: service(),
- session: service(),
-
- model(params) {
- const { id } = params;
- const redux = this.get('redux');
-
- redux.dispatch(AnomalyActions.fetchData(id));
- return {};
- },
-
- actions: {
- /**
- * save session url for transition on login
- * @method willTransition
- */
- willTransition(transition) {
- //saving session url - TODO: add a util or service - lohuynh
- if (transition.intent.name && transition.intent.name !== 'logout') {
- this.set('session.store.fromUrl', {lastIntentTransition: transition});
- }
- },
- error() {
- return true;
- }
- }
-});
diff --git a/thirdeye/thirdeye-frontend/app/pods/example/template.hbs b/thirdeye/thirdeye-frontend/app/pods/example/template.hbs
deleted file mode 100644
index 996120c..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/example/template.hbs
+++ /dev/null
@@ -1,23 +0,0 @@
-{{#containers/anomaly-container as |anomalyList actions|}}
- {{#if anomalyList.loading}}
- Loading...
- {{/if}}
-
- {{#if anomalyList.failed}}
- Oops, something went wrong...
- {{/if}}
-
- {{#if anomalyList.loaded}}
- {{#if anomalyList.anomaly}}
- <section class="anomaly-title-bar">
- {{anomaly-id anomaly=anomalyList.anomaly}}
- </section>
- <main class="anomaly-content container">
- <h1>Example</h1>
- <p>This is a placeholder example page for the new ember app utilizing ember-redux and connecting to the back end at localhost:1426</p>
- </main>
- {{else}}
- No anomalies found.
- {{/if}}
- {{/if}}
-{{/containers/anomaly-container}}
diff --git a/thirdeye/thirdeye-frontend/app/pods/manage/alerts/performance/controller.js b/thirdeye/thirdeye-frontend/app/pods/manage/alerts/performance/controller.js
deleted file mode 100644
index 0f268a2..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/manage/alerts/performance/controller.js
+++ /dev/null
@@ -1,101 +0,0 @@
-import _ from 'lodash';
-import moment from 'moment';
-import { computed, set } from '@ember/object';
-import Controller from '@ember/controller';
-import { inject as service } from '@ember/service';
-
-export default Controller.extend({
-
- /**
- * Make duration service accessible
- */
- durationCache: service('services/duration'),
-
- /**
- * Active class appendage of 'view totals' link
- * @type {String}
- */
- viewTotalsState: computed('viewTotals', function() {
- return this.get('viewTotals') ? 'active' : 'inactive';
- }),
-
- /**
- * Active class appendage of 'view average' link
- * @type {String}
- */
- viewAvgState: computed('viewTotals', function() {
- return !this.get('viewTotals') ? 'active' : 'inactive';
- }),
-
- /**
- * List of applications to render as rows, with filtering applied
- * @type {Array}
- */
- applications: computed(
- 'perfDataByApplication',
- 'selectedSortMode',
- 'viewTotals',
- 'sortMap',
- function() {
- const sortMap = this.get('sortMap');
- const selectedSortMode = this.get('selectedSortMode');
- const sortMapChild = this.get('viewTotals') ? '.tot' : '.avg';
- const keysWithChildren = ['anomaly', 'user', 'responses'];
- let allApps = this.get('perfDataByApplication');
- let fullSortKey = '';
- let applySortType = true;
-
- if (selectedSortMode) {
- let [ sortKey, sortDir ] = selectedSortMode.split(':');
- applySortType = keysWithChildren.includes(sortKey);
- fullSortKey = applySortType ? sortMap[sortKey] + sortMapChild : sortMap[sortKey];
-
- if (sortDir === 'up') {
- allApps = _.sortBy(allApps, fullSortKey);
- } else {
- allApps = _.sortBy(allApps, fullSortKey).reverse();
- }
- }
-
- return allApps;
- }
- ),
-
- actions: {
-
- /**
- * Sets the new custom date range for anomaly coverage
- * @method onRangeSelection
- * @param {Object} rangeOption - the user-selected time range to load
- */
- onRangeSelection(rangeOption) {
- const {
- start,
- end,
- value: duration
- } = rangeOption;
- const durationObj = {
- duration,
- startDate: moment(start).valueOf(),
- endDate: moment(end).valueOf()
- };
- // Cache the new time range and update page with it
- this.get('durationCache').setDuration(durationObj);
- this.transitionToRoute({ queryParams: durationObj });
- },
-
- /**
- * Handle sorting for each sortable table column
- * @param {String} sortKey - stringified start date
- */
- toggleSortDirection(sortKey) {
- const sortMenu = this.get('sortMenuGlyph');
- const propName = 'sortColumn' + sortKey.capitalize() + 'Up' || '';
- let direction = '';
- this.toggleProperty(propName);
- direction = this.get(propName) ? 'up' : 'down';
- set(sortMenu, sortKey, direction);
- this.set('selectedSortMode', `${sortKey}:${direction}`);
- }
- }
-});
diff --git a/thirdeye/thirdeye-frontend/app/pods/manage/alerts/performance/route.js b/thirdeye/thirdeye-frontend/app/pods/manage/alerts/performance/route.js
deleted file mode 100644
index 548b23b..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/manage/alerts/performance/route.js
+++ /dev/null
@@ -1,348 +0,0 @@
-/**
- * Handles the 'create alert' route nested in the 'manage' route.
- * @module self-serve/create/route
- * @exports alert create model
- */
-
-import fetch from 'fetch';
-import moment from 'moment';
-import Route from '@ember/routing/route';
-import {
- hash,
- allSettled
-} from 'rsvp';
-import { getWithDefault } from '@ember/object';
-import {
- checkStatus,
- buildDateEod
-} from 'thirdeye-frontend/utils/utils';
-import { isPresent } from '@ember/utils';
-import { setUpTimeRangeOptions } from 'thirdeye-frontend/utils/manage-alert-utils';
-import { inject as service } from '@ember/service';
-
-/**
- * If true, this reduces the list of alerts per app to 2 for a quick demo.
- */
-const isDemoMode = false;
-
-/**
- * Mapping anomaly table column names to corresponding prop keys
- */
-const sortMap = {
- name: 'name',
- alert: 'alerts',
- anomaly: 'data.totalAlerts',
- user: 'data.userReportAnomaly',
- responses: 'data.totalResponses',
- resrate: 'data.responseRate',
- precision: 'data.precision'
-};
-
-/**
- * Time range-related constants
- */
-const displayDateFormat = 'YYYY-MM-DD HH:mm';
-const durationMap = { m:'month', d:'day', w:'week' };
-const defaultDurationObj = {
- duration: '3m',
- startDate: buildDateEod(3, 'month').valueOf(),
- endDate: moment()
-};
-
-/**
- * Fetches all anomaly data for found anomalies - downloads all 'pages' of data from server
- * in order to handle sorting/filtering on the entire set locally. Start/end date are not used here.
- * @param {Array} anomalyIds - list of all found anomaly ids
- * @return {Ember.RSVP promise}
- */
-const fetchAppAnomalies = (alertList, startDate, endDate) => {
- const alertPromises = [];
- const filteredStartDate = moment(Number(startDate)).toISOString();
- const filteredEndDate = moment(Number(endDate)).toISOString();
- const tuneParams = `start=${filteredStartDate}&end=${filteredEndDate}`;
-
- alertList.forEach((alert) => {
- let { name, id } = alert;
- let getAlertPerfHash = {
- id,
- name,
- data: fetch(`/detection-job/eval/filter/${alert.id}?${tuneParams}`).then(checkStatus)
- };
- alertPromises.push(hash(getAlertPerfHash));
- });
-
- return allSettled(alertPromises);
-};
-
-/**
- * Associate each anomaly with an application name. This is done by:
- * 1) For each existing application, find all alert groups associated with it
- * 2) Add the app name to each of the group's function Ids (making sure we don't duplicate an Id)
- * @param {Array} allApps - list of all applications
- * @param {Array} validGroups - all alert groups that are active
- * @returns {Array} appBucket
- */
-const fillAppBuckets = (allApps, validGroups) => {
- let appBucket = [];
-
- allApps.forEach((app) => {
- let associatedGroups = validGroups.filter(group => group.application.includes(app.application));
- if (associatedGroups.length) {
- let uniqueIds = Array.from(new Set([].concat(...associatedGroups.map(group => group.emailConfig.functionIds))));
- if (isDemoMode) {
- uniqueIds = uniqueIds.slice(0, 1);
- }
- if (uniqueIds.length) {
- uniqueIds.forEach((id) => {
- appBucket.push({ name: app.application, id });
- });
- }
- }
- });
-
- return appBucket;
-};
-
-/**
- * Simply average the given array of numbers
- * @param {Array} values - all values to average
- * @returns {Number} average value
- */
-const average = (values) => {
- return (values.reduce((total, amount) => amount += total))/values.length;
-};
-
-/**
- * Check whether there are any fetch promise failures
- * @param {Array} data - all settled RSVP promises
- * @returns {Boolean} true if a failure was found
- */
-const isPromiseRejected = (data) => {
- return data.map(obj => obj.state).some(state => state === 'rejected');
-};
-
-/**
- * Calculate the standard deviation, or variance in the given array
- * @param {Array} values - all values to average
- * @returns {Number} standard deviation
- */
-const standardDeviation = (values) => {
- let avg = average(values);
-
- let squareDiffs = values.map((value) => {
- let diff = value - avg;
- let sqrDiff = diff * diff;
- return sqrDiff;
- });
-
- let avgSquareDiff = average(squareDiffs);
- let stdDev = Math.sqrt(avgSquareDiff);
- return stdDev;
-};
-
-/**
- * Derive the response or precision rate for a set of anomalies
- * @param {Array} anomalies - all anomalies in a given application
- * @param {Number} subset - the target subset (true anomalies, false, etc)
- * @returns {Number} a percentage
- */
-const calculateRate = (anomalies, subset) => {
- let percentage = 0;
- if (anomalies && subset) {
- percentage = (subset * 100) / anomalies;
- }
- return Number(percentage.toFixed());
-};
-
-/**
- * Setup for query param behavior
- */
-const queryParamsConfig = {
- refreshModel: true,
- replace: true
-};
-
-export default Route.extend({
- session: service(),
- queryParams: {
- duration: queryParamsConfig,
- startDate: queryParamsConfig,
- endDate: queryParamsConfig
- },
-
- beforeModel(transition) {
- const { duration, startDate } = transition.queryParams;
- // Default to 1 month of anomalies to show if no dates present in query params
- if (!duration || !startDate) {
- this.transitionTo({ queryParams: defaultDurationObj });
- }
- },
-
- /**
- * Model hook for the create alert route.
- * @method model
- * @return {Object}
- */
- model(transition) {
- // Get duration data
- const {
- duration,
- startDate,
- endDate
- } = transition;
-
- return hash({
- // Fetch all alert group configurations
- configGroups: fetch('/thirdeye/entity/ALERT_CONFIG').then(checkStatus),
- applications: fetch('/thirdeye/entity/APPLICATION').then(checkStatus),
- duration,
- startDate,
- endDate
- });
- },
-
- afterModel(model) {
- this._super(model);
-
- const activeGroups = model.configGroups.filterBy('active');
- const groupsWithAppName = activeGroups.filter(group => isPresent(group.application));
- const groupsWithAlertId = groupsWithAppName.filter(group => group.emailConfig.functionIds.length > 0);
- const filteredGroups = isDemoMode ? groupsWithAlertId.slice(0, 3) : groupsWithAlertId;
- const idsByApplication = fillAppBuckets(model.applications, filteredGroups);
- Object.assign(model, { idsByApplication });
- },
-
- setupController(controller, model) {
- this._super(controller, model);
-
- const {
- idsByApplication,
- startDate,
- endDate,
- duration
- } = model;
-
- // Display loading banner
- controller.setProperties({
- timeRangeOptions: setUpTimeRangeOptions(['1m', '3m'], duration),
- activeRangeStart: moment(Number(startDate)).format(displayDateFormat),
- activeRangeEnd: moment(Number(endDate)).format(displayDateFormat),
- uiDateFormat: "MMM D, YYYY hh:mm a",
- timePickerIncrement: 5,
- isDataLoading: true
- });
-
- // Get perf data for each alert and assign it to the model
- fetchAppAnomalies(idsByApplication, startDate, endDate)
- .then((richFunctionObjects) => {
- const newFunctionObjects = richFunctionObjects.filter(obj => obj.state === 'fulfilled').map(obj => obj.value);
- const availableGroups = Array.from(new Set(newFunctionObjects.map(alertObj => alertObj.name)));
- const roundable = ['totalAlerts', 'totalResponses', 'falseAlarm', 'newTrend', 'trueAnomalies', 'userReportAnomaly'];
- let sortMenuGlyph = {};
- let newGroupArr = [];
- let count = 0;
-
- // Filter down to functions belonging to our active application groups
- availableGroups.forEach((group) => {
- let avgData = {};
- let keyData = {};
- let groupData = newFunctionObjects.filter((alert) => {
- return alert.name === group;
- });
-
- // Get array of keys from first record
- let metricKeys = Object.keys(groupData[0].data);
- let getTotalValue = (key) => getWithDefault(avgData, key, 0);
- count++;
-
- // Look at each anomaly's perf object keys. For our "roundable" fields, get derived data
- metricKeys.forEach((key) => {
- let isRawValue = roundable.includes(key);
- let allValues = groupData.map(group => group.data[key]);
- let allNumeric = allValues.every(val => !Number.isNaN(Number(val)));
- let total = allValues.reduce((total, amount) => amount += total);
- avgData[key] = {};
-
- if (allNumeric && isRawValue) {
- let avg = total/allValues.length;
- avgData[key].avg = Math.round(avg);
- avgData[key].tot = total;
- avgData[key].max = Math.max(...allValues);
- avgData[key].min = Math.min(...allValues);
- avgData[key].std = standardDeviation(allValues).toFixed(2);
- avgData[key].name = group;
- } else {
- let avg = total/(allValues.filter(Number)).length;
- avgData[key].avg = !Number.isNaN(Number(avg)) ? `${(avg * 100).toFixed(1)}` : 'N/A';
- avgData[key].tot = 'N/A';
- }
- avgData[key].values = allValues;
- });
-
- // Gather totals and make custom calculations
- let pTrue = getTotalValue('trueAnomalies.tot');
- let pNew = getTotalValue('newTrend.tot');
- let pFalse = getTotalValue('falseAlarm.tot');
- let rResponses = getTotalValue('totalResponses.tot');
- let rTotal = getTotalValue('totalAlerts.tot');
- let precisionTotal = pTrue + pNew + pFalse;
- avgData['responseRate'] = avgData['responseRate'] ? calculateRate(rTotal, rResponses) : 'N/A';
- avgData['precision'] = avgData['precision'] ? calculateRate(precisionTotal, pTrue + pNew) : 'N/A';
-
- // Add perf data to application groups array
- newGroupArr.push({
- name: isDemoMode ? `group ${count}` : group,
- data: avgData,
- alerts: groupData.length
- });
- });
-
- // Initialize glyph icons for each table column
- for (var key in sortMap) {
- sortMenuGlyph[key] = 'down';
- }
-
- // Pass perf data and state to controller
- controller.setProperties({
- sortMap,
- sortMenuGlyph,
- viewTotals: true,
- isDataLoading: false,
- isDataLoadingError: false,
- perfDataByApplication: newGroupArr
- });
-
- })
- .catch((errMsg) => {
- controller.setProperties({
- isDataLoadingError: true,
- errMsg
- });
- });
- },
-
- actions: {
- /**
- * save session url for transition on login
- * @method willTransition
- */
- willTransition(transition) {
- //saving session url - TODO: add a util or service - lohuynh
- if (transition.intent.name && transition.intent.name !== 'logout') {
- this.set('session.store.fromUrl', {lastIntentTransition: transition});
- }
- },
- error() {
- return true;
- },
-
- /**
- * Refresh route's model.
- * @method refreshModel
- * @return {undefined}
- */
- refreshModel() {
- this.refresh();
- }
- }
-});
diff --git a/thirdeye/thirdeye-frontend/app/pods/manage/alerts/performance/template.hbs b/thirdeye/thirdeye-frontend/app/pods/manage/alerts/performance/template.hbs
deleted file mode 100644
index 9a00a55..0000000
--- a/thirdeye/thirdeye-frontend/app/pods/manage/alerts/performance/template.hbs
+++ /dev/null
@@ -1,140 +0,0 @@
-{{#if isDataLoading}}
- <div class="te-alert-page-pending">
- <img src="{{rootURL}}assets/images/te-alert-{{if isDataLoadingError "error" "pending"}}.png" class="te-alert-page-pending__image {{if isDataLoadingError "te-alert-page-pending__image--error"}}" alt="alertData.Setup is Processing">
- <h2 class="te-alert-page-pending__title">{{if isDataLoadingError "Oops, something went wrong." "Aggregating anomaly performance data..."}}</h2>
- {{#if (not isDataLoadingError)}}<div class="te-alert-page-pending__loader"></div>{{/if}}
- <p class="te-alert-page-pending__text">
- {{#if isDataLoadingError}}
- The performance data cannot be retrieved.<br/>{{errMsg}}
- {{else}}
- Fetching all app-related anomaly data for all alerts may take up to a minute. <br/>Hang in there!
- {{/if}}
- </p>
- </div>
-{{else}}
- <div class="manage-alert-tune">
-
- {{!-- Date range selector --}}
- {{range-pill-selectors
- title="Select Time Range"
- uiDateFormat=uiDateFormat
- activeRangeEnd=activeRangeEnd
- activeRangeStart=activeRangeStart
- timeRangeOptions=timeRangeOptions
- timePickerIncrement=timePickerIncrement
- selectAction=(action "onRangeSelection")
- }}
-
- <div class="te-content-block">
- <h4 class="te-alert-page__subtitle">Alert Performance by Application Group</h4>
- <a class="te-self-serve__side-link te-self-serve__side-link--{{viewTotalsState}}" {{action (toggle "viewTotals" this)}}>View total values</a>
- <a class="te-self-serve__side-link te-self-serve__side-link--{{viewAvgState}}" {{action (toggle "viewTotals" this)}}>View average values</a>
- {{!-- Alert anomaly table --}}
- <table class="te-anomaly-table te-anomaly-table--performance">
- <thead>
- <tr class="te-anomaly-table__row te-anomaly-table__head">
- <th class="te-anomaly-table__cell-head">
- <a class="te-anomaly-table__cell-link" {{action "toggleSortDirection" "name"}}>
- Appp
- <i class="te-anomaly-table__icon te-anomaly-table__icon--small glyphicon glyphicon-menu-{{sortMenuGlyph.name}}"></i>
- </a>
- </th>
- <th class="te-anomaly-table__cell-head">
- <a class="te-anomaly-table__cell-link" {{action "toggleSortDirection" "alert"}}>
- Alerts
- <i class="te-anomaly-table__icon te-anomaly-table__icon--small glyphicon glyphicon-menu-{{sortMenuGlyph.alert}}"></i>
- </a>
- </th>
- <th class="te-anomaly-table__cell-head">
- <a class="te-anomaly-table__cell-link" {{action "toggleSortDirection" "anomaly"}}>
- Anomalies
- <i class="te-anomaly-table__icon te-anomaly-table__icon--small glyphicon glyphicon-menu-{{sortMenuGlyph.anomaly}}"></i>
- </a>
- </th>
- <th class="te-anomaly-table__cell-head">
- <a class="te-anomaly-table__cell-link" {{action "toggleSortDirection" "user"}}>
- User-rep
- <i class="te-anomaly-table__icon te-anomaly-table__icon--small glyphicon glyphicon-menu-{{sortMenuGlyph.user}}"></i>
- </a>
- </th>
- <th class="te-anomaly-table__cell-head">
- <a class="te-anomaly-table__cell-link" {{action "toggleSortDirection" "responses"}}>
- Responses
- <i class="te-anomaly-table__icon te-anomaly-table__icon--small glyphicon glyphicon-menu-{{sortMenuGlyph.responses}}"></i>
- </a>
- </th>
- <th class="te-anomaly-table__cell-head">
- <a class="te-anomaly-table__cell-link" {{action "toggleSortDirection" "resrate"}}>
- Response rate
- <i class="te-anomaly-table__icon te-anomaly-table__icon--small glyphicon glyphicon-menu-{{sortMenuGlyph.resrate}}"></i>
- </a>
- </th>
- <th class="te-anomaly-table__cell-head">
- <a class="te-anomaly-table__cell-link" {{action "toggleSortDirection" "precision"}}>
- Precision
- <i class="te-anomaly-table__icon te-anomaly-table__icon--small glyphicon glyphicon-menu-{{sortMenuGlyph.precision}}"></i>
- </a>
- </th>
- </tr>
- </thead>
-
- <tbody>
- {{#each applications as |app|}}
- <tr class="te-anomaly-table__row">
- <td class="te-anomaly-table__cell te-anomaly-table__list-item te-anomaly-table__list-item--stronger">{{app.name}}</td>
- <td class="te-anomaly-table__cell">{{app.alerts}}</td>
- <td class="te-anomaly-table__cell">
- {{performance-tooltip
- data=app.data.totalAlerts
- category="Anomalies"
- viewTotals=viewTotals
- }}
- </td>
- <td class="te-anomaly-table__cell">
- {{performance-tooltip
- data=app.data.userReportAnomaly
- category="User reported anomalies"
- viewTotals=viewTotals
- }}
- </td>
- <td class="te-anomaly-table__cell">
- <div class="te-performance-metric">
- {{performance-tooltip
- data=app.data.totalResponses
- category="Total Responses"
- viewTotals=viewTotals
- }}
- </div>
- <div class="te-performance-metric__subset">
- ( T: {{performance-tooltip
- data=app.data.trueAnomalies
- category="True anomalies"
- viewTotals=viewTotals
- }} |
- F: {{performance-tooltip
- data=app.data.falseAlarm
- category="False anomalies"
- viewTotals=viewTotals
- }} |
- N: {{performance-tooltip
- data=app.data.newTrend
- category="New trend anomalies"
- viewTotals=viewTotals
- }} )
- </div>
- </td>
- <td class="te-anomaly-table__cell">
- {{app.data.responseRate}}
- <span class="te-anomaly-table__list-item te-anomaly-table__list-item--smaller">%</span>
- </td>
- <td class="te-anomaly-table__cell">
- {{app.data.precision}}
- <span class="te-anomaly-table__list-item te-anomaly-table__list-item--smaller">%</span>
- </td>
- </tr>
- {{/each}}
- </tbody>
- </table>
- </div>
- </div>
-{{/if}}
diff --git a/thirdeye/thirdeye-frontend/app/pods/self-serve/create-alert/template.hbs b/thirdeye/thirdeye-frontend/app/pods/self-serve/create-alert/template.hbs
index 2d7165f..f5320d9 100644
--- a/thirdeye/thirdeye-frontend/app/pods/self-serve/create-alert/template.hbs
+++ b/thirdeye/thirdeye-frontend/app/pods/self-serve/create-alert/template.hbs
@@ -120,21 +120,6 @@
</div>
{{!-- Render metric graph --}}
- {{self-serve-graph
- removeGraphMargin=true
- metricData=selectedMetric
- componentId='create-alert'
- topDimensions=topDimensions
- isTopDimensionsAllowed=false
- graphMailtoLink=graphMailtoLink
- selectedDimension=selectedDimension
- selectedDimensions=selectedDimensions
- isMetricSelected=isMetricSelected
- isMetricDataLoading=isMetricDataLoading
- isMetricDataInvalid=isMetricDataInvalid
- isSecondaryDataLoading=isSecondaryDataLoading
- isDimensionFetchDone=isDimensionFetchDone
- }}
</fieldset>
diff --git a/thirdeye/thirdeye-frontend/app/router.js b/thirdeye/thirdeye-frontend/app/router.js
index a9d895b..945a302 100644
--- a/thirdeye/thirdeye-frontend/app/router.js
+++ b/thirdeye/thirdeye-frontend/app/router.js
@@ -24,7 +24,7 @@ Router.map(function() {
this.route('manage', function() {
this.route('alerts', function() {
- this.route('performance');
+ this.route('index', { path: '/' });
});
this.route('explore', { path: 'explore/:alert_id'});
this.route('yaml', { path: 'yaml/:alert_id' });
diff --git a/thirdeye/thirdeye-frontend/app/styles/app.scss b/thirdeye/thirdeye-frontend/app/styles/app.scss
index 1c470dd..cca77e1 100644
--- a/thirdeye/thirdeye-frontend/app/styles/app.scss
+++ b/thirdeye/thirdeye-frontend/app/styles/app.scss
@@ -32,14 +32,10 @@ body {
// Components
@import 'components/alert-details';
-@import 'components/anomaly-id';
-@import 'components/anomaly-graph';
@import 'components/te-navbar';
@import 'components/button';
@import 'components/links';
@import 'components/filter-select';
-@import 'components/dimension-heatmap';
-@import 'components/dimension-summary';
@import 'components/heatmap-chart';
@import 'components/login-form';
@import 'components/entity-filter';
diff --git a/thirdeye/thirdeye-frontend/app/styles/components/anomaly-graph.scss b/thirdeye/thirdeye-frontend/app/styles/components/anomaly-graph.scss
deleted file mode 100644
index 93983f6..0000000
--- a/thirdeye/thirdeye-frontend/app/styles/components/anomaly-graph.scss
+++ /dev/null
@@ -1,151 +0,0 @@
-// Overriding default c3
-
-.anomaly-graph {
- box-sizing: border-box;
- display: flex;
- border: 1px solid $te-grey--border;
-
- &:not(:first-child) {
- margin-top: 14px;
- }
-
- &--no-border {
- border: 0;
- }
-
- .c3-brush .extent {
- fill: #4682b4;
- fill-opacity: .125;
- stroke: #CCC;
- }
-
- .c3-line {
- stroke-width: 2px;
- }
-
- .c3-chart-line:nth-child(even) > .c3-lines {
- stroke-dasharray: 1%;
- }
-
- .anomaly-graph__slider-line {
- stroke: white;
- stroke-width: 3;
- }
-
- .anomaly-graph__region-slider .extent{
- stroke: #fff;
- fill-opacity: .2;
- fill: $te-orange;
- }
-
- &__legend {
- position: absolute;
- top: 0;
- right: 0;
- }
-
- &__legend-item {
- display: block;
- }
-
- &__legend-line {
- stroke: $te-blue !important;
- stroke-width: 3;
-
- &--orange {
- stroke: $te-orange !important;
- }
- }
-}
-
-.anomaly-graph__filter-item {
- white-space: nowrap;
- text-overflow: ellipsis;
- overflow: hidden;
-}
-.anomaly-graph__filter-label {
- cursor: pointer;
- color: #0091CA;
- font-weight: normal;
-}
-
-.anomaly-graph__filter-group {
- padding-left: 14px;
- margin: 14px 0;
- list-style: none;
- &--hidden {
- height: 0;
- overflow: hidden;
- margin: 0;
- }
-}
-
-.anomaly-graph__title {
- @include margin-reset;
- @include padding-reset;
- font-size: initial;
- font-weight: normal;
- margin-bottom: 14px;
-}
-
-.legend-title {
- padding: 14px;
- color: rgba(0,0,0, 0.55);
- margin: 0;
- background-color: #F3F6F8;
- font-size: 14px;
- font-weight: 600;
- position: sticky;
- top: 0;
-}
-
-.legend-cta {
- color: rgba(0, 0, 0, 0.30);
-}
-
-.anomaly-graph__left-panel {
- min-width: 250px;
- flex-grow: 1;
- overflow: scroll;
- position: relative;
- border-right: 1px solid $te-grey--border;
-}
-
-.anomaly-graph__right-panel {
- position: relative;
- flex-basis: 75%;
- flex-grow: 1;
- width: 75%;
- padding: 14px;
-}
-
-.anomaly_graph__filters {
- position: absolute;
- top: 0;
- bottom: 0;
- right: 0;
- left: 0;
-}
-
-
-$colors:
- "blue" $te-blue,
- "orange" $te-orange,
- "teal" $te-teal,
- "purple" $te-purple,
- "red" $te-red,
- "green" $te-green,
- "pink" $te-pink,
- "grey" $te-grey,
- "dark-orange" #B74700;
-
-// creates .c3-region-"color" classes
-@each $i in $colors{
- .c3-region--#{nth($i, 1)} {
- fill: nth($i, 2);
- }
-
- .anomaly-graph__filter-label--#{nth($i, 1)} {
- color: lighten(nth($i, 2), 10%);
- }
-};
diff --git a/thirdeye/thirdeye-frontend/app/styles/components/anomaly-id.scss b/thirdeye/thirdeye-frontend/app/styles/components/anomaly-id.scss
deleted file mode 100644
index b98f61f..0000000
--- a/thirdeye/thirdeye-frontend/app/styles/components/anomaly-id.scss
+++ /dev/null
@@ -1,32 +0,0 @@
-.anomaly-id {
- list-style: none;
- font-size: $te-font-size-medium;
- font-weight: 300;
- width: 100%;
- padding: 20px 0;
-
- &__item {
- line-height: $te-list-line-height;
-
- &--title {
- font-size: $te-font-size-component-title;
- }
-
- &--value {
- font-size: $te-font-size-medium;
- font-weight: normal;
- }
- }
-
- &__subtitle {
- font-weight: normal;
- }
-
- &__total {
- font-weight: bold;
- }
-
- &__percent {
- color: $anomaly-id-percent-change;
- }
-}
diff --git a/thirdeye/thirdeye-frontend/app/styles/components/dimension-heatmap.scss b/thirdeye/thirdeye-frontend/app/styles/components/dimension-heatmap.scss
deleted file mode 100644
index 71ef52f..0000000
--- a/thirdeye/thirdeye-frontend/app/styles/components/dimension-heatmap.scss
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copy paste from the old Thirdeye UI
-.dimension-heatmap {
- margin-top: 24px;
-}
-
-.dimension-heatmap__table {
- margin-bottom: 0;
-}
-
-.heatmap {
- background-color: #f5f5f5;
-}
-
-.analysis-tooltip {
- font-size: 14px;
-}
-
-.analysis-tooltip__header {
- font-weight: bold;
-}
-
-.analysis-tooltip__column {
- text-align: right;
-}
-
-.analysis-tooltip__column-header {
- text-align: left;
-}
-
-.analysis-tooltip__container {
- width: 400px;
-}
-
-.analysis-tooltip__list {
- list-style: none;
- margin-bottom: 0;
- padding-left: 0;
-}
-
-.analysis-tooltip__list-item {
- display: flex;
- justify-content: space-between;
-}
-
-#tooltip,
-#heatmap-tooltip {
- position: absolute;
- min-width: 300px;
- height: auto;
- padding: 10px;
- background-color: white;
- -webkit-border-radius: 10px;
- -moz-border-radius: 10px;
- border-radius: 10px;
- -webkit-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
- -moz-box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
- box-shadow: 4px 4px 10px rgba(0, 0, 0, 0.4);
- pointer-events: none;
-
- &.hidden {
- display: none;
- }
-
- & p {
- margin: 0;
- font-size: 13px;
- }
-}
-
diff --git a/thirdeye/thirdeye-frontend/app/styles/components/dimension-summary.scss b/thirdeye/thirdeye-frontend/app/styles/components/dimension-summary.scss
deleted file mode 100644
index fb105fc..0000000
--- a/thirdeye/thirdeye-frontend/app/styles/components/dimension-summary.scss
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copy paste from old Thirdeye UI
-.dimension-summary {
- display: flex;
- justify-content: space-between;
-}
-.dimension-summary__label {
- text-transform: uppercase;
- color: rgba(0,0,0,.55);
- font-weight: normal;
-}
-
-.dimension-summary__item {
- display: flex;
- flex-direction: column;
- justify-content: space-between;
-}
-
-.dimension-summary__data {
- font-size: 18px;
- color: rgba(0,0,0,.70);
- margin-top: 0;
-
- &--positive {
- color: #398b18;
- }
-
- &--negative {
- color: #ee1620;
- }
-}
diff --git a/thirdeye/thirdeye-frontend/app/styles/pods/manage/alerts-performance.scss b/thirdeye/thirdeye-frontend/app/styles/pods/manage/alerts-performance.scss
index 8566192..e62be78 100644
--- a/thirdeye/thirdeye-frontend/app/styles/pods/manage/alerts-performance.scss
+++ b/thirdeye/thirdeye-frontend/app/styles/pods/manage/alerts-performance.scss
@@ -1,23 +1,3 @@
-.te-performance-tooltip {
- display: inline-block;
-
- &__title {
- text-transform: uppercase;
- }
- &__list {
- padding-left: 0;
- margin-top: 5px;
- max-width: 400px;
- }
- &__item {
- list-style: none;
- }
- &__category {
- color: app-shade(white, 5);
- padding-right: 7px;
- }
-}
-
.te-performance-metric {
width: 20px;
text-align: right;
diff --git a/thirdeye/thirdeye-frontend/tests/integration/pods/components/anomaly-graph/component-test.js b/thirdeye/thirdeye-frontend/tests/integration/pods/components/anomaly-graph/component-test.js
deleted file mode 100644
index 3d881cb..0000000
--- a/thirdeye/thirdeye-frontend/tests/integration/pods/components/anomaly-graph/component-test.js
+++ /dev/null
@@ -1,23 +0,0 @@
-// TODO: [THIRDEYE-1796] Fix failing tests
-// import { moduleForComponent, test } from 'ember-qunit';
-// import hbs from 'htmlbars-inline-precompile';
-
-// moduleForComponent('anomaly-graph', 'Integration | Component | anomaly graph', {
-// integration: true
-// });
-
-// test('it renders', function(assert) {
-// const selector = '.anomaly-graph';
-// const anomaly = {
-// dates: ['2017-01-01 10:00', '2017-01-02 10:00', '2017-01-03 10:00'],
-// currentValues: [1,2,3],
-// baselineValues: [4,5,6],
-// anomalyRegionStart: '2017-01-01 10:00',
-// anomalyRegionEnd: '2017-01-03 10:00',
-// metricName: 'test_metric'
-// };
-// this.set('anomaly', anomaly);
-// this.render(hbs`{{anomaly-graph anomaly=anomaly}}`);
-
-// assert.ok(this.$(selector).length, 'anomaly graph renders correctly');
-// });
diff --git a/thirdeye/thirdeye-frontend/tests/integration/pods/components/anomaly-id/component-test.js b/thirdeye/thirdeye-frontend/tests/integration/pods/components/anomaly-id/component-test.js
deleted file mode 100644
index 2916e7e..0000000
--- a/thirdeye/thirdeye-frontend/tests/integration/pods/components/anomaly-id/component-test.js
+++ /dev/null
@@ -1,55 +0,0 @@
-import { module, test } from 'qunit';
-import { setupRenderingTest } from 'ember-qunit';
-import { render } from '@ember/test-helpers';
-import hbs from 'htmlbars-inline-precompile';
-import floatToPercent from 'thirdeye-frontend/utils/float-to-percent';
-
-module('Integration | Component | anomaly id', function(hooks) {
- setupRenderingTest(hooks);
-
- const idSelector = '.anomaly-id__id';
- const nameSelector = '.anomaly-id__name';
- const currentValueSelector = '.anomaly-id__total';
- const changeRateSelector = '.anomaly-id__percent';
- const anomalyId = 20475;
- const anomalyCurrentValue = 10;
- const anomalyBaselineValue = 2;
- const anomaly = {
- anomalyIds: anomalyId,
- current: anomalyCurrentValue,
- baseline: anomalyBaselineValue,
- anomalyFunctionName: 'some-function-name'
- };
- const calculateChangeRate = (current, baseline) => {
- return (baseline === 0) ? 0 : floatToPercent((current - baseline) / baseline);
- };
-
- // Test for proper rendering of all Anomaly ID Block data
- test('Anomaly ID block: all meta properties render', async function(assert) {
- let changeRate = calculateChangeRate(anomaly.current, anomaly.baseline);
-
- // this.set('anomaly', anomaly);
- // this.set('anomalyChangeRate', changeRate);
- this.setProperties({ 'anomaly': anomaly, 'anomalyChangeRate': changeRate });
- await render(hbs`{{anomaly-id anomaly=anomaly}}`);
-
- assert.equal(this.$(idSelector).text().trim(), anomalyId, 'The anomaly id is correct and renders');
- assert.equal(this.$(nameSelector).text().trim(), anomaly.anomalyFunctionName, 'The anomaly name is correct and renders');
- assert.equal(this.$(currentValueSelector).text().trim(), anomaly.current, 'The current value is correct and renders');
- assert.equal(this.$(changeRateSelector).text().trim(), '(' + changeRate + '%)', 'The change rate is correct and renders');
- });
-
- // Now test for proper handling of a zero-value for baseline. In this case, percent change
- // cannot be calculated - we should return and display '0'
- test('Anomaly ID block: render correct change rate for zero baseline', async function(assert) {
- anomaly.baseline = 0;
- let changeRate = calculateChangeRate(anomaly.current, anomaly.baseline);
-
- // this.set('anomaly', anomaly);
- // this.set('anomalyChangeRate', changeRate);
- this.setProperties({ 'anomaly': anomaly, 'anomalyChangeRate': changeRate });
- await render(hbs`{{anomaly-id anomaly=anomaly}}`);
-
- assert.equal(this.$(changeRateSelector).text().trim(), '(' + changeRate + '%)', 'The change rate handles a zero baseline correctly');
- });
-});
diff --git a/thirdeye/thirdeye-frontend/tests/integration/pods/components/thirdeye-chart/component-test.js b/thirdeye/thirdeye-frontend/tests/integration/pods/components/thirdeye-chart/component-test.js
deleted file mode 100644
index e729d2f..0000000
--- a/thirdeye/thirdeye-frontend/tests/integration/pods/components/thirdeye-chart/component-test.js
+++ /dev/null
@@ -1,26 +0,0 @@
-// TODO: [THIRDEYE-1796] Fix failing tests
-// import { moduleForComponent, test } from 'ember-qunit';
-// import hbs from 'htmlbars-inline-precompile';
-
-// moduleForComponent('thirdeye-chart', 'Integration | Component | thirdeye chart', {
-// integration: true
-// });
-
-// test('it renders', function(assert) {
-
-// // Set any properties with this.set('myProperty', 'value');
-// // Handle any actions with this.on('myAction', function(val) { ... });
-
-// this.render(hbs`{{thirdeye-chart}}`);
-
-// assert.equal(this.$().text().trim(), '');
-
-// // Template block usage:
-// this.render(hbs`
-// {{#thirdeye-chart}}
-// template block text
-// {{/thirdeye-chart}}
-// `);
-
-// assert.equal(this.$().text().trim(), 'template block text');
-// });
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@pinot.apache.org
For additional commands, e-mail: commits-help@pinot.apache.org