18 changed files with 558 additions and 320 deletions
@ -1,12 +1 @@ |
|||||||
<h3 class="page-heading">Enter your Hastic config</h3> |
|
||||||
<div class="gf-form-group"> |
|
||||||
<div class="gf-form"> |
|
||||||
<label class="gf-form-label width-10">Hastic server url</label> |
|
||||||
<input |
|
||||||
type="text" |
|
||||||
class="gf-form-input max-width-20" |
|
||||||
ng-model="ctrl.appModel.jsonData.hasticServerUrl" |
|
||||||
ng-blur="ctrl.normalizeUrl" |
|
||||||
/> |
|
||||||
</div> |
|
||||||
</div> |
|
||||||
|
@ -0,0 +1,33 @@ |
|||||||
|
import { normalizeUrl } from '../utlis'; |
||||||
|
import configTemplate from './partials/config.html'; |
||||||
|
|
||||||
|
|
||||||
|
export class HasticConfigCtrl { |
||||||
|
public static template = configTemplate; |
||||||
|
public ACCESS_OPTIONS = [ |
||||||
|
{ key: 'proxy', value: 'Server (Default)' }, |
||||||
|
{ key: 'direct', value: 'Browser' } |
||||||
|
]; |
||||||
|
|
||||||
|
public showAccessHelp = false; |
||||||
|
|
||||||
|
constructor(private $scope: any) { |
||||||
|
if(this.$scope.current === undefined) { |
||||||
|
this.$scope.current = { |
||||||
|
url: '', |
||||||
|
access: 'proxy' |
||||||
|
}; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
normalizeUrl() { |
||||||
|
if(this.$scope.current.url === '') { |
||||||
|
return; |
||||||
|
} |
||||||
|
this.$scope.current.url = normalizeUrl(this.$scope.current.url); |
||||||
|
} |
||||||
|
|
||||||
|
toggleAccessHelp() { |
||||||
|
this.showAccessHelp = !this.showAccessHelp; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,37 @@ |
|||||||
|
import HasticAPI from './hastic_api'; |
||||||
|
|
||||||
|
import { BackendSrv } from 'grafana/app/core/services/backend_srv'; |
||||||
|
|
||||||
|
export class HasticDatasource { |
||||||
|
private hastic: HasticAPI; |
||||||
|
|
||||||
|
/** @ngInject */ |
||||||
|
constructor(instanceSettings: any, backendSrv: BackendSrv) { |
||||||
|
this.hastic = new HasticAPI(instanceSettings, backendSrv); |
||||||
|
} |
||||||
|
|
||||||
|
async query(options: any) { |
||||||
|
console.log(options); |
||||||
|
} |
||||||
|
|
||||||
|
async testDatasource() { |
||||||
|
try { |
||||||
|
await this.hastic.get('/'); |
||||||
|
// TODO: check if it is hastic
|
||||||
|
return { |
||||||
|
status: 'success', title: 'Success', |
||||||
|
message: 'Datasource is working' |
||||||
|
}; |
||||||
|
} catch(err) { |
||||||
|
console.error(err); |
||||||
|
return { |
||||||
|
status: 'error', title: 'Error', |
||||||
|
message: 'Hastic connection error' |
||||||
|
}; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
metricFindQuery(options: any) { |
||||||
|
return []; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
import { BackendSrv } from 'grafana/app/core/services/backend_srv'; |
||||||
|
|
||||||
|
export default class HasticAPI { |
||||||
|
private url: string; |
||||||
|
|
||||||
|
constructor(instanceSettings: any, private backendSrv: BackendSrv) { |
||||||
|
this.url = instanceSettings.url; |
||||||
|
} |
||||||
|
|
||||||
|
get(url: string, params?: any) { |
||||||
|
return this._query('GET', url, params); |
||||||
|
} |
||||||
|
|
||||||
|
private async _query(method: string, url: string, data?: any) { |
||||||
|
method = method.toUpperCase(); |
||||||
|
let options: any = { |
||||||
|
method, |
||||||
|
url: this.url + url |
||||||
|
}; |
||||||
|
if(method === 'GET' || method === 'DELETE') { |
||||||
|
options.params = data; |
||||||
|
} else { |
||||||
|
options.data = data; |
||||||
|
} |
||||||
|
|
||||||
|
const response = await this.backendSrv.datasourceRequest(options); |
||||||
|
return response.data; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,10 @@ |
|||||||
|
import { HasticDatasource } from './datasource'; |
||||||
|
import { HasticQueryCtrl } from './query_ctrl'; |
||||||
|
import { HasticConfigCtrl } from './config_ctrl'; |
||||||
|
|
||||||
|
|
||||||
|
export { |
||||||
|
HasticDatasource as Datasource, |
||||||
|
HasticConfigCtrl as ConfigCtrl, |
||||||
|
HasticQueryCtrl as QueryCtrl |
||||||
|
}; |
@ -0,0 +1,87 @@ |
|||||||
|
<div class="gf-form-group"> |
||||||
|
<h3 class="page-heading">HTTP</h3> |
||||||
|
<div class="gf-form-group"> |
||||||
|
<div class="gf-form-inline"> |
||||||
|
<div class="gf-form max-width-30"> |
||||||
|
<span class="gf-form-label width-10">Hastic Server URL</span> |
||||||
|
<input |
||||||
|
class="gf-form-input" type="text" |
||||||
|
placeholder="http://localhost:8000" |
||||||
|
ng-model='ctrl.current.url' |
||||||
|
min-length="0" |
||||||
|
ng-pattern="/^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/" |
||||||
|
required |
||||||
|
ng-blur="ctrl.normalizeUrl()" |
||||||
|
/> |
||||||
|
<info-popover mode="right-absolute"> |
||||||
|
<p>Specify a complete Hastic Server HTTP URL (for example http://your_hastic_server:8000)</p> |
||||||
|
<span ng-show="ctrl.current.access === 'direct'"> |
||||||
|
Your access method is <em>Browser</em>, this means the URL |
||||||
|
needs to be accessible from the browser. |
||||||
|
</span> |
||||||
|
<span ng-show="ctrl.current.access === 'proxy'"> |
||||||
|
Your access method is <em>Server</em>, this means the URL |
||||||
|
needs to be accessible from the grafana backend/server. |
||||||
|
</span> |
||||||
|
</info-popover> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="gf-form-inline"> |
||||||
|
<div class="gf-form max-width-30"> |
||||||
|
<span class="gf-form-label width-10">Access</span> |
||||||
|
<div class="gf-form-select-wrapper max-width-24"> |
||||||
|
<select |
||||||
|
class="gf-form-input" |
||||||
|
ng-model="ctrl.current.access" |
||||||
|
ng-options="f.key as f.value for f in ctrl.ACCESS_OPTIONS" |
||||||
|
/> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
<div class="gf-form"> |
||||||
|
<label class="gf-form-label query-keyword pointer" ng-click="ctrl.toggleAccessHelp()"> |
||||||
|
Help |
||||||
|
<i class="fa fa-caret-down" ng-show="ctrl.showAccessHelp"></i> |
||||||
|
<i class="fa fa-caret-right" ng-hide="ctrl.showAccessHelp"> </i> |
||||||
|
</label> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="grafana-info-box m-t-2" ng-show="ctrl.showAccessHelp"> |
||||||
|
<p> |
||||||
|
Access mode controls how requests to the data source will be handled. |
||||||
|
<strong><i>Server</i></strong> access mode should be the preferred way if nothing else stated. |
||||||
|
</p> |
||||||
|
<div class="alert-title">Server access mode (Default):</div> |
||||||
|
<p> |
||||||
|
All requests will be made from the browser to Grafana backend/server which in turn will |
||||||
|
forward the requests to the data source and by that circumvent possible |
||||||
|
Cross-Origin Resource Sharing (CORS) requirements. |
||||||
|
The URL needs to be accessible from the grafana backend/server if you select this access mode. |
||||||
|
</p> |
||||||
|
<div class="alert-title">Browser access mode:</div> |
||||||
|
<p> |
||||||
|
All requests will be made from the browser directly to the data source and may be subject to |
||||||
|
Cross-Origin Resource Sharing (CORS) requirements. The URL needs to be accessible from the browser |
||||||
|
if you select this access mode. |
||||||
|
</p> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="gf-form-inline" ng-if="ctrl.current.access=='proxy'"> |
||||||
|
<div class="gf-form"> |
||||||
|
<span class="gf-form-label width-10">Whitelisted Cookies</span> |
||||||
|
<bootstrap-tagsinput |
||||||
|
ng-model="ctrl.current.jsonData.keepCookies" |
||||||
|
width-class="width-20" tagclass="label label-tag" |
||||||
|
placeholder="Add Name" |
||||||
|
/> |
||||||
|
<info-popover mode="right-absolute"> |
||||||
|
Grafana Proxy deletes forwarded cookies by default. Specify cookies by name |
||||||
|
that should be forwarded to the data source. |
||||||
|
</info-popover> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
|
@ -0,0 +1,12 @@ |
|||||||
|
{ |
||||||
|
"type": "datasource", |
||||||
|
"name": "Hastic Datasource", |
||||||
|
"id": "corpglory-hastic-datasource", |
||||||
|
"metrics": true, |
||||||
|
"info": { |
||||||
|
"logos": { |
||||||
|
"small": "../corpglory-hastic-app/img/icn-graph-panel.png", |
||||||
|
"large": "../corpglory-hastic-app/img/icn-graph-panel.png" |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
import template from './partials/query_ctrl.html'; |
||||||
|
|
||||||
|
import { QueryCtrl } from 'grafana/app/plugins/sdk'; |
||||||
|
|
||||||
|
export class HasticQueryCtrl extends QueryCtrl { |
||||||
|
static template = template; |
||||||
|
|
||||||
|
/** @ngInject */ |
||||||
|
constructor($scope, $injector) { |
||||||
|
super($scope, $injector); |
||||||
|
} |
||||||
|
} |
@ -1,210 +1,224 @@ |
|||||||
<div class="gf-form-button-row" ng-if="ctrl.analyticsController.serverStatus === false"> |
<div class="gf-form-group"> |
||||||
<h5>Hastic server at "{{ctrl.backendURL}}" is not available</h5> |
<div class="gf-form"> |
||||||
<button class="btn btn-inverse" ng-click="ctrl.runBackendConnectivityCheck()"> |
<label class="gf-form-label">Select Hastic datasource</label> |
||||||
<i class="fa fa-plug"></i> |
<select class="gf-form-input max-width-15" |
||||||
Reconnect to Hastic server |
ng-model="ctrl.panel.hasticDatasource" |
||||||
</button> |
ng-options="ds.id as ds.name for ds in ctrl.hasticDatasources" |
||||||
|
ng-change="ctrl.onHasticDatasourceChange()" |
||||||
|
/> |
||||||
|
</div> |
||||||
</div> |
</div> |
||||||
|
|
||||||
<div ng-if="ctrl.analyticsController.serverStatus === true"> |
<div class="gf-form"> |
||||||
<h5> Analytic Units </h5> |
<div class="gf-form-button-row" ng-if="ctrl.analyticsController.serverStatus === false"> |
||||||
<div class="editor-row"> |
<h5>Hastic server at "{{ctrl.backendURL}}" is not available</h5> |
||||||
<div class="gf-form" ng-repeat="analyticUnit in ctrl.analyticsController.analyticUnits"> |
<button class="btn btn-inverse" ng-click="ctrl.runBackendConnectivityCheck()"> |
||||||
|
<i class="fa fa-plug"></i> |
||||||
<label class="gf-form-label width-5"> |
Reconnect to Hastic server |
||||||
<i class="fa fa-info" bs-tooltip="'Analytic unit id: ' + analyticUnit.id"></i> |
</button> |
||||||
Name |
</div> |
||||||
</label> |
|
||||||
<input |
|
||||||
type="text" class="gf-form-input max-width-15" |
|
||||||
ng-model="analyticUnit.name" |
|
||||||
ng-change="ctrl.onAnalyticUnitNameChange(analyticUnit)" |
|
||||||
> |
|
||||||
|
|
||||||
<label class="gf-form-label width-4"> Type </label> |
|
||||||
<div class="gf-form-select-wrapper"> |
|
||||||
<select class="gf-form-input width-10" |
|
||||||
ng-model="analyticUnit.type" |
|
||||||
ng-options="type.value as type.name for type in ctrl.analyticUnitTypes[analyticUnit.detectorType]" |
|
||||||
ng-disabled="true" |
|
||||||
/> |
|
||||||
</div> |
|
||||||
|
|
||||||
<!-- |
|
||||||
<label class="gf-form-label width-6"> Confidence </label> |
|
||||||
<input |
|
||||||
type="number" class="gf-form-input width-5 ng-valid ng-scope ng-empty ng-dirty ng-valid-number ng-touched" |
|
||||||
placeholder="auto" bs-tooltip="'Override automatic decimal precision for legend and tooltips'" |
|
||||||
data-placement="right" ng-model="ctrl.panel.decimals" ng-change="ctrl.render()" ng-model-onblur="" data-original-title="" title="" |
|
||||||
/> |
|
||||||
--> |
|
||||||
|
|
||||||
<label class="gf-form-label width-8"> Positive Color </label> |
|
||||||
<span class="gf-form-label"> |
|
||||||
<color-picker |
|
||||||
color="analyticUnit.labeledColor" |
|
||||||
onChange="ctrl.onColorChange.bind(ctrl, analyticUnit.id, false)" |
|
||||||
/> |
|
||||||
</span> |
|
||||||
|
|
||||||
<!-- Hack to avoid Grafana's .gf-form-label + .gf-form-label css. Fix for https://github.com/hastic/hastic-grafana-app/issues/192 --> |
|
||||||
<div ng-if="analyticUnit.detectorType === 'pattern'"></div> |
|
||||||
|
|
||||||
<label ng-if="analyticUnit.detectorType === 'pattern'" class="gf-form-label width-8"> Negative Color </label> |
|
||||||
<span ng-if="analyticUnit.detectorType === 'pattern'" class="gf-form-label"> |
|
||||||
<color-picker |
|
||||||
color="analyticUnit.deletedColor" |
|
||||||
onChange="ctrl.onColorChange.bind(ctrl, analyticUnit.id, true)" |
|
||||||
/> |
|
||||||
</span> |
|
||||||
|
|
||||||
<label |
|
||||||
class="gf-form-label" |
|
||||||
ng-if="analyticUnit.detectorType === 'pattern'" |
|
||||||
ng-style="analyticUnit.status === 'LEARNING' && { 'cursor': 'not-allowed' }" |
|
||||||
> |
|
||||||
<a class="pointer" tabindex="1" |
|
||||||
ng-click="ctrl.onToggleLabelingMode(analyticUnit.id)" |
|
||||||
ng-disabled="analyticUnit.status === 'LEARNING'" |
|
||||||
> |
|
||||||
<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.saving" ng-disabled="true"> saving... </b> |
|
||||||
</a> |
|
||||||
</label> |
|
||||||
|
|
||||||
<select class="gf-form-input width-10" |
|
||||||
ng-model="ctrl.analyticsController.labelingMode" |
|
||||||
ng-options="type.value as type.name for type in [ |
|
||||||
{ name:'Label Positive', value: 'LABELING' }, |
|
||||||
{ name:'Label Negative', value: 'DELETING' }, |
|
||||||
{ name:'Unlabel', value: 'UNLABELING' } |
|
||||||
]" |
|
||||||
ng-if="analyticUnit.selected && !analyticUnit.saving" |
|
||||||
ng-disabled="analyticUnit.status === 'LEARNING'" |
|
||||||
/> |
|
||||||
|
|
||||||
<select class="gf-form-input width-7" |
|
||||||
ng-model="ctrl.analyticsController.getThreshold(analyticUnit.id).condition" |
|
||||||
ng-options="type for type in ctrl.analyticsController.conditions" |
|
||||||
ng-if="analyticUnit.detectorType === 'threshold'" |
|
||||||
/> |
|
||||||
<input |
|
||||||
class="gf-form-input width-5" |
|
||||||
type="number" |
|
||||||
ng-model="ctrl.analyticsController.getThreshold(analyticUnit.id).value" |
|
||||||
ng-if=" |
|
||||||
analyticUnit.detectorType === 'threshold' && |
|
||||||
ctrl.analyticsController.getThreshold(analyticUnit.id).condition != 'NO_DATA' |
|
||||||
" |
|
||||||
/> |
|
||||||
<!-- TODO set .saving flag to thresholds, when learning is in progress --> |
|
||||||
<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'" |
|
||||||
> |
|
||||||
Apply |
|
||||||
</button> |
|
||||||
|
|
||||||
<label class="gf-form-label" ng-hide="analyticUnit.selected"> |
<div ng-if="ctrl.analyticsController.serverStatus === true"> |
||||||
<a |
<h5> Analytic Units </h5> |
||||||
ng-if="analyticUnit.visible" |
<div class="editor-row"> |
||||||
bs-tooltip="'Hide. It`s visible now.'" |
<div class="gf-form" ng-repeat="analyticUnit in ctrl.analyticsController.analyticUnits"> |
||||||
ng-click="ctrl.onToggleVisibility(analyticUnit.id)" |
|
||||||
class="pointer" |
<label class="gf-form-label width-5"> |
||||||
> |
<i class="fa fa-info" bs-tooltip="'Analytic unit id: ' + analyticUnit.id"></i> |
||||||
<i class="fa fa-eye"></i> |
Name |
||||||
</a> |
</label> |
||||||
|
<input |
||||||
<a |
type="text" class="gf-form-input max-width-15" |
||||||
ng-if="!analyticUnit.visible" |
ng-model="analyticUnit.name" |
||||||
bs-tooltip="'Show. It`s hidden now.'" |
ng-change="ctrl.onAnalyticUnitNameChange(analyticUnit)" |
||||||
ng-click="ctrl.onToggleVisibility(analyticUnit.id)" |
|
||||||
class="pointer" |
|
||||||
> |
> |
||||||
<i class="fa fa-eye-slash"></i> |
|
||||||
</a> |
|
||||||
</label> |
|
||||||
|
|
||||||
<label class="gf-form-label"> |
|
||||||
<a |
|
||||||
ng-if="!analyticUnit.selected" |
|
||||||
ng-click="ctrl.onRemove(analyticUnit.id)" |
|
||||||
class="pointer" |
|
||||||
> |
|
||||||
<i class="fa fa-trash"></i> |
|
||||||
</a> |
|
||||||
|
|
||||||
<a |
<label class="gf-form-label width-4"> Type </label> |
||||||
ng-if="analyticUnit.selected" |
<div class="gf-form-select-wrapper"> |
||||||
ng-click="ctrl.onCancelLabeling(analyticUnit.id)" |
<select class="gf-form-input width-10" |
||||||
class="pointer" |
ng-model="analyticUnit.type" |
||||||
|
ng-options="type.value as type.name for type in ctrl.analyticUnitTypes[analyticUnit.detectorType]" |
||||||
|
ng-disabled="true" |
||||||
|
/> |
||||||
|
</div> |
||||||
|
|
||||||
|
<!-- |
||||||
|
<label class="gf-form-label width-6"> Confidence </label> |
||||||
|
<input |
||||||
|
type="number" class="gf-form-input width-5 ng-valid ng-scope ng-empty ng-dirty ng-valid-number ng-touched" |
||||||
|
placeholder="auto" bs-tooltip="'Override automatic decimal precision for legend and tooltips'" |
||||||
|
data-placement="right" ng-model="ctrl.panel.decimals" ng-change="ctrl.render()" ng-model-onblur="" data-original-title="" title="" |
||||||
|
/> |
||||||
|
--> |
||||||
|
|
||||||
|
<label class="gf-form-label width-8"> Positive Color </label> |
||||||
|
<span class="gf-form-label"> |
||||||
|
<color-picker |
||||||
|
color="analyticUnit.labeledColor" |
||||||
|
onChange="ctrl.onColorChange.bind(ctrl, analyticUnit.id, false)" |
||||||
|
/> |
||||||
|
</span> |
||||||
|
|
||||||
|
<!-- Hack to avoid Grafana's .gf-form-label + .gf-form-label css. Fix for https://github.com/hastic/hastic-grafana-app/issues/192 --> |
||||||
|
<div ng-if="analyticUnit.detectorType === 'pattern'"></div> |
||||||
|
|
||||||
|
<label ng-if="analyticUnit.detectorType === 'pattern'" class="gf-form-label width-8"> Negative Color </label> |
||||||
|
<span ng-if="analyticUnit.detectorType === 'pattern'" class="gf-form-label"> |
||||||
|
<color-picker |
||||||
|
color="analyticUnit.deletedColor" |
||||||
|
onChange="ctrl.onColorChange.bind(ctrl, analyticUnit.id, true)" |
||||||
|
/> |
||||||
|
</span> |
||||||
|
|
||||||
|
<label |
||||||
|
class="gf-form-label" |
||||||
|
ng-if="analyticUnit.detectorType === 'pattern'" |
||||||
|
ng-style="analyticUnit.status === 'LEARNING' && { 'cursor': 'not-allowed' }" |
||||||
> |
> |
||||||
<i class="fa fa-ban"></i> |
<a class="pointer" tabindex="1" |
||||||
</a> |
ng-click="ctrl.onToggleLabelingMode(analyticUnit.id)" |
||||||
</label> |
ng-disabled="analyticUnit.status === 'LEARNING'" |
||||||
|
> |
||||||
<label> |
<i class="fa fa-bar-chart" ng-if="!analyticUnit.saving"></i> |
||||||
<i ng-if="analyticUnit.status === 'LEARNING'" class="grafana-tip fa fa-leanpub ng-scope" bs-tooltip="'Learning'"></i> |
<i class="fa fa-spinner fa-spin" ng-if="analyticUnit.saving"></i> |
||||||
<i ng-if="analyticUnit.status === 'PENDING'" class="grafana-tip fa fa-list-ul ng-scope" bs-tooltip="'Pending'"></i> |
<b ng-if="analyticUnit.saving" ng-disabled="true"> saving... </b> |
||||||
<i ng-if="analyticUnit.status === 'FAILED'" class="grafana-tip fa fa-exclamation-circle ng-scope" bs-tooltip="'Error: ' + analyticUnit.error"></i> |
</a> |
||||||
</label> |
</label> |
||||||
|
|
||||||
</div> |
|
||||||
</div> |
|
||||||
|
|
||||||
<div class="editor-row" ng-if="ctrl.analyticsController.creatingNew"> |
|
||||||
<div class="gf-form"> |
|
||||||
<label class="gf-form-label width-4"> Name </label> |
|
||||||
<input |
|
||||||
type="text" class="gf-form-input max-width-15" |
|
||||||
ng-model="ctrl.analyticsController.newAnalyticUnit.name" |
|
||||||
> |
|
||||||
|
|
||||||
<label class="gf-form-label width-8"> Detector Type </label> |
|
||||||
<div class="gf-form-select-wrapper"> |
|
||||||
<select class="gf-form-input width-10" |
<select class="gf-form-input width-10" |
||||||
ng-model="ctrl.analyticsController.newAnalyticUnit.detectorType" |
ng-model="ctrl.analyticsController.labelingMode" |
||||||
ng-options="analyticUnitDetectorType for analyticUnitDetectorType in ctrl.analyticUnitDetectorTypes" |
ng-options="type.value as type.name for type in [ |
||||||
ng-change="ctrl.analyticsController.onAnalyticUnitDetectorChange(ctrl.analyticUnitTypes);" |
{ name:'Label Positive', value: 'LABELING' }, |
||||||
|
{ name:'Label Negative', value: 'DELETING' }, |
||||||
|
{ name:'Unlabel', value: 'UNLABELING' } |
||||||
|
]" |
||||||
|
ng-if="analyticUnit.selected && !analyticUnit.saving" |
||||||
|
ng-disabled="analyticUnit.status === 'LEARNING'" |
||||||
/> |
/> |
||||||
</div> |
|
||||||
|
|
||||||
<label class="gf-form-label width-8"> Type </label> |
<select class="gf-form-input width-7" |
||||||
<div class="gf-form-select-wrapper"> |
ng-model="ctrl.analyticsController.getThreshold(analyticUnit.id).condition" |
||||||
<select class="gf-form-input width-10" |
ng-options="type for type in ctrl.analyticsController.conditions" |
||||||
ng-model="ctrl.analyticsController.newAnalyticUnit.type" |
ng-if="analyticUnit.detectorType === 'threshold'" |
||||||
ng-options=" |
/> |
||||||
type.value as type.name |
<input |
||||||
for type in ctrl.analyticUnitTypes[ctrl.analyticsController.newAnalyticUnit.detectorType] |
class="gf-form-input width-5" |
||||||
|
type="number" |
||||||
|
ng-model="ctrl.analyticsController.getThreshold(analyticUnit.id).value" |
||||||
|
ng-if=" |
||||||
|
analyticUnit.detectorType === 'threshold' && |
||||||
|
ctrl.analyticsController.getThreshold(analyticUnit.id).condition != 'NO_DATA' |
||||||
" |
" |
||||||
/> |
/> |
||||||
|
<!-- TODO set .saving flag to thresholds, when learning is in progress --> |
||||||
|
<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'" |
||||||
|
> |
||||||
|
Apply |
||||||
|
</button> |
||||||
|
|
||||||
|
<label class="gf-form-label" ng-hide="analyticUnit.selected"> |
||||||
|
<a |
||||||
|
ng-if="analyticUnit.visible" |
||||||
|
bs-tooltip="'Hide. It`s visible now.'" |
||||||
|
ng-click="ctrl.onToggleVisibility(analyticUnit.id)" |
||||||
|
class="pointer" |
||||||
|
> |
||||||
|
<i class="fa fa-eye"></i> |
||||||
|
</a> |
||||||
|
|
||||||
|
<a |
||||||
|
ng-if="!analyticUnit.visible" |
||||||
|
bs-tooltip="'Show. It`s hidden now.'" |
||||||
|
ng-click="ctrl.onToggleVisibility(analyticUnit.id)" |
||||||
|
class="pointer" |
||||||
|
> |
||||||
|
<i class="fa fa-eye-slash"></i> |
||||||
|
</a> |
||||||
|
</label> |
||||||
|
|
||||||
|
<label class="gf-form-label"> |
||||||
|
<a |
||||||
|
ng-if="!analyticUnit.selected" |
||||||
|
ng-click="ctrl.onRemove(analyticUnit.id)" |
||||||
|
class="pointer" |
||||||
|
> |
||||||
|
<i class="fa fa-trash"></i> |
||||||
|
</a> |
||||||
|
|
||||||
|
<a |
||||||
|
ng-if="analyticUnit.selected" |
||||||
|
ng-click="ctrl.onCancelLabeling(analyticUnit.id)" |
||||||
|
class="pointer" |
||||||
|
> |
||||||
|
<i class="fa fa-ban"></i> |
||||||
|
</a> |
||||||
|
</label> |
||||||
|
|
||||||
|
<label> |
||||||
|
<i ng-if="analyticUnit.status === 'LEARNING'" class="grafana-tip fa fa-leanpub ng-scope" bs-tooltip="'Learning'"></i> |
||||||
|
<i ng-if="analyticUnit.status === 'PENDING'" class="grafana-tip fa fa-list-ul ng-scope" bs-tooltip="'Pending'"></i> |
||||||
|
<i ng-if="analyticUnit.status === 'FAILED'" class="grafana-tip fa fa-exclamation-circle ng-scope" bs-tooltip="'Error: ' + analyticUnit.error"></i> |
||||||
|
</label> |
||||||
|
|
||||||
</div> |
</div> |
||||||
|
</div> |
||||||
|
|
||||||
|
<div class="editor-row" ng-if="ctrl.analyticsController.creatingNew"> |
||||||
|
<div class="gf-form"> |
||||||
|
<label class="gf-form-label width-4"> Name </label> |
||||||
|
<input |
||||||
|
type="text" class="gf-form-input max-width-15" |
||||||
|
ng-model="ctrl.analyticsController.newAnalyticUnit.name" |
||||||
|
> |
||||||
|
|
||||||
<label class="gf-form-label"> |
<label class="gf-form-label width-8"> Detector Type </label> |
||||||
<a class="pointer" tabindex="1" ng-click="ctrl.saveNew()"> |
<div class="gf-form-select-wrapper"> |
||||||
<b ng-if="!ctrl.analyticsController.saving"> create </b> |
<select class="gf-form-input width-10" |
||||||
<b ng-if="ctrl.analyticsController.saving" ng-disabled="true"> saving... </b> |
ng-model="ctrl.analyticsController.newAnalyticUnit.detectorType" |
||||||
</a> |
ng-options="analyticUnitDetectorType for analyticUnitDetectorType in ctrl.analyticUnitDetectorTypes" |
||||||
</label> |
ng-change="ctrl.analyticsController.onAnalyticUnitDetectorChange(ctrl.analyticUnitTypes);" |
||||||
|
/> |
||||||
|
</div> |
||||||
|
|
||||||
|
<label class="gf-form-label width-8"> Type </label> |
||||||
|
<div class="gf-form-select-wrapper"> |
||||||
|
<select class="gf-form-input width-10" |
||||||
|
ng-model="ctrl.analyticsController.newAnalyticUnit.type" |
||||||
|
ng-options=" |
||||||
|
type.value as type.name |
||||||
|
for type in ctrl.analyticUnitTypes[ctrl.analyticsController.newAnalyticUnit.detectorType] |
||||||
|
" |
||||||
|
/> |
||||||
|
</div> |
||||||
|
|
||||||
|
<label class="gf-form-label"> |
||||||
|
<a class="pointer" tabindex="1" ng-click="ctrl.saveNew()"> |
||||||
|
<b ng-if="!ctrl.analyticsController.saving"> create </b> |
||||||
|
<b ng-if="ctrl.analyticsController.saving" ng-disabled="true"> saving... </b> |
||||||
|
</a> |
||||||
|
</label> |
||||||
|
</div> |
||||||
</div> |
</div> |
||||||
</div> |
|
||||||
|
|
||||||
<div class="gf-form-button-row" ng-if="!ctrl.analyticsController.creatingAnalyticUnit"> |
<div class="gf-form-button-row" ng-if="!ctrl.analyticsController.creatingAnalyticUnit"> |
||||||
<button class="btn btn-inverse" ng-click="ctrl.createNew()"> |
<button class="btn btn-inverse" ng-click="ctrl.createNew()"> |
||||||
<i class="fa fa-plus"></i> |
<i class="fa fa-plus"></i> |
||||||
Add Analytic Unit |
Add Analytic Unit |
||||||
</button> |
</button> |
||||||
</div> |
</div> |
||||||
<div class="gf-form-button-row"> |
<div class="gf-form-button-row"> |
||||||
<button class="gf-form-label width-10 pointer" ng-click="ctrl.showHelp = !ctrl.showHelp"> |
<button class="gf-form-label width-10 pointer" ng-click="ctrl.showHelp = !ctrl.showHelp"> |
||||||
Show Help |
Show Help |
||||||
<i class="fa fa-caret-down" ng-show="ctrl.showHelp"></i> |
<i class="fa fa-caret-down" ng-show="ctrl.showHelp"></i> |
||||||
<i class="fa fa-caret-right" ng-hide="ctrl.showHelp"></i> |
<i class="fa fa-caret-right" ng-hide="ctrl.showHelp"></i> |
||||||
</button> |
</button> |
||||||
|
</div> |
||||||
</div> |
</div> |
||||||
|
</div> |
||||||
|
|
||||||
<div class="gf-form" ng-show="ctrl.showHelp" ng-bind-html="ctrl.analyticsController.helpSectionText"></div> |
<div class="gf-form" ng-show="ctrl.showHelp" ng-bind-html="ctrl.analyticsController.helpSectionText"></div> |
||||||
|
|
||||||
|
Loading…
Reference in new issue