Commit 0bea6aba by Torkel Ödegaard

feat(plugins): migrated elasticsearch to new plugin editor model, also minor fixes

parent eecf844c
......@@ -5,7 +5,7 @@ import _ from 'lodash';
import coreModule from '../core_module';
function pluginDirectiveLoader($compile, datasourceSrv, $rootScope) {
function pluginDirectiveLoader($compile, datasourceSrv, $rootScope, $q) {
function getPluginComponentDirective(options) {
return function() {
......@@ -83,7 +83,7 @@ function pluginDirectiveLoader($compile, datasourceSrv, $rootScope) {
});
}
default: {
$rootScope.appEvent('alert-error', ['Plugin component error', 'could not find component '+ attrs.type]);
return $q.reject({message: "Could not find component type: " + attrs.type });
}
}
}
......@@ -106,6 +106,10 @@ function pluginDirectiveLoader($compile, datasourceSrv, $rootScope) {
return;
}
if (!componentInfo.Component) {
throw {message: 'Failed to find exported plugin component for ' + componentInfo.name};
}
if (!componentInfo.Component.registered) {
var directiveName = attrs.$normalize(componentInfo.name);
var directiveFn = getPluginComponentDirective(componentInfo);
......@@ -121,6 +125,8 @@ function pluginDirectiveLoader($compile, datasourceSrv, $rootScope) {
link: function(scope, elem, attrs) {
getModule(scope, attrs).then(function (componentInfo) {
registerPluginComponent(scope, elem, attrs, componentInfo);
}).catch(err => {
$rootScope.appEvent('alert-error', ['Plugin Error', err.message || err]);
});
}
};
......
declare var Datasource: any;
export default Datasource;
declare var ElasticDatasource: any;
export {ElasticDatasource};
......@@ -304,5 +304,7 @@ function (angular, _, moment, kbn, ElasticQueryBuilder, IndexPattern, ElasticRes
};
}
return ElasticDatasource;
return {
ElasticDatasource: ElasticDatasource
};
});
define([
'./datasource',
'./edit_view',
'./bucket_agg',
'./metric_agg',
],
function (ElasticDatasource, editView) {
'use strict';
function metricsQueryEditor() {
return {controller: 'ElasticQueryCtrl', templateUrl: 'public/app/plugins/datasource/elasticsearch/partials/query.editor.html'};
}
function metricsQueryOptions() {
return {templateUrl: 'public/app/plugins/datasource/elasticsearch/partials/query.options.html'};
}
function annotationsQueryEditor() {
return {templateUrl: 'public/app/plugins/datasource/elasticsearch/partials/annotations.editor.html'};
}
return {
Datasource: ElasticDatasource,
configView: editView.default,
annotationsQueryEditor: annotationsQueryEditor,
metricsQueryEditor: metricsQueryEditor,
metricsQueryOptions: metricsQueryOptions,
};
});
import {ElasticDatasource} from './datasource';
import {ElasticQueryCtrl} from './query_ctrl';
class ElasticConfigCtrl {
static templateUrl = 'public/app/plugins/datasource/elasticsearch/partials/config.html';
}
class ElasticQueryOptionsCtrl {
static templateUrl = 'public/app/plugins/datasource/elasticsearch/partials/query.options.html';
}
class ElasticAnnotationsQueryCtrl {
static templateUrl = 'public/app/plugins/datasource/elasticsearch/partials/annotations.editor.html';
}
export {
ElasticDatasource as Datasource,
ElasticQueryCtrl as QueryCtrl,
ElasticConfigCtrl as ConfigCtrl,
ElasticQueryOptionsCtrl as QueryOptionsCtrl,
ElasticAnnotationsQueryCtrl as AnnotationsQueryCtrl,
};
<div class="tight-form">
<ul class="tight-form-list pull-right">
<li ng-show="parserError" class="tight-form-item">
<a bs-tooltip="parserError" style="color: rgb(229, 189, 28)" role="menuitem">
<i class="fa fa-warning"></i>
</a>
</li>
<li class="tight-form-item small" ng-show="target.datasource">
<em>{{target.datasource}}</em>
</li>
<li class="tight-form-item">
<div class="dropdown">
<a class="pointer dropdown-toggle" data-toggle="dropdown" tabindex="1">
<i class="fa fa-bars"></i>
</a>
<ul class="dropdown-menu pull-right" role="menu">
<li role="menuitem"><a tabindex="1" ng-click="panelCtrl.duplicateDataQuery(target)">Duplicate</a></li>
<li role="menuitem"><a tabindex="1" ng-click="panelCtrl.moveDataQuery($index, $index-1)">Move up</a></li>
<li role="menuitem"><a tabindex="1" ng-click="panelCtrl.moveDataQuery($index, $index+1)">Move down</a></li>
</ul>
</div>
</li>
<query-editor-row ctrl="ctrl">
<li class="tight-form-item query-keyword" style="width: 75px">
Query
</li>
<li>
<input type="text" class="tight-form-input" style="width: 345px;" ng-model="ctrl.target.query" spellcheck='false' placeholder="Lucene query" ng-blur="ctrl.refresh()">
</li>
<li class="tight-form-item query-keyword">
Alias
</li>
<li>
<input type="text" class="tight-form-input" style="width: 200px;" ng-model="ctrl.target.alias" spellcheck='false' placeholder="alias patterns (empty = auto)" ng-blur="ctrl.refresh()">
</li>
</query-editor-row>
<li class="tight-form-item last">
<a class="pointer" tabindex="1" ng-click="panelCtrl.removeDataQuery(target)">
<i class="fa fa-remove"></i>
</a>
</li>
</ul>
<ul class="tight-form-list">
<li class="tight-form-item" style="min-width: 15px; text-align: center">
{{target.refId}}
</li>
<li>
<a class="tight-form-item" ng-click="target.hide = !target.hide; panelCtrl.refresh();" role="menuitem">
<i class="fa fa-eye"></i>
</a>
</li>
</ul>
<ul class="tight-form-list">
<li class="tight-form-item query-keyword" style="width: 75px">
Query
</li>
<li>
<input type="text" class="tight-form-input" style="width: 345px;" ng-model="target.query" spellcheck='false' placeholder="Lucene query" ng-blur="panelCtrl.refresh()">
</li>
<li class="tight-form-item query-keyword">
Alias
</li>
<li>
<input type="text" class="tight-form-input" style="width: 200px;" ng-model="target.alias" spellcheck='false' placeholder="alias patterns (empty = auto)" ng-blur="panelCtrl.refresh()">
</li>
</ul>
<div class="clearfix"></div>
<div ng-repeat="agg in ctrl.target.metrics">
<elastic-metric-agg
target="ctrl.target" index="$index"
get-fields="ctrl.getFields($fieldType)"
on-change="ctrl.queryUpdated()"
es-version="ctrl.esVersion">
</elastic-metric-agg>
</div>
<div ng-hide="target.rawQuery">
<div ng-repeat="agg in target.metrics">
<elastic-metric-agg
target="target" index="$index"
get-fields="getFields($fieldType)"
on-change="queryUpdated()"
es-version="esVersion">
</elastic-metric-agg>
</div>
<div ng-repeat="agg in target.bucketAggs">
<elastic-bucket-agg
target="target" index="$index"
get-fields="getFields($fieldType)"
on-change="queryUpdated()">
</elastic-bucket-agg>
</div>
<div ng-repeat="agg in ctrl.target.bucketAggs">
<elastic-bucket-agg
target="ctrl.target" index="$index"
get-fields="ctrl.getFields($fieldType)"
on-change="ctrl.queryUpdated()">
</elastic-bucket-agg>
</div>
......@@ -8,7 +8,7 @@
Group by time interval
</li>
<li>
<input type="text" class="input-medium tight-form-input" ng-model="ctrl.panel.interval" ng-blur="ctrl.refresh();"
<input type="text" class="input-medium tight-form-input" ng-model="ctrl.panelCtrl.panel.interval" ng-blur="ctrl.panelCtrl.refresh();"
spellcheck='false' placeholder="example: >10s">
</li>
<li class="tight-form-item">
......@@ -23,7 +23,7 @@
<i class="fa fa-info-circle"></i>
</li>
<li class="tight-form-item">
<a ng-click="ctrl.toggleEditorHelp(1);" bs-tooltip="'click to show helpful info'" data-placement="bottom">
<a ng-click="ctrl.panelCtrl.toggleEditorHelp(1);" bs-tooltip="'click to show helpful info'" data-placement="bottom">
alias patterns
</a>
</li>
......@@ -34,7 +34,7 @@
<div class="editor-row">
<div class="pull-left" style="margin-top: 30px;">
<div class="grafana-info-box span6" ng-if="ctrl.editorHelpIndex === 1">
<div class="grafana-info-box span6" ng-if="ctrl.panelCtrl.editorHelpIndex === 1">
<h5>Alias patterns</h5>
<ul ng-non-bindable>
<li>{{term fieldname}} = replaced with value of term group by</li>
......
define([
'angular',
],
function (angular) {
'use strict';
var module = angular.module('grafana.controllers');
module.controller('ElasticQueryCtrl', function($scope, $rootScope, $timeout, uiSegmentSrv) {
$scope.esVersion = $scope.datasource.esVersion;
$scope.panelCtrl = $scope.ctrl;
$scope.init = function() {
var target = $scope.target;
if (!target) { return; }
$scope.queryUpdated();
};
$scope.getFields = function(type) {
var jsonStr = angular.toJson({find: 'fields', type: type});
return $scope.datasource.metricFindQuery(jsonStr)
.then(uiSegmentSrv.transformToSegments(false))
.then(null, $scope.handleQueryError);
};
$scope.queryUpdated = function() {
var newJson = angular.toJson($scope.datasource.queryBuilder.build($scope.target), true);
if (newJson !== $scope.oldQueryRaw) {
$scope.rawQueryOld = newJson;
$scope.panelCtrl.refresh();
}
$rootScope.appEvent('elastic-query-updated');
};
$scope.handleQueryError = function(err) {
$scope.parserError = err.message || 'Failed to issue metric query';
return [];
};
$scope.init();
});
});
///<reference path="../../../headers/common.d.ts" />
import './bucket_agg';
import './metric_agg';
import angular from 'angular';
import _ from 'lodash';
import {QueryCtrl} from 'app/features/panel/panel';
export class ElasticQueryCtrl extends QueryCtrl {
static templateUrl = 'public/app/plugins/datasource/elasticsearch/partials/query.editor.html';
esVersion: any;
rawQueryOld: string;
/** @ngInject **/
constructor($scope, $injector, private $rootScope, private $timeout, private uiSegmentSrv) {
super($scope, $injector);
this.esVersion = this.datasource.esVersion;
this.queryUpdated();
}
getFields(type) {
var jsonStr = angular.toJson({find: 'fields', type: type});
return this.datasource.metricFindQuery(jsonStr)
.then(this.uiSegmentSrv.transformToSegments(false))
.catch(this.handleQueryError.bind(this));
}
queryUpdated() {
var newJson = angular.toJson(this.datasource.queryBuilder.build(this.target), true);
if (newJson !== this.rawQueryOld) {
this.rawQueryOld = newJson;
this.refresh();
}
this.$rootScope.appEvent('elastic-query-updated');
}
handleQueryError(err) {
this.error = err.message || 'Failed to issue metric query';
return [];
}
}
......@@ -3,7 +3,7 @@ import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/co
import moment from 'moment';
import angular from 'angular';
import helpers from 'test/specs/helpers';
import Datasource from "../datasource";
import {ElasticDatasource} from "../datasource";
describe('ElasticDatasource', function() {
var ctx = new helpers.ServiceTestContext();
......@@ -21,7 +21,7 @@ describe('ElasticDatasource', function() {
function createDatasource(instanceSettings) {
instanceSettings.jsonData = instanceSettings.jsonData || {};
ctx.ds = ctx.$injector.instantiate(Datasource, {instanceSettings: instanceSettings});
ctx.ds = ctx.$injector.instantiate(ElasticDatasource, {instanceSettings: instanceSettings});
}
describe('When testing datasource with index pattern', function() {
......
///<amd-dependency path="../query_ctrl" />
///<amd-dependency path="app/core/services/segment_srv" />
///<amd-dependency path="test/specs/helpers" name="helpers" />
import {describe, beforeEach, it, sinon, expect, angularMocks} from 'test/lib/common';
import helpers from 'test/specs/helpers';
describe('ElasticQueryCtrl', function() {
var ctx = new helpers.ControllerTestContext();
beforeEach(angularMocks.module('grafana.controllers'));
beforeEach(angularMocks.module('grafana.services'));
beforeEach(ctx.providePhase());
beforeEach(ctx.createControllerPhase('ElasticQueryCtrl'));
beforeEach(function() {
ctx.scope.target = {};
ctx.scope.$parent = { get_data: sinon.spy() };
ctx.scope.datasource = ctx.datasource;
ctx.scope.datasource.metricFindQuery = sinon.stub().returns(ctx.$q.when([]));
});
describe('init', function() {
beforeEach(function() {
ctx.scope.init();
});
});
});
......@@ -2,14 +2,15 @@
import angular from 'angular';
import {GrafanaDatasource} from './datasource';
import {QueryCtrl} from 'app/features/panel/panel';
class GrafanaMetricsQueryEditor {
class GrafanaQueryCtrl extends QueryCtrl {
static templateUrl = 'public/app/plugins/datasource/grafana/partials/query.editor.html';
}
export {
GrafanaDatasource,
GrafanaDatasource as Datasource,
GrafanaMetricsQueryEditor as MetricsQueryEditor,
GrafanaQueryCtrl as QueryCtrl,
};
<div class="tight-form">
<ul class="tight-form-list pull-right">
<li ng-show="parserError" class="tight-form-item">
<a bs-tooltip="parserError" style="color: rgb(229, 189, 28)" role="menuitem">
<i class="fa fa-warning"></i>
</a>
</li>
<li class="tight-form-item">
<div class="dropdown">
<a class="pointer dropdown-toggle" data-toggle="dropdown" tabindex="1">
<i class="fa fa-bars"></i>
</a>
<ul class="dropdown-menu pull-right" role="menu">
<li role="menuitem">
<a tabindex="1"
ng-click="duplicate()">
Duplicate
</a>
</li>
<li role="menuitem">
<a tabindex="1"
ng-click="moveMetricQuery($index, $index-1)">
Move up
</a>
</li>
<li role="menuitem">
<a tabindex="1"
ng-click="moveMetricQuery($index, $index+1)">
Move down
</a>
</li>
</ul>
</div>
</li>
<li class="tight-form-item last">
<a class="pointer" tabindex="1" ng-click="removeDataQuery(target)">
<i class="fa fa-remove"></i>
</a>
</li>
</ul>
<ul class="tight-form-list">
<li class="tight-form-item" style="min-width: 15px; text-align: center">
{{ctrl.target.refId}}
</li>
<li>
<a class="tight-form-item" ng-click="target.hide = !target.hide; get_data();" role="menuitem">
<i class="fa fa-eye"></i>
</a>
</li>
<li class="tight-form-item">
Test metric (fake data source)
</li>
</ul>
<div class="clearfix"></div>
</div>
<query-editor-row ctrl="ctrl">
<li class="tight-form-item">
Test metric (fake data source)
</li>
</query-editor-row>
......@@ -21,33 +21,4 @@ export {
InfluxAnnotationsQueryCtrl as AnnotationsQueryCtrl,
};
// define([
// './datasource',
// ],
// function (InfluxDatasource) {
// 'use strict';
//
// function influxMetricsQueryEditor() {
// return {controller: 'InfluxQueryCtrl', templateUrl: 'public/app/plugins/datasource/influxdb/partials/query.editor.html'};
// }
//
// function influxMetricsQueryOptions() {
// return {templateUrl: 'public/app/plugins/datasource/influxdb/partials/query.options.html'};
// }
//
// function influxAnnotationsQueryEditor() {
// return {templateUrl: 'public/app/plugins/datasource/influxdb/partials/annotations.editor.html'};
// }
//
// function influxConfigView() {
// return {templateUrl: 'public/app/plugins/datasource/influxdb/partials/config.html'};
// }
//
// return {
// Datasource: InfluxDatasource,
// metricsQueryEditor: influxMetricsQueryEditor,
// metricsQueryOptions: influxMetricsQueryOptions,
// annotationsQueryEditor: influxAnnotationsQueryEditor,
// configView: influxConfigView,
// };
// });
......@@ -8,7 +8,7 @@
Group by time interval
</li>
<li>
<input type="text" class="input-medium tight-form-input" ng-model="ctrl.panel.interval" ng-blur="ctrl.refresh();"
<input type="text" class="input-medium tight-form-input" ng-model="ctrl.panelCtrl.panel.interval" ng-blur="ctrl.panelCtrl.refresh();"
spellcheck='false' placeholder="example: >10s">
</li>
<li class="tight-form-item">
......@@ -24,17 +24,17 @@
<i class="fa fa-info-circle"></i>
</li>
<li class="tight-form-item">
<a ng-click="ctrl.toggleEditorHelp(1);" bs-tooltip="'click to show helpful info'" data-placement="bottom">
<a ng-click="ctrl.panelCtrl.toggleEditorHelp(1);" bs-tooltip="'click to show helpful info'" data-placement="bottom">
alias patterns
</a>
</li>
<li class="tight-form-item">
<a ng-click="ctrl.toggleEditorHelp(2)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
<a ng-click="ctrl.panelCtrl.toggleEditorHelp(2)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
stacking &amp; and fill
</a>
</li>
<li class="tight-form-item">
<a ng-click="ctrl.toggleEditorHelp(3)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
<a ng-click="ctrl.panelCtrl.toggleEditorHelp(3)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
group by time
</a>
</li>
......@@ -46,7 +46,7 @@
<div class="editor-row">
<div class="pull-left" style="margin-top: 30px;">
<div class="grafana-info-box span6" ng-if="ctrl.editorHelpIndex === 1">
<div class="grafana-info-box span6" ng-if="ctrl.panelCtrl.editorHelpIndex === 1">
<h5>Alias patterns</h5>
<ul>
<li>$m = replaced with measurement name</li>
......@@ -58,7 +58,7 @@
</ul>
</div>
<div class="grafana-info-box span6" ng-if="ctrl.editorHelpIndex === 2">
<div class="grafana-info-box span6" ng-if="ctrl.panelCtrl.editorHelpIndex === 2">
<h5>Stacking and fill</h5>
<ul>
<li>When stacking is enabled it important that points align</li>
......@@ -69,7 +69,7 @@
</ul>
</div>
<div class="grafana-info-box span6" ng-if="ctrl.editorHelpIndex === 3">
<div class="grafana-info-box span6" ng-if="ctrl.panelCtrl.editorHelpIndex === 3">
<h5>Group by time</h5>
<ul>
<li>Group by time is important, otherwise the query could return many thousands of datapoints that will slow down Grafana</li>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment