Browse Source

Unlabeled segments #187 && Choose deleted segment color #182 (#188)

master
rozetko 5 years ago committed by GitHub
parent
commit
5ac21a011e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 12
      src/panel/graph_panel/colors.ts
  2. 109
      src/panel/graph_panel/controllers/analytic_controller.ts
  3. 38
      src/panel/graph_panel/graph_ctrl.ts
  4. 54
      src/panel/graph_panel/graph_renderer.ts
  5. 2
      src/panel/graph_panel/graph_tooltip.ts
  6. 28
      src/panel/graph_panel/models/analytic_unit.ts
  7. 2
      src/panel/graph_panel/models/segment_array.ts
  8. 29
      src/panel/graph_panel/partials/tab_analytics.html
  9. 16
      src/panel/graph_panel/services/analytic_service.ts
  10. 12
      tests/analytic_controller.jest.ts

12
src/panel/graph_panel/colors.ts

@ -76,6 +76,16 @@ export const ANALYTIC_UNIT_COLORS = [
'#f8c171',
];
export const DEFAULT_DELETED_SEGMENT_COLOR = '#00f0ff';
export const REGION_UNLABEL_COLOR_LIGHT = '#d1d1d1';
export const REGION_UNLABEL_COLOR_DARK = 'white';
export const LABELED_SEGMENT_BORDER_COLOR = 'black';
export const DELETED_SEGMENT_BORDER_COLOR = 'black';
export const SEGMENT_FILL_ALPHA = 0.5;
export const SEGMENT_STROKE_ALPHA = 0.8;
export const LABELING_MODE_ALPHA = 0.7;
export function hexToHsl(color) {
return tinycolor(color).toHsl();
}
@ -85,4 +95,4 @@ export function hslToHex(color) {
}
export default colors;
export default colors;

109
src/panel/graph_panel/controllers/analytic_controller.ts

@ -4,7 +4,8 @@ import { AnalyticService } from '../services/analytic_service'
import {
AnalyticUnitId, AnalyticUnit,
AnalyticUnitsSet, AnalyticSegment, AnalyticSegmentsSearcher, AnalyticSegmentPair
AnalyticUnitsSet, AnalyticSegment, AnalyticSegmentsSearcher, AnalyticSegmentPair,
LabelingMode
} from '../models/analytic_unit';
import { MetricExpanded } from '../models/metric';
import { DatasourceRequest } from '../models/datasource';
@ -14,30 +15,27 @@ import { SegmentArray } from '../models/segment_array';
import { ServerInfo } from '../models/info';
import { Threshold, Condition } from '../models/threshold';
import { ANALYTIC_UNIT_COLORS } from '../colors';
import {
ANALYTIC_UNIT_COLORS,
LABELED_SEGMENT_BORDER_COLOR,
DELETED_SEGMENT_BORDER_COLOR,
SEGMENT_FILL_ALPHA,
SEGMENT_STROKE_ALPHA,
LABELING_MODE_ALPHA
} from '../colors';
import { Emitter } from 'grafana/app/core/utils/emitter';
import _ from 'lodash';
import * as tinycolor from 'tinycolor2';
export const REGION_FILL_ALPHA = 0.5;
export const REGION_STROKE_ALPHA = 0.8;
const LABELING_MODE_ALPHA = 0.7;
export const REGION_DELETE_COLOR_LIGHT = '#d1d1d1';
export const REGION_DELETE_COLOR_DARK = 'white';
const LABELED_SEGMENT_BORDER_COLOR = 'black';
const DELETED_SEGMENT_FILL_COLOR = '#00f0ff';
const DELETED_SEGMENT_BORDER_COLOR = 'black';
export class AnalyticController {
private _analyticUnitsSet: AnalyticUnitsSet;
private _selectedAnalyticUnitId: AnalyticUnitId = null;
private _labelingDataAddedSegments: SegmentsSet<AnalyticSegment>;
private _labelingDataDeletedSegments: SegmentsSet<AnalyticSegment>;
private _labelingDataRemovedSegments: SegmentsSet<AnalyticSegment>;
private _newAnalyticUnit: AnalyticUnit = null;
private _creatingNewAnalyticType: boolean = false;
private _savingNewAnalyticUnit: boolean = false;
@ -54,7 +52,7 @@ export class AnalyticController {
_panelObject.analyticUnits = _panelObject.anomalyTypes || [];
}
this._labelingDataAddedSegments = new SegmentArray<AnalyticSegment>();
this._labelingDataDeletedSegments = new SegmentArray<AnalyticSegment>();
this._labelingDataRemovedSegments = new SegmentArray<AnalyticSegment>();
this._analyticUnitsSet = new AnalyticUnitsSet(this._panelObject.analyticUnits);
this._thresholds = [];
this.updateThresholds();
@ -87,11 +85,11 @@ export class AnalyticController {
this._creatingNewAnalyticType = true;
this._savingNewAnalyticUnit = false;
if (this.analyticUnits.length === 0) {
this._newAnalyticUnit.color = ANALYTIC_UNIT_COLORS[0];
this._newAnalyticUnit.labeledColor = ANALYTIC_UNIT_COLORS[0];
} else {
let colorIndex = ANALYTIC_UNIT_COLORS.indexOf(_.last(this.analyticUnits).color) + 1;
let colorIndex = ANALYTIC_UNIT_COLORS.indexOf(_.last(this.analyticUnits).labeledColor) + 1;
colorIndex %= ANALYTIC_UNIT_COLORS.length;
this._newAnalyticUnit.color = ANALYTIC_UNIT_COLORS[colorIndex];
this._newAnalyticUnit.labeledColor = ANALYTIC_UNIT_COLORS[colorIndex];
}
}
@ -161,29 +159,29 @@ export class AnalyticController {
this._labelingDataAddedSegments.getSegments().forEach(s => {
this.labelingUnit.segments.remove(s.id);
});
this._labelingDataDeletedSegments.getSegments().forEach(s => {
s.deleted = false;
this._labelingDataRemovedSegments.getSegments().forEach(s => {
this.labelingUnit.segments.addSegment(s);
});
this.dropLabeling();
}
dropLabeling() {
this._labelingDataAddedSegments.clear();
this._labelingDataDeletedSegments.clear();
this._labelingDataRemovedSegments.clear();
this.labelingUnit.selected = false;
this._selectedAnalyticUnitId = null;
this._tempIdCounted = -1;
}
get labelingMode(): boolean {
get inLabelingMode(): boolean {
return this._selectedAnalyticUnitId !== null;
}
get labelingDeleteMode(): boolean {
if(!this.labelingMode) {
return false;
get labelingMode(): LabelingMode {
if(!this.inLabelingMode) {
return LabelingMode.NOT_IN_LABELING_MODE;
}
return this.labelingUnit.deleteMode;
return this.labelingUnit.labelingMode;
}
addLabelSegment(segment: Segment, deleted = false) {
@ -195,11 +193,15 @@ export class AnalyticController {
return this._analyticUnitsSet.items;
}
onAnalyticUnitColorChange(id: AnalyticUnitId, value: string) {
onAnalyticUnitColorChange(id: AnalyticUnitId, value: string, deleted: boolean) {
if(id === undefined) {
throw new Error('id is undefined');
}
this._analyticUnitsSet.byId(id).color = value;
if(deleted) {
this._analyticUnitsSet.byId(id).deletedColor = value;
} else {
this._analyticUnitsSet.byId(id).labeledColor = value;
}
}
fetchAnalyticUnitsStatuses() {
@ -228,7 +230,7 @@ export class AnalyticController {
var allSegmentsSet = new SegmentArray(allSegmentsList);
if(analyticUnit.selected) {
this._labelingDataAddedSegments.getSegments().forEach(s => allSegmentsSet.addSegment(s));
this._labelingDataDeletedSegments.getSegments().forEach(s => allSegmentsSet.remove(s.id));
this._labelingDataRemovedSegments.getSegments().forEach(s => allSegmentsSet.remove(s.id));
}
analyticUnit.segments = allSegmentsSet;
}
@ -241,16 +243,20 @@ export class AnalyticController {
if(
this._labelingDataAddedSegments.length === 0 &&
this._labelingDataDeletedSegments.length === 0
this._labelingDataRemovedSegments.length === 0
) {
return [];
}
await this._analyticService.updateMetric(unit.id, this._currentMetric, this._currentDatasource);
return this._analyticService.updateSegments(
unit.id, this._labelingDataAddedSegments, this._labelingDataDeletedSegments
const newIds = await this._analyticService.updateSegments(
unit.id, this._labelingDataAddedSegments, this._labelingDataRemovedSegments
);
if(unit.labelingMode !== LabelingMode.UNLABELING) {
await this._analyticService.runDetect(unit.id);
}
return newIds;
}
// TODO: move to renderer
@ -265,18 +271,18 @@ export class AnalyticController {
continue;
}
let borderColor = addAlphaToRGB(analyticUnit.color, REGION_STROKE_ALPHA);
let fillColor = addAlphaToRGB(analyticUnit.color, REGION_FILL_ALPHA);
let defaultBorderColor = addAlphaToRGB(analyticUnit.labeledColor, SEGMENT_STROKE_ALPHA);
let defaultFillColor = addAlphaToRGB(analyticUnit.labeledColor, SEGMENT_FILL_ALPHA);
let labeledSegmentBorderColor = tinycolor(LABELED_SEGMENT_BORDER_COLOR).toRgbString();
labeledSegmentBorderColor = addAlphaToRGB(labeledSegmentBorderColor, REGION_STROKE_ALPHA);
let deletedSegmentFillColor = tinycolor(DELETED_SEGMENT_FILL_COLOR).toRgbString();
deletedSegmentFillColor = addAlphaToRGB(deletedSegmentFillColor, REGION_FILL_ALPHA);
labeledSegmentBorderColor = addAlphaToRGB(labeledSegmentBorderColor, SEGMENT_STROKE_ALPHA);
let deletedSegmentFillColor = tinycolor(analyticUnit.deletedColor).toRgbString();
deletedSegmentFillColor = addAlphaToRGB(deletedSegmentFillColor, SEGMENT_FILL_ALPHA);
let deletedSegmentBorderColor = tinycolor(DELETED_SEGMENT_BORDER_COLOR).toRgbString();
deletedSegmentBorderColor = addAlphaToRGB(deletedSegmentBorderColor, REGION_STROKE_ALPHA);
deletedSegmentBorderColor = addAlphaToRGB(deletedSegmentBorderColor, SEGMENT_STROKE_ALPHA);
if(isEditMode && this.labelingMode && analyticUnit.selected) {
borderColor = addAlphaToRGB(borderColor, LABELING_MODE_ALPHA);
fillColor = addAlphaToRGB(fillColor, LABELING_MODE_ALPHA);
if(isEditMode && this.inLabelingMode && analyticUnit.selected) {
defaultBorderColor = addAlphaToRGB(defaultBorderColor, LABELING_MODE_ALPHA);
defaultFillColor = addAlphaToRGB(defaultFillColor, LABELING_MODE_ALPHA);
labeledSegmentBorderColor = addAlphaToRGB(labeledSegmentBorderColor, LABELING_MODE_ALPHA);
deletedSegmentFillColor = addAlphaToRGB(deletedSegmentFillColor, LABELING_MODE_ALPHA);
deletedSegmentBorderColor = addAlphaToRGB(deletedSegmentBorderColor, LABELING_MODE_ALPHA);
@ -286,8 +292,8 @@ export class AnalyticController {
const rangeDist = +options.xaxis.max - +options.xaxis.min;
segments.forEach(s => {
let segmentBorderColor = borderColor;
let segmentFillColor = fillColor;
let segmentBorderColor = defaultBorderColor;
let segmentFillColor = defaultFillColor;
if(s.deleted) {
segmentBorderColor = deletedSegmentBorderColor;
@ -298,7 +304,7 @@ export class AnalyticController {
}
}
var expanded = s.expandDist(rangeDist, 0.01);
const expanded = s.expandDist(rangeDist, 0.01);
options.grid.markings.push({
xaxis: { from: expanded.from, to: expanded.to },
color: segmentFillColor
@ -317,21 +323,24 @@ export class AnalyticController {
}
deleteLabelingAnalyticUnitSegmentsInRange(from: number, to: number) {
let allRemovedSegs = this.labelingUnit.removeSegmentsInRange(from, to);
const allRemovedSegs = this.labelingUnit.removeSegmentsInRange(from, to);
allRemovedSegs.forEach(s => {
if(!this._labelingDataAddedSegments.has(s.id)) {
this._labelingDataDeletedSegments.addSegment(s);
this.labelingUnit.addLabeledSegment(s, true);
this._labelingDataRemovedSegments.addSegment(s);
}
});
this._labelingDataAddedSegments.removeInRange(from, to);
}
toggleDeleteMode() {
if(!this.labelingMode) {
throw new Error('Cant enter delete mode is labeling mode disabled');
toggleLabelingMode(mode: LabelingMode) {
if(!this.inLabelingMode) {
throw new Error(`Can't enter ${mode} mode when labeling mode is disabled`);
}
if(this.labelingUnit.labelingMode === mode) {
this.labelingUnit.labelingMode = LabelingMode.LABELING;
} else {
this.labelingUnit.labelingMode = mode;
}
this.labelingUnit.deleteMode = !this.labelingUnit.deleteMode;
}
async removeAnalyticUnit(id: AnalyticUnitId, silent: boolean = false) {

38
src/panel/graph_panel/graph_ctrl.ts

@ -7,7 +7,7 @@ import { GraphLegend } from './graph_legend';
import { DataProcessor } from './data_processor';
import { MetricExpanded } from './models/metric';
import { DatasourceRequest } from './models/datasource';
import { AnalyticUnitId, AnalyticUnit } from './models/analytic_unit';
import { AnalyticUnitId, AnalyticUnit, LabelingMode } from './models/analytic_unit';
import { AnalyticService } from './services/analytic_service';
import { AnalyticController } from './controllers/analytic_controller';
import { PanelInfo } from './models/info';
@ -35,7 +35,6 @@ class GraphCtrl extends MetricsPanelCtrl {
private _datasourceRequest: DatasourceRequest;
private _datasources: any;
private _panelPath: any;
private _renderError: boolean = false;
// annotationsPromise: any;
@ -157,19 +156,28 @@ class GraphCtrl extends MetricsPanelCtrl {
this.events.on('init-edit-mode', this.onInitEditMode.bind(this));
}
rebindDKey() {
rebindKeys() {
const dKeyCode = 68;
const uKeyCode = 85;
$(document).off('keydown.hasticDKey');
$(document).on('keydown.hasticDKey', (e) => {
// 68 is 'd' key kode
if(e.keyCode === 68) {
if(e.keyCode === dKeyCode) {
this.onDKey();
}
});
$(document).off('keydown.hasticUKey');
$(document).on('keydown.hasticUKey', (e) => {
if(e.keyCode === uKeyCode) {
this.onUKey();
}
});
}
editPanel() {
super.editPanel();
this.rebindDKey();
this.rebindKeys();
}
async getBackendURL(): Promise<string> {
@ -300,7 +308,7 @@ class GraphCtrl extends MetricsPanelCtrl {
onInitEditMode() {
this.rebindDKey(); // a small hask: bind if we open page in edit mode
this.rebindKeys(); // a small hask: bind if we open page in edit mode
const partialPath = this.panelPath + '/partials';
this.addEditorTab('Analytics', `${partialPath}/tab_analytics.html`, 2);
@ -581,11 +589,11 @@ class GraphCtrl extends MetricsPanelCtrl {
this.analyticsController.fetchAnalyticUnitName(analyticUnit);
}
onColorChange(id: AnalyticUnitId, value: string) {
onColorChange(id: AnalyticUnitId, deleted: boolean, value: string) {
if(id === undefined) {
throw new Error('id is undefined');
}
this.analyticsController.onAnalyticUnitColorChange(id, value);
this.analyticsController.onAnalyticUnitColorChange(id, value, deleted);
this.render();
}
@ -624,10 +632,18 @@ class GraphCtrl extends MetricsPanelCtrl {
}
onDKey() {
if(!this.analyticsController.labelingMode) {
if(!this.analyticsController.inLabelingMode) {
return;
}
this.analyticsController.toggleLabelingMode(LabelingMode.DELETING);
this.refresh();
}
onUKey() {
if(!this.analyticsController.inLabelingMode) {
return;
}
this.analyticsController.toggleDeleteMode();
this.analyticsController.toggleLabelingMode(LabelingMode.UNLABELING);
this.refresh();
}

54
src/panel/graph_panel/graph_renderer.ts

@ -1,15 +1,17 @@
import { Segment } from './models/segment';
import { LabelingMode } from './models/analytic_unit';
import { GraphTooltip } from './graph_tooltip';
import { convertValuesToHistogram, getSeriesValues } from './histogram';
import {
AnalyticController,
REGION_FILL_ALPHA,
REGION_STROKE_ALPHA,
REGION_DELETE_COLOR_LIGHT,
REGION_DELETE_COLOR_DARK
AnalyticController
} from './controllers/analytic_controller';
import {
REGION_UNLABEL_COLOR_LIGHT,
REGION_UNLABEL_COLOR_DARK
} from './colors';
import { GraphCtrl } from './graph_ctrl';
import 'jquery';
@ -140,19 +142,26 @@ export class GraphRenderer {
if(this._isHasticEvent(selectionEvent)) {
this.plot.clearSelection();
var id = this._analyticController.getNewTempSegmentId();
var segment = new Segment(
const id = this._analyticController.getNewTempSegmentId();
const segment = new Segment(
id,
Math.round(selectionEvent.xaxis.from),
Math.round(selectionEvent.xaxis.to)
);
if(this._analyticController.labelingDeleteMode) {
if(this._analyticController.labelingMode === LabelingMode.DELETING) {
this._analyticController.deleteLabelingAnalyticUnitSegmentsInRange(
segment.from, segment.to
);
} else {
this._analyticController.addLabelSegment(segment);
this._analyticController.addLabelSegment(segment, true);
}
if(this._analyticController.labelingMode === LabelingMode.LABELING) {
this._analyticController.addLabelSegment(segment, false);
}
if(this._analyticController.labelingMode === LabelingMode.UNLABELING) {
this._analyticController.deleteLabelingAnalyticUnitSegmentsInRange(
segment.from, segment.to
);
}
this.renderPanel();
return;
@ -335,21 +344,22 @@ export class GraphRenderer {
}
private _chooseSelectionColor(e) {
var color = COLOR_SELECTION;
var fillAlpha = 0.4;
var strokeAlpha = 0.4;
let color = COLOR_SELECTION;
if(this._isHasticEvent(e)) {
if(this._analyticController.labelingDeleteMode) {
if(this._analyticController.labelingMode === LabelingMode.DELETING) {
color = this._analyticController.labelingUnit.deletedColor;
}
if(this._analyticController.labelingMode === LabelingMode.LABELING) {
color = this._analyticController.labelingUnit.labeledColor;
}
if(this._analyticController.labelingMode === LabelingMode.UNLABELING) {
color = this.contextSrv.user.lightTheme ?
REGION_DELETE_COLOR_LIGHT :
REGION_DELETE_COLOR_DARK;
} else {
color = this._analyticController.labelingUnit.color;
REGION_UNLABEL_COLOR_LIGHT :
REGION_UNLABEL_COLOR_DARK;
}
fillAlpha = REGION_FILL_ALPHA;
strokeAlpha = REGION_STROKE_ALPHA;
}
this.plot.getOptions().selection.color = color
this.plot.getOptions().selection.color = color;
}
private _buildFlotPairs(data) {
@ -806,7 +816,7 @@ export class GraphRenderer {
private _isHasticEvent(obj: any) {
return (obj.ctrlKey || obj.metaKey) &&
this.contextSrv.isEditor &&
this._analyticController.labelingMode;
this._analyticController.inLabelingMode;
}
}

2
src/panel/graph_panel/graph_tooltip.ts

@ -211,7 +211,7 @@ export class GraphTooltip {
result += `
<div class="graph-tooltip-list-item">
<div class="graph-tooltip-series-name">
<i class="fa fa-exclamation" style="color:${s.analyticUnit.color}"></i>
<i class="fa fa-exclamation" style="color:${s.analyticUnit.labeledColor}"></i>
${s.analyticUnit.name}:
</div>
<div class="graph-tooltip-value">

28
src/panel/graph_panel/models/analytic_unit.ts

@ -2,11 +2,18 @@ import { SegmentsSet } from './segment_set';
import { SegmentArray } from './segment_array';
import { Segment, SegmentId } from './segment';
import { ANALYTIC_UNIT_COLORS } from '../colors';
import { ANALYTIC_UNIT_COLORS, DEFAULT_DELETED_SEGMENT_COLOR } from '../colors';
import _ from 'lodash';
export enum LabelingMode {
LABELING = 'LABELING',
UNLABELING = 'UNLABELING',
DELETING = 'DELETING',
NOT_IN_LABELING_MODE = 'NOT_IN_LABELING_MODE'
};
export type AnalyticSegmentPair = { analyticUnit: AnalyticUnit, segment: AnalyticSegment };
export type AnalyticSegmentsSearcher = (point: number, rangeDist: number) => AnalyticSegmentPair[];
@ -23,8 +30,8 @@ export class AnalyticSegment extends Segment {
export class AnalyticUnit {
private _labelingMode: LabelingMode = LabelingMode.LABELING;
private _selected: boolean = false;
private _deleteMode: boolean = false;
private _saving: boolean = false;
private _segmentSet = new SegmentArray<AnalyticSegment>();
private _status: string;
@ -36,7 +43,8 @@ export class AnalyticUnit {
}
_.defaults(this._panelObject, {
name: 'AnalyticUnitName',
color: ANALYTIC_UNIT_COLORS[0],
labeledColor: ANALYTIC_UNIT_COLORS[0],
deletedColor: DEFAULT_DELETED_SEGMENT_COLOR,
detectorType: 'pattern',
type: 'GENERAL',
alert: false
@ -58,8 +66,11 @@ export class AnalyticUnit {
set confidence(value: number) { this._panelObject.confidence = value; }
get confidence(): number { return this._panelObject.confidence; }
set color(value: string) { this._panelObject.color = value; }
get color(): string { return this._panelObject.color; }
set labeledColor(value: string) { this._panelObject.labeledColor = value; }
get labeledColor(): string { return this._panelObject.labeledColor; }
set deletedColor(value: string) { this._panelObject.deletedColor = value; }
get deletedColor(): string { return this._panelObject.deletedColor; }
set alert(value: boolean) { this._panelObject.alert = value; }
get alert(): boolean { return this._panelObject.alert; }
@ -67,8 +78,8 @@ export class AnalyticUnit {
get selected(): boolean { return this._selected; }
set selected(value: boolean) { this._selected = value; }
get deleteMode(): boolean { return this._deleteMode; }
set deleteMode(value: boolean) { this._deleteMode = value; }
get labelingMode(): LabelingMode { return this._labelingMode; }
set labelingMode(value: LabelingMode) { this._labelingMode = value; }
get saving(): boolean { return this._saving; }
set saving(value: boolean) { this._saving = value; }
@ -88,9 +99,6 @@ export class AnalyticUnit {
removeSegmentsInRange(from: number, to: number): AnalyticSegment[] {
let deletedSegments = this._segmentSet.removeInRange(from, to);
deletedSegments.forEach(s => {
s.deleted = true;
});
return deletedSegments;
}

2
src/panel/graph_panel/models/segment_array.ts

@ -47,7 +47,7 @@ export class SegmentArray<T extends Segment> implements SegmentsSet<T> {
findSegments(point: number, rangeDist: number): T[] {
return this._segments.filter(s => {
var expanded = s.expandDist(rangeDist, 0.01);
const expanded = s.expandDist(rangeDist, 0.01);
return (expanded.from <= point) && (point <= expanded.to);
});
}

29
src/panel/graph_panel/partials/tab_analytics.html

@ -11,7 +11,7 @@
<div class="editor-row">
<div class="gf-form" ng-repeat="analyticUnit in ctrl.analyticsController.analyticUnits">
<label class="gf-form-label width-6">
<label class="gf-form-label width-5">
<i class="fa fa-info" bs-tooltip="'Analytic unit id: ' + analyticUnit.id"></i>
&nbsp; Name
</label>
@ -21,7 +21,7 @@
ng-change="ctrl.onAnalyticUnitNameChange(analyticUnit)"
>
<label class="gf-form-label width-8"> Type </label>
<label class="gf-form-label width-4"> Type </label>
<div class="gf-form-select-wrapper">
<select class="gf-form-input width-12"
ng-model="analyticUnit.type"
@ -39,11 +39,19 @@
/>
-->
<label class="gf-form-label width-6"> Color </label>
<label class="gf-form-label width-8"> Labeled Color </label>
<span class="gf-form-label">
<color-picker
color="analyticUnit.color"
onChange="ctrl.onColorChange.bind(ctrl, analyticUnit.id)"
color="analyticUnit.labeledColor"
onChange="ctrl.onColorChange.bind(ctrl, analyticUnit.id, false)"
/>
</span>
<label class="gf-form-label width-8"> Deleted Color </label>
<span class="gf-form-label">
<color-picker
color="analyticUnit.deletedColor"
onChange="ctrl.onColorChange.bind(ctrl, analyticUnit.id, true)"
/>
</span>
@ -58,8 +66,9 @@
>
<i class="fa fa-bar-chart" ng-if="!analyticUnit.saving"></i>
<i class="fa fa-spinner fa-spin" ng-if="analyticUnit.saving"></i>
<b ng-if="analyticUnit.selected && !analyticUnit.deleteMode && !analyticUnit.saving"> labeling </b>
<b ng-if="analyticUnit.selected && analyticUnit.deleteMode && !analyticUnit.saving"> deleting </b>
<b ng-if="analyticUnit.selected && analyticUnit.labelingMode === 'LABELING' && !analyticUnit.saving"> labeling </b>
<b ng-if="analyticUnit.selected && analyticUnit.labelingMode === 'DELETING' && !analyticUnit.saving"> deleting </b>
<b ng-if="analyticUnit.selected && analyticUnit.labelingMode === 'UNLABELING' && !analyticUnit.saving"> unlabeling </b>
<b ng-if="analyticUnit.saving" ng-disabled="true"> saving... </b>
</a>
</label>
@ -79,9 +88,9 @@
"
/>
<!-- TODO set .saving flag to thresholds, when learning is in progress -->
<button
class="btn btn-inverse"
ng-if="analyticUnit.detectorType === 'threshold'"
<button
class="btn btn-inverse"
ng-if="analyticUnit.detectorType === 'threshold'"
ng-click="ctrl.analyticsController.sendThresholdParamsToServer(analyticUnit.id)"
ng-disabled="analyticUnit.status === 'PENDING' || analyticUnit.status === 'LEARNING'"
>

16
src/panel/graph_panel/services/analytic_service.ts

@ -66,20 +66,22 @@ export class AnalyticService {
}
async updateSegments(
id: AnalyticUnitId, addedSegments: SegmentsSet<Segment>, removedSegments: SegmentsSet<Segment>
id: AnalyticUnitId, addedSegments: SegmentsSet<AnalyticSegment>, removedSegments: SegmentsSet<AnalyticSegment>
): Promise<SegmentId[]> {
const getJSONs = (segs: SegmentsSet<Segment>) => segs.getSegments().map(segment => ({
const getJSONs = (segs: SegmentsSet<AnalyticSegment>) => segs.getSegments().map(segment => ({
from: segment.from,
to: segment.to
to: segment.to,
labeled: segment.labeled,
deleted: segment.deleted
}));
var payload = {
const payload = {
id,
addedSegments: getJSONs(addedSegments),
removedSegments: removedSegments.getSegments().map(s => s.id)
};
var data = await this.patch('/segments', payload);
const data = await this.patch('/segments', payload);
if(data.addedIds === undefined) {
throw new Error('Server didn`t send addedIds');
}
@ -158,6 +160,10 @@ export class AnalyticService {
return this.patch('/analyticUnits', updateObj);
}
async runDetect(id: AnalyticUnitId) {
return this.post('/analyticUnits/detect', { id });
}
private async _analyticRequest(method: string, url: string, data?: any) {
try {
method = method.toUpperCase();

12
tests/analytic_controller.jest.ts

@ -9,7 +9,7 @@ describe('AnalyticController', function () {
it('should create analytic units with colors from palette', async function () {
for (let color of ANALYTIC_UNIT_COLORS) {
analyticController.createNew();
expect(analyticController.newAnalyticUnit.color).toBe(color);
expect(analyticController.newAnalyticUnit.labeledColor).toBe(color);
await analyticController.saveNew({} as MetricExpanded, {} as DatasourceRequest, '');
}
});
@ -29,19 +29,19 @@ describe('AnalyticController', function () {
let auArray = analyticController.analyticUnits;
analyticController.createNew();
await analyticController.saveNew({} as MetricExpanded, {} as DatasourceRequest, '');
expect(auArray[auArray.length - 2].panelObject.color).not.toBe(auArray[auArray.length - 1].panelObject.color);
expect(auArray[auArray.length - 2].panelObject.labeledColor).not.toBe(auArray[auArray.length - 1].panelObject.labeledColor);
});
it('should set different color to newly created Analytic Unit, afer LAST AU was deleted', async function () {
it('should set different color to newly created Analytic Unit, after LAST AU was deleted', async function () {
let auArray = analyticController.analyticUnits;
auArray.splice(-1, 1);
analyticController.createNew();
await analyticController.saveNew({} as MetricExpanded, {} as DatasourceRequest, '');
expect(auArray[auArray.length - 2].panelObject.color).not.toBe(auArray[auArray.length - 1].panelObject.color);
expect(auArray[auArray.length - 2].panelObject.labeledColor).not.toBe(auArray[auArray.length - 1].panelObject.labeledColor);
});
it('should change color on choosing from palette', function () {
analyticController.onAnalyticUnitColorChange('1', 'red');
expect(analyticController.analyticUnits[0].color).toBe('red');
analyticController.onAnalyticUnitColorChange('1', 'red', false);
expect(analyticController.analyticUnits[0].labeledColor).toBe('red');
});
});

Loading…
Cancel
Save