mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge branch 'query_part_refactor' into alerting
Conflicts: pkg/services/sqlstore/migrations/alert_mig.go pkg/services/sqlstore/migrations/heartbeat_mig.go
This commit is contained in:
@@ -5,33 +5,34 @@ import $ from 'jquery';
|
||||
import coreModule from 'app/core/core_module';
|
||||
|
||||
var template = `
|
||||
<div class="tight-form-func-controls">
|
||||
<span class="pointer fa fa-remove" ng-click="removeActionInternal()"></span>
|
||||
</div>
|
||||
|
||||
<a ng-click="toggleControls()" class="query-part-name">{{part.def.type}}</a>
|
||||
<div class="dropdown cascade-open">
|
||||
<a ng-click="showActionsMenu()" class="query-part-name pointer dropdown-toggle" data-toggle="dropdown">{{part.def.type}}</a>
|
||||
<span>(</span><span class="query-part-parameters"></span><span>)</span>
|
||||
<ul class="dropdown-menu">
|
||||
<li ng-repeat="action in partActions">
|
||||
<a ng-click="triggerPartAction(action)">{{action.text}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
`;
|
||||
|
||||
/** @ngInject */
|
||||
export function queryPartEditorDirective($compile, templateSrv) {
|
||||
|
||||
var paramTemplate = '<input type="text" style="display:none"' +
|
||||
' class="input-mini tight-form-func-param"></input>';
|
||||
var paramTemplate = '<input type="text" class="hide input-mini tight-form-func-param"></input>';
|
||||
|
||||
return {
|
||||
restrict: 'E',
|
||||
template: template,
|
||||
scope: {
|
||||
part: "=",
|
||||
removeAction: "&",
|
||||
partUpdated: "&",
|
||||
getOptions: "&",
|
||||
handleEvent: "&",
|
||||
},
|
||||
link: function postLink($scope, elem) {
|
||||
var part = $scope.part;
|
||||
var partDef = part.def;
|
||||
var $paramsContainer = elem.find('.query-part-parameters');
|
||||
var $controlsContainer = elem.find('.tight-form-func-controls');
|
||||
|
||||
$scope.partActions = [];
|
||||
|
||||
function clickFuncParam(paramIndex) {
|
||||
/*jshint validthis:true */
|
||||
@@ -63,7 +64,9 @@ export function queryPartEditorDirective($compile, templateSrv) {
|
||||
$link.html(templateSrv.highlightVariablesAsHtml(newValue));
|
||||
|
||||
part.updateParam($input.val(), paramIndex);
|
||||
$scope.$apply($scope.partUpdated);
|
||||
$scope.$apply(() => {
|
||||
$scope.handleEvent({$event: {name: 'part-param-changed'}});
|
||||
});
|
||||
}
|
||||
|
||||
$input.hide();
|
||||
@@ -91,7 +94,7 @@ export function queryPartEditorDirective($compile, templateSrv) {
|
||||
if (param.options) { return param.options; }
|
||||
|
||||
$scope.$apply(function() {
|
||||
$scope.getOptions().then(function(result) {
|
||||
$scope.handleEvent({$event: {name: 'get-param-options'}}).then(function(result) {
|
||||
var dynamicOptions = _.map(result, function(op) { return op.value; });
|
||||
callback(dynamicOptions);
|
||||
});
|
||||
@@ -124,24 +127,16 @@ export function queryPartEditorDirective($compile, templateSrv) {
|
||||
};
|
||||
}
|
||||
|
||||
$scope.toggleControls = function() {
|
||||
var targetDiv = elem.closest('.tight-form');
|
||||
|
||||
if (elem.hasClass('show-function-controls')) {
|
||||
elem.removeClass('show-function-controls');
|
||||
targetDiv.removeClass('has-open-function');
|
||||
$controlsContainer.hide();
|
||||
return;
|
||||
$scope.showActionsMenu = function() {
|
||||
if ($scope.partActions.length === 0) {
|
||||
$scope.handleEvent({$event: {name: 'get-part-actions'}}).then(res => {
|
||||
$scope.partActions = res;
|
||||
});
|
||||
}
|
||||
|
||||
elem.addClass('show-function-controls');
|
||||
targetDiv.addClass('has-open-function');
|
||||
$controlsContainer.show();
|
||||
};
|
||||
|
||||
$scope.removeActionInternal = function() {
|
||||
$scope.toggleControls();
|
||||
$scope.removeAction();
|
||||
$scope.triggerPartAction = function(action) {
|
||||
$scope.handleEvent({$event: {name: 'action', action: action}});
|
||||
};
|
||||
|
||||
function addElementsAndCompile() {
|
||||
|
||||
@@ -25,12 +25,6 @@ var alertQueryDef = new QueryPartDef({
|
||||
defaultParams: ['#A', '5m', 'now', 'avg']
|
||||
});
|
||||
|
||||
var reducerAvgDef = new QueryPartDef({
|
||||
type: 'avg',
|
||||
params: [],
|
||||
defaultParams: []
|
||||
});
|
||||
|
||||
var conditionTypes = [
|
||||
{text: 'Query', value: 'query'},
|
||||
];
|
||||
@@ -43,6 +37,19 @@ var evalFunctions = [
|
||||
{text: 'HAS NO VALUE' , value: 'no_value'}
|
||||
];
|
||||
|
||||
var reducerTypes = [
|
||||
{text: 'avg()', value: 'avg'},
|
||||
{text: 'min()', value: 'min'},
|
||||
{text: 'max()', value: 'max'},
|
||||
{text: 'sum()' , value: 'sum'},
|
||||
{text: 'count()', value: 'count'},
|
||||
];
|
||||
|
||||
function createReducerPart(model) {
|
||||
var def = new QueryPartDef({type: model.type, defaultParams: []});
|
||||
return new QueryPart(model, def);
|
||||
}
|
||||
|
||||
var severityLevels = [
|
||||
{text: 'Critical', value: 'critical'},
|
||||
{text: 'Warning', value: 'warning'},
|
||||
@@ -50,9 +57,10 @@ var severityLevels = [
|
||||
|
||||
export default {
|
||||
alertQueryDef: alertQueryDef,
|
||||
reducerAvgDef: reducerAvgDef,
|
||||
getSeverityIconClass: getSeverityIconClass,
|
||||
conditionTypes: conditionTypes,
|
||||
evalFunctions: evalFunctions,
|
||||
severityLevels: severityLevels,
|
||||
reducerTypes: reducerTypes,
|
||||
createReducerPart: createReducerPart,
|
||||
};
|
||||
|
||||
@@ -21,7 +21,7 @@ export class AlertTabCtrl {
|
||||
alertNotifications;
|
||||
|
||||
/** @ngInject */
|
||||
constructor(private $scope, private $timeout, private backendSrv, private dashboardSrv, private uiSegmentSrv) {
|
||||
constructor(private $scope, private $timeout, private backendSrv, private dashboardSrv, private uiSegmentSrv, private $q) {
|
||||
this.panelCtrl = $scope.ctrl;
|
||||
this.panel = this.panelCtrl.panel;
|
||||
this.$scope.ctrl = this;
|
||||
@@ -148,19 +148,46 @@ export class AlertTabCtrl {
|
||||
var cm: any = {source: source, type: source.type};
|
||||
|
||||
cm.queryPart = new QueryPart(source.query, alertDef.alertQueryDef);
|
||||
cm.reducerPart = new QueryPart({params: []}, alertDef.reducerAvgDef);
|
||||
cm.reducerPart = alertDef.createReducerPart(source.reducer);
|
||||
cm.evaluator = source.evaluator;
|
||||
|
||||
return cm;
|
||||
}
|
||||
|
||||
queryPartUpdated(conditionModel) {
|
||||
handleQueryPartEvent(conditionModel, evt) {
|
||||
switch (evt.name) {
|
||||
case "action-remove-part": {
|
||||
break;
|
||||
}
|
||||
case "get-part-actions": {
|
||||
return this.$q.when([]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleReducerPartEvent(conditionModel, evt) {
|
||||
switch (evt.name) {
|
||||
case "action": {
|
||||
conditionModel.source.reducer.type = evt.action.value;
|
||||
conditionModel.reducerPart = alertDef.createReducerPart(conditionModel.source.reducer);
|
||||
break;
|
||||
}
|
||||
case "get-part-actions": {
|
||||
var result = [];
|
||||
for (var type of alertDef.reducerTypes) {
|
||||
if (type.value !== conditionModel.source.reducer.type) {
|
||||
result.push(type);
|
||||
}
|
||||
}
|
||||
return this.$q.when(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addCondition(type) {
|
||||
var condition = this.buildDefaultCondition();
|
||||
// add to persited model
|
||||
this.alert.conditions.push(condition);
|
||||
this.panelCtrl.conditions.push(condition);
|
||||
// add to view model
|
||||
this.conditionModels.push(this.buildConditionModel(condition));
|
||||
}
|
||||
|
||||
@@ -49,12 +49,12 @@
|
||||
<span class="gf-form-label query-keyword width-5" ng-if="$index===0">WHEN</span>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<query-part-editor class="gf-form-label query-part" part="conditionModel.queryPart" part-updated="ctrl.queryPartUpdated(conditionModel)">
|
||||
<query-part-editor class="gf-form-label query-part" part="conditionModel.queryPart" handle-event="ctrl.handleQueryPartEvent(conditionModel, $event)">
|
||||
</query-part-editor>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label">Reducer</span>
|
||||
<query-part-editor class="gf-form-label query-part" part="conditionModel.reducerPart" part-updated="ctrl.reducerPartUpdated(conditionModel)">
|
||||
<query-part-editor class="gf-form-label query-part" part="conditionModel.reducerPart" handle-event="ctrl.handleReducerPartEvent(conditionModel, $event)">
|
||||
</query-part-editor>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
|
||||
@@ -35,12 +35,7 @@
|
||||
</div>
|
||||
|
||||
<div class="gf-form" ng-repeat="part in selectParts">
|
||||
<query-part-editor
|
||||
class="gf-form-label query-part"
|
||||
part="part"
|
||||
remove-action="ctrl.removeSelectPart(selectParts, part)"
|
||||
part-updated="ctrl.selectPartUpdated(selectParts, part)"
|
||||
get-options="ctrl.getPartOptions(part)">
|
||||
<query-part-editor class="gf-form-label query-part" part="part" handle-event="ctrl.handleSelectPartEvent(selectParts, part, $event)">
|
||||
</query-part-editor>
|
||||
</div>
|
||||
|
||||
@@ -62,11 +57,9 @@
|
||||
<span>GROUP BY</span>
|
||||
</label>
|
||||
|
||||
<query-part-editor
|
||||
ng-repeat="part in ctrl.queryModel.groupByParts"
|
||||
part="part"
|
||||
class="gf-form-label query-part"
|
||||
remove-action="ctrl.removeGroupByPart(part, $index)" part-updated="ctrl.refresh();" get-options="ctrl.getPartOptions(part)">
|
||||
<query-part-editor ng-repeat="part in ctrl.queryModel.groupByParts"
|
||||
part="part" class="gf-form-label query-part"
|
||||
handle-event="ctrl.handleGroupByPartEvent(part, $index, $event)">
|
||||
</query-part-editor>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ export class InfluxQueryCtrl extends QueryCtrl {
|
||||
measurementSegment: any;
|
||||
removeTagFilterSegment: any;
|
||||
|
||||
|
||||
/** @ngInject **/
|
||||
constructor($scope, $injector, private templateSrv, private $q, private uiSegmentSrv) {
|
||||
super($scope, $injector);
|
||||
@@ -106,23 +105,55 @@ export class InfluxQueryCtrl extends QueryCtrl {
|
||||
this.panelCtrl.refresh();
|
||||
}
|
||||
|
||||
removeGroupByPart(part, index) {
|
||||
this.queryModel.removeGroupByPart(part, index);
|
||||
this.panelCtrl.refresh();
|
||||
}
|
||||
|
||||
addSelectPart(selectParts, cat, subitem) {
|
||||
this.queryModel.addSelectPart(selectParts, subitem.value);
|
||||
this.panelCtrl.refresh();
|
||||
}
|
||||
|
||||
removeSelectPart(selectParts, part) {
|
||||
this.queryModel.removeSelectPart(selectParts, part);
|
||||
this.panelCtrl.refresh();
|
||||
handleSelectPartEvent(selectParts, part, evt) {
|
||||
switch (evt.name) {
|
||||
case "get-param-options": {
|
||||
var fieldsQuery = this.queryBuilder.buildExploreQuery('FIELDS');
|
||||
return this.datasource.metricFindQuery(fieldsQuery)
|
||||
.then(this.transformToSegments(true))
|
||||
.catch(this.handleQueryError.bind(this));
|
||||
}
|
||||
case "part-param-changed": {
|
||||
this.panelCtrl.refresh();
|
||||
break;
|
||||
}
|
||||
case "action": {
|
||||
this.queryModel.removeSelectPart(selectParts, part);
|
||||
this.panelCtrl.refresh();
|
||||
break;
|
||||
}
|
||||
case "get-part-actions": {
|
||||
return this.$q.when([{text: 'Remove', value: 'remove-part'}]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
selectPartUpdated() {
|
||||
this.panelCtrl.refresh();
|
||||
handleGroupByPartEvent(part, index, evt) {
|
||||
switch (evt.name) {
|
||||
case "get-param-options": {
|
||||
var tagsQuery = this.queryBuilder.buildExploreQuery('TAG_KEYS');
|
||||
return this.datasource.metricFindQuery(tagsQuery)
|
||||
.then(this.transformToSegments(true))
|
||||
.catch(this.handleQueryError.bind(this));
|
||||
}
|
||||
case "part-param-changed": {
|
||||
this.panelCtrl.refresh();
|
||||
break;
|
||||
}
|
||||
case "action": {
|
||||
this.queryModel.removeGroupByPart(part, index);
|
||||
this.panelCtrl.refresh();
|
||||
break;
|
||||
}
|
||||
case "get-part-actions": {
|
||||
return this.$q.when([{text: 'Remove', value: 'remove-part'}]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fixTagSegments() {
|
||||
@@ -167,21 +198,6 @@ export class InfluxQueryCtrl extends QueryCtrl {
|
||||
.catch(this.handleQueryError.bind(this));
|
||||
}
|
||||
|
||||
getPartOptions(part) {
|
||||
if (part.def.type === 'field') {
|
||||
var fieldsQuery = this.queryBuilder.buildExploreQuery('FIELDS');
|
||||
return this.datasource.metricFindQuery(fieldsQuery)
|
||||
.then(this.transformToSegments(true))
|
||||
.catch(this.handleQueryError.bind(this));
|
||||
}
|
||||
if (part.def.type === 'tag') {
|
||||
var tagsQuery = this.queryBuilder.buildExploreQuery('TAG_KEYS');
|
||||
return this.datasource.metricFindQuery(tagsQuery)
|
||||
.then(this.transformToSegments(true))
|
||||
.catch(this.handleQueryError.bind(true));
|
||||
}
|
||||
}
|
||||
|
||||
handleQueryError(err) {
|
||||
this.error = err.message || 'Failed to issue metric query';
|
||||
return [];
|
||||
@@ -243,11 +259,6 @@ export class InfluxQueryCtrl extends QueryCtrl {
|
||||
.catch(this.handleQueryError);
|
||||
}
|
||||
|
||||
setFill(fill) {
|
||||
this.target.fill = fill;
|
||||
this.panelCtrl.refresh();
|
||||
}
|
||||
|
||||
tagSegmentUpdated(segment, index) {
|
||||
this.tagSegments[index] = segment;
|
||||
|
||||
@@ -323,4 +334,3 @@ export class InfluxQueryCtrl extends QueryCtrl {
|
||||
return this.queryModel.render(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -140,6 +140,12 @@
|
||||
& > .dropdown-menu {
|
||||
display: block;
|
||||
}
|
||||
|
||||
&.cascade-open {
|
||||
.dropdown-menu {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Backdrop to catch body clicks on mobile, etc.
|
||||
|
||||
Reference in New Issue
Block a user