You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
355 lines
11 KiB
355 lines
11 KiB
![]()
7 years ago
|
import { AnalyticService } from '../services/analytic_service'
|
||
![]()
7 years ago
|
|
||
|
import {
|
||
![]()
7 years ago
|
AnalyticUnitKey, AnalyticUnit,
|
||
|
AnalyticUnitsSet, AnalyticSegment, AnalyticSegmentsSearcher, AnalyticSegmentPair
|
||
|
} from '../model/analytic_unit';
|
||
![]()
7 years ago
|
import { MetricExpanded } from '../model/metric';
|
||
|
import { DatasourceRequest } from '../model/datasource';
|
||
![]()
7 years ago
|
import { Segment, SegmentKey } from '../model/segment';
|
||
|
import { SegmentsSet } from '../model/segment_set';
|
||
|
import { SegmentArray } from '../model/segment_array';
|
||
|
import { Emitter } from 'grafana/app/core/utils/emitter'
|
||
|
|
||
|
import _ from 'lodash';
|
||
|
|
||
![]()
7 years ago
|
|
||
![]()
7 years ago
|
export const REGION_FILL_ALPHA = 0.7;
|
||
|
export const REGION_STROKE_ALPHA = 0.9;
|
||
|
export const REGION_DELETE_COLOR_LIGHT = '#d1d1d1';
|
||
|
export const REGION_DELETE_COLOR_DARK = 'white';
|
||
|
|
||
|
|
||
![]()
7 years ago
|
export class AnalyticController {
|
||
![]()
7 years ago
|
|
||
![]()
7 years ago
|
private _analyticUnitsSet: AnalyticUnitsSet;
|
||
|
private _selectedAnalyticUnitKey: AnalyticUnitKey = null;
|
||
![]()
7 years ago
|
|
||
![]()
7 years ago
|
private _labelingDataAddedSegments: SegmentsSet<AnalyticSegment>;
|
||
|
private _labelingDataDeletedSegments: SegmentsSet<AnalyticSegment>;
|
||
|
private _newAnalyticUnitType: AnalyticUnit = null;
|
||
|
private _creatingNewAnalyticType: boolean = false;
|
||
|
private _savingNewAnalyticUnit: boolean = false;
|
||
![]()
7 years ago
|
private _tempIdCounted = -1;
|
||
|
private _graphLocked = false;
|
||
|
|
||
![]()
7 years ago
|
private _statusRunners: Set<AnalyticUnitKey> = new Set<AnalyticUnitKey>();
|
||
![]()
7 years ago
|
|
||
|
|
||
![]()
7 years ago
|
constructor(private _panelObject: any, private _analyticService: AnalyticService, private _emitter: Emitter) {
|
||
![]()
7 years ago
|
if(_panelObject.anomalyTypes === undefined) {
|
||
|
_panelObject.anomalyTypes = [];
|
||
|
}
|
||
![]()
7 years ago
|
this._labelingDataAddedSegments = new SegmentArray<AnalyticSegment>();
|
||
|
this._labelingDataDeletedSegments = new SegmentArray<AnalyticSegment>();
|
||
|
this._analyticUnitsSet = new AnalyticUnitsSet(this._panelObject.anomalyTypes);
|
||
|
this.analyticUnits.forEach(a => this.runEnabledWaiter(a));
|
||
![]()
7 years ago
|
}
|
||
|
|
||
![]()
7 years ago
|
getSegmentsSearcher(): AnalyticSegmentsSearcher {
|
||
|
return this._segmentsSearcher.bind(this);
|
||
![]()
7 years ago
|
}
|
||
|
|
||
![]()
7 years ago
|
private _segmentsSearcher(point: number, rangeDist: number): AnalyticSegmentPair[] {
|
||
|
var result: AnalyticSegmentPair[] = [];
|
||
|
this._analyticUnitsSet.items.forEach(at => {
|
||
7 years ago
|
var segs = at.segments.findSegments(point, rangeDist);
|
||
![]()
7 years ago
|
segs.forEach(s => {
|
||
|
result.push({ anomalyType: at, segment: s });
|
||
|
})
|
||
|
})
|
||
|
return result;
|
||
|
}
|
||
|
|
||
![]()
7 years ago
|
createNew() {
|
||
|
this._newAnalyticUnitType = new AnalyticUnit();
|
||
|
this._creatingNewAnalyticType = true;
|
||
|
this._savingNewAnalyticUnit = false;
|
||
![]()
7 years ago
|
}
|
||
|
|
||
![]()
7 years ago
|
async saveNew(metricExpanded: MetricExpanded, datasourceRequest: DatasourceRequest, panelId: number) {
|
||
|
this._savingNewAnalyticUnit = true;
|
||
|
await this._analyticService.postNewAnalyticUnit(metricExpanded, datasourceRequest, this._newAnalyticUnitType, panelId);
|
||
|
this._analyticUnitsSet.addAnomalyType(this._newAnalyticUnitType);
|
||
|
this._creatingNewAnalyticType = false;
|
||
|
this._savingNewAnalyticUnit = false;
|
||
|
this.runEnabledWaiter(this._newAnalyticUnitType);
|
||
|
this._runStatusWaiter(this._newAnalyticUnitType);
|
||
![]()
7 years ago
|
}
|
||
|
|
||
![]()
7 years ago
|
get creatingNew() { return this._creatingNewAnalyticType; }
|
||
|
get saving() { return this._savingNewAnalyticUnit; }
|
||
|
get newAnalyticUnit(): AnalyticUnit { return this._newAnalyticUnitType; }
|
||
![]()
7 years ago
|
|
||
|
get graphLocked() { return this._graphLocked; }
|
||
![]()
7 years ago
|
set graphLocked(value) { this._graphLocked = value; }
|
||
![]()
7 years ago
|
|
||
![]()
7 years ago
|
get labelingAnomaly(): AnalyticUnit {
|
||
|
if(this._selectedAnalyticUnitKey === null) {
|
||
![]()
7 years ago
|
return null;
|
||
|
}
|
||
![]()
7 years ago
|
return this._analyticUnitsSet.byKey(this._selectedAnalyticUnitKey);
|
||
![]()
7 years ago
|
}
|
||
|
|
||
![]()
7 years ago
|
async toggleAnomalyTypeLabelingMode(key: AnalyticUnitKey) {
|
||
![]()
7 years ago
|
if(this.labelingAnomaly && this.labelingAnomaly.saving) {
|
||
|
throw new Error('Can`t toggel during saving');
|
||
|
}
|
||
![]()
7 years ago
|
if(this._selectedAnalyticUnitKey === key) {
|
||
|
return this.disableLabeling();
|
||
![]()
7 years ago
|
}
|
||
![]()
7 years ago
|
await this.disableLabeling();
|
||
|
this._selectedAnalyticUnitKey = key;
|
||
![]()
7 years ago
|
this.labelingAnomaly.selected = true;
|
||
![]()
7 years ago
|
this.toggleVisibility(key, true);
|
||
![]()
7 years ago
|
}
|
||
|
|
||
![]()
7 years ago
|
async disableLabeling() {
|
||
|
if(this._selectedAnalyticUnitKey === null) {
|
||
![]()
7 years ago
|
return;
|
||
|
}
|
||
|
this.labelingAnomaly.saving = true;
|
||
|
var newIds = await this._saveLabelingData();
|
||
|
this._labelingDataAddedSegments.getSegments().forEach((s, i) => {
|
||
|
this.labelingAnomaly.segments.updateKey(s.key, newIds[i]);
|
||
|
})
|
||
|
this.labelingAnomaly.saving = false;
|
||
|
|
||
|
var anomaly = this.labelingAnomaly;
|
||
|
this.dropLabeling();
|
||
![]()
7 years ago
|
this._runStatusWaiter(anomaly);
|
||
![]()
7 years ago
|
}
|
||
|
|
||
|
undoLabeling() {
|
||
|
this._labelingDataAddedSegments.getSegments().forEach(s => {
|
||
|
this.labelingAnomaly.segments.remove(s.key);
|
||
|
});
|
||
|
this._labelingDataDeletedSegments.getSegments().forEach(s => {
|
||
|
this.labelingAnomaly.segments.addSegment(s);
|
||
|
});
|
||
|
this.dropLabeling();
|
||
|
}
|
||
|
|
||
|
dropLabeling() {
|
||
|
this._labelingDataAddedSegments.clear();
|
||
|
this._labelingDataDeletedSegments.clear();
|
||
|
this.labelingAnomaly.selected = false;
|
||
![]()
7 years ago
|
this._selectedAnalyticUnitKey = null;
|
||
![]()
7 years ago
|
this._tempIdCounted = -1;
|
||
|
}
|
||
|
|
||
|
get labelingMode(): boolean {
|
||
![]()
7 years ago
|
return this._selectedAnalyticUnitKey !== null;
|
||
![]()
7 years ago
|
}
|
||
|
|
||
|
get labelingDeleteMode(): boolean {
|
||
|
if(!this.labelingMode) {
|
||
|
return false;
|
||
|
}
|
||
|
return this.labelingAnomaly.deleteMode;
|
||
|
}
|
||
|
|
||
|
addLabelSegment(segment: Segment) {
|
||
|
var asegment = this.labelingAnomaly.addLabeledSegment(segment);
|
||
|
this._labelingDataAddedSegments.addSegment(asegment);
|
||
|
}
|
||
|
|
||
![]()
7 years ago
|
get analyticUnits(): AnalyticUnit[] {
|
||
|
return this._analyticUnitsSet.items;
|
||
![]()
7 years ago
|
}
|
||
|
|
||
![]()
7 years ago
|
onAnomalyColorChange(key: AnalyticUnitKey, value) {
|
||
|
this._analyticUnitsSet.byKey(key).color = value;
|
||
![]()
7 years ago
|
}
|
||
|
|
||
|
fetchAnomalyTypesStatuses() {
|
||
![]()
7 years ago
|
this.analyticUnits.forEach(a => this._runStatusWaiter(a));
|
||
![]()
7 years ago
|
}
|
||
|
|
||
|
async fetchAnomalyTypesSegments(from: number, to: number) {
|
||
![]()
7 years ago
|
if(!_.isNumber(+from)) {
|
||
![]()
7 years ago
|
throw new Error('from isn`t number');
|
||
|
}
|
||
|
if(!_.isNumber(+to)) {
|
||
|
throw new Error('to isn`t number');
|
||
|
}
|
||
![]()
7 years ago
|
var tasks = this.analyticUnits.map(a => this.fetchSegments(a, from, to));
|
||
![]()
7 years ago
|
return Promise.all(tasks);
|
||
|
}
|
||
|
|
||
![]()
7 years ago
|
async fetchSegments(anomalyType: AnalyticUnit, from: number, to: number): Promise<void> {
|
||
|
if(!_.isNumber(+from)) {
|
||
![]()
7 years ago
|
throw new Error('from isn`t number');
|
||
|
}
|
||
|
if(!_.isNumber(+to)) {
|
||
|
throw new Error('to isn`t number');
|
||
|
}
|
||
![]()
7 years ago
|
var allSegmentsList = await this._analyticService.getSegments(anomalyType.key, from, to);
|
||
![]()
7 years ago
|
var allSegmentsSet = new SegmentArray(allSegmentsList);
|
||
|
if(anomalyType.selected) {
|
||
|
this._labelingDataAddedSegments.getSegments().forEach(s => allSegmentsSet.addSegment(s));
|
||
|
this._labelingDataDeletedSegments.getSegments().forEach(s => allSegmentsSet.remove(s.key));
|
||
|
}
|
||
|
anomalyType.segments = allSegmentsSet;
|
||
|
}
|
||
|
|
||
|
private async _saveLabelingData(): Promise<SegmentKey[]> {
|
||
|
var anomaly = this.labelingAnomaly;
|
||
|
if(anomaly === null) {
|
||
|
throw new Error('anomaly is not selected');
|
||
|
}
|
||
|
|
||
|
if(
|
||
|
this._labelingDataAddedSegments.length === 0 &&
|
||
|
this._labelingDataDeletedSegments.length === 0
|
||
|
) {
|
||
|
return [];
|
||
|
}
|
||
|
|
||
![]()
7 years ago
|
return this._analyticService.updateSegments(
|
||
![]()
7 years ago
|
anomaly.key, this._labelingDataAddedSegments, this._labelingDataDeletedSegments
|
||
|
);
|
||
|
}
|
||
|
|
||
|
// TODO: move to renderer
|
||
|
updateFlotEvents(isEditMode, options) {
|
||
|
if(options.grid.markings === undefined) {
|
||
|
options.markings = [];
|
||
|
}
|
||
|
|
||
![]()
7 years ago
|
for(var i = 0; i < this.analyticUnits.length; i++) {
|
||
|
var anomalyType = this.analyticUnits[i];
|
||
![]()
7 years ago
|
var borderColor = addAlphaToRGB(anomalyType.color, REGION_STROKE_ALPHA);
|
||
|
var fillColor = addAlphaToRGB(anomalyType.color, REGION_FILL_ALPHA);
|
||
|
var segments = anomalyType.segments.getSegments();
|
||
|
if(!anomalyType.visible) {
|
||
|
continue;
|
||
|
}
|
||
|
if(isEditMode && this.labelingMode) {
|
||
|
if(anomalyType.selected) {
|
||
|
borderColor = addAlphaToRGB(borderColor, 0.7);
|
||
|
fillColor = addAlphaToRGB(borderColor, 0.7);
|
||
|
} else {
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
var rangeDist = +options.xaxis.max - +options.xaxis.min;
|
||
|
segments.forEach(s => {
|
||
|
var expanded = s.expandDist(rangeDist, 0.01);
|
||
|
options.grid.markings.push({
|
||
|
xaxis: { from: expanded.from, to: expanded.to },
|
||
|
color: fillColor
|
||
|
});
|
||
|
options.grid.markings.push({
|
||
|
xaxis: { from: expanded.from, to: expanded.from },
|
||
|
color: borderColor
|
||
|
});
|
||
|
options.grid.markings.push({
|
||
|
xaxis: { from: expanded.to, to: expanded.to },
|
||
|
color: borderColor
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
deleteLabelingAnomalySegmentsInRange(from: number, to: number) {
|
||
|
var allRemovedSegs = this.labelingAnomaly.removeSegmentsInRange(from, to);
|
||
|
allRemovedSegs.forEach(s => {
|
||
|
if(!this._labelingDataAddedSegments.has(s.key)) {
|
||
|
this._labelingDataDeletedSegments.addSegment(s);
|
||
|
}
|
||
|
});
|
||
|
this._labelingDataAddedSegments.removeInRange(from, to);
|
||
|
}
|
||
|
|
||
|
toggleDeleteMode() {
|
||
|
if(!this.labelingMode) {
|
||
|
throw new Error('Cant enter delete mode is labeling mode disabled');
|
||
|
}
|
||
|
this.labelingAnomaly.deleteMode = !this.labelingAnomaly.deleteMode;
|
||
|
}
|
||
|
|
||
|
removeAnomalyType(key) {
|
||
![]()
7 years ago
|
if(key === this._selectedAnalyticUnitKey) {
|
||
![]()
7 years ago
|
this.dropLabeling();
|
||
|
}
|
||
![]()
7 years ago
|
this._analyticUnitsSet.removeAnomalyType(key);
|
||
![]()
7 years ago
|
}
|
||
|
|
||
![]()
7 years ago
|
private async _runStatusWaiter(anomalyType: AnalyticUnit) {
|
||
![]()
7 years ago
|
if(anomalyType === undefined || anomalyType === null) {
|
||
|
throw new Error('anomalyType not defined');
|
||
|
}
|
||
|
|
||
|
if(this._statusRunners.has(anomalyType.key)) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
this._statusRunners.add(anomalyType.key);
|
||
|
|
||
![]()
7 years ago
|
var statusGenerator = this._analyticService.getAnomalyTypeStatusGenerator(
|
||
![]()
7 years ago
|
anomalyType.key, 1000
|
||
|
);
|
||
|
|
||
7 years ago
|
for await (const data of statusGenerator) {
|
||
|
let status = data.status;
|
||
|
let error = data.errorMessage;
|
||
![]()
7 years ago
|
if(anomalyType.status !== status) {
|
||
|
anomalyType.status = status;
|
||
7 years ago
|
if(error !== undefined) {
|
||
|
anomalyType.error = error;
|
||
|
}
|
||
![]()
7 years ago
|
this._emitter.emit('anomaly-type-status-change', anomalyType);
|
||
|
}
|
||
|
if(!anomalyType.isActiveStatus) {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
this._statusRunners.delete(anomalyType.key);
|
||
|
}
|
||
|
|
||
![]()
7 years ago
|
async runEnabledWaiter(anomalyType: AnalyticUnit) {
|
||
|
var enabled = await this._analyticService.getAlertEnabled(anomalyType.key);
|
||
![]()
7 years ago
|
if(anomalyType.alertEnabled !== enabled) {
|
||
|
anomalyType.alertEnabled = enabled;
|
||
|
this._emitter.emit('anomaly-type-alert-change', anomalyType);
|
||
|
}
|
||
|
}
|
||
|
|
||
![]()
7 years ago
|
async toggleAnomalyTypeAlertEnabled(anomalyType: AnalyticUnit) {
|
||
![]()
7 years ago
|
var enabled = anomalyType.alertEnabled;
|
||
|
anomalyType.alertEnabled = undefined;
|
||
![]()
7 years ago
|
await this._analyticService.setAlertEnabled(anomalyType.key, enabled);
|
||
![]()
7 years ago
|
anomalyType.alertEnabled = enabled;
|
||
|
this._emitter.emit('anomaly-type-alert-change', anomalyType);
|
||
|
}
|
||
|
|
||
|
public getIdForNewLabelSegment() {
|
||
|
this._tempIdCounted--;
|
||
|
return this._tempIdCounted;
|
||
|
}
|
||
|
|
||
![]()
7 years ago
|
public toggleVisibility(key: AnalyticUnitKey, value?: boolean) {
|
||
|
var anomaly = this._analyticUnitsSet.byKey(key);
|
||
![]()
7 years ago
|
if(value !== undefined) {
|
||
|
anomaly.visible = value;
|
||
|
} else {
|
||
|
anomaly.visible = !anomaly.visible;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
function addAlphaToRGB(colorString: string, alpha: number): string {
|
||
|
let color = tinycolor(colorString);
|
||
|
if (color.isValid()) {
|
||
|
color.setAlpha(color.getAlpha() * alpha);
|
||
|
return color.toRgbString();
|
||
|
} else {
|
||
|
return colorString;
|
||
|
}
|
||
|
}
|