Browse Source

Unlabeling mode

master
rozetko 5 years ago
parent
commit
a9a82d374b
  1. 9
      src/panel/graph_panel/colors.ts
  2. 55
      src/panel/graph_panel/controllers/analytic_controller.ts
  3. 33
      src/panel/graph_panel/graph_ctrl.ts
  4. 44
      src/panel/graph_panel/graph_renderer.ts
  5. 13
      src/panel/graph_panel/models/analytic_unit.ts
  6. 15
      src/panel/graph_panel/partials/tab_analytics.html
  7. 4
      src/panel/graph_panel/services/analytic_service.ts

9
src/panel/graph_panel/colors.ts

@ -76,12 +76,15 @@ export const ANALYTIC_UNIT_COLORS = [
'#f8c171',
];
export const REGION_DELETE_COLOR_LIGHT = '#d1d1d1';
export const REGION_DELETE_COLOR_DARK = 'white';
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_FILL_COLOR = '#00f0ff';
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();
}

55
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,11 +15,13 @@ import { SegmentArray } from '../models/segment_array';
import { ServerInfo } from '../models/info';
import { Threshold, Condition } from '../models/threshold';
import {
import {
ANALYTIC_UNIT_COLORS,
LABELED_SEGMENT_BORDER_COLOR,
DELETED_SEGMENT_FILL_COLOR,
DELETED_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';
@ -26,10 +29,6 @@ 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;
export const LABELING_MODE_ALPHA = 0.7;
export class AnalyticController {
private _analyticUnitsSet: AnalyticUnitsSet;
@ -174,15 +173,15 @@ export class AnalyticController {
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) {
@ -251,9 +250,13 @@ export class AnalyticController {
await this._analyticService.updateMetric(unit.id, this._currentMetric, this._currentDatasource);
return this._analyticService.updateSegments(
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
@ -268,16 +271,16 @@ export class AnalyticController {
continue;
}
let defaultBorderColor = addAlphaToRGB(analyticUnit.labeledColor, REGION_STROKE_ALPHA);
let defaultFillColor = addAlphaToRGB(analyticUnit.labeledColor, 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);
labeledSegmentBorderColor = addAlphaToRGB(labeledSegmentBorderColor, SEGMENT_STROKE_ALPHA);
let deletedSegmentFillColor = tinycolor(analyticUnit.deletedColor).toRgbString();
deletedSegmentFillColor = addAlphaToRGB(deletedSegmentFillColor, REGION_FILL_ALPHA);
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) {
if(isEditMode && this.inLabelingMode && analyticUnit.selected) {
defaultBorderColor = addAlphaToRGB(defaultBorderColor, LABELING_MODE_ALPHA);
defaultFillColor = addAlphaToRGB(defaultFillColor, LABELING_MODE_ALPHA);
labeledSegmentBorderColor = addAlphaToRGB(labeledSegmentBorderColor, LABELING_MODE_ALPHA);
@ -329,11 +332,15 @@ export class AnalyticController {
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) {

33
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';
@ -156,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> {
@ -299,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);
@ -623,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();
}

44
src/panel/graph_panel/graph_renderer.ts

@ -1,16 +1,15 @@
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
AnalyticController
} from './controllers/analytic_controller';
import {
REGION_DELETE_COLOR_LIGHT,
REGION_DELETE_COLOR_DARK
REGION_UNLABEL_COLOR_LIGHT,
REGION_UNLABEL_COLOR_DARK
} from './colors';
import { GraphCtrl } from './graph_ctrl';
@ -149,14 +148,20 @@ export class GraphRenderer {
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
);
this._analyticController.addLabelSegment(segment, true);
} else {
}
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;
@ -339,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) {
color = this.contextSrv.user.lightTheme ?
REGION_DELETE_COLOR_LIGHT :
REGION_DELETE_COLOR_DARK;
} else {
if(this._analyticController.labelingMode === LabelingMode.DELETING) {
color = this._analyticController.labelingUnit.deletedColor;
}
if(this._analyticController.labelingMode === LabelingMode.LABELING) {
color = this._analyticController.labelingUnit.labeledColor;
}
fillAlpha = REGION_FILL_ALPHA;
strokeAlpha = REGION_STROKE_ALPHA;
if(this._analyticController.labelingMode === LabelingMode.UNLABELING) {
color = this.contextSrv.user.lightTheme ?
REGION_UNLABEL_COLOR_LIGHT :
REGION_UNLABEL_COLOR_DARK;
}
}
this.plot.getOptions().selection.color = color
this.plot.getOptions().selection.color = color;
}
private _buildFlotPairs(data) {
@ -810,7 +816,7 @@ export class GraphRenderer {
private _isHasticEvent(obj: any) {
return (obj.ctrlKey || obj.metaKey) &&
this.contextSrv.isEditor &&
this._analyticController.labelingMode;
this._analyticController.inLabelingMode;
}
}

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

@ -7,6 +7,13 @@ import { ANALYTIC_UNIT_COLORS } 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;
@ -71,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; }

15
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"
@ -66,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>
@ -87,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'"
>

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

@ -160,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();

Loading…
Cancel
Save