mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge branch 'master' into settings-icons-fix
This commit is contained in:
@@ -117,6 +117,14 @@ export function grafanaAppDirective(playlistSrv, contextSrv, $timeout, $rootScop
|
||||
appEvents.emit('toggle-kiosk-mode');
|
||||
}
|
||||
|
||||
// check for 'inactive' url param for clean looks like kiosk, but with title
|
||||
if (data.params.inactive) {
|
||||
body.addClass('user-activity-low');
|
||||
|
||||
// for some reason, with this class it looks cleanest
|
||||
body.addClass('sidemenu-open');
|
||||
}
|
||||
|
||||
// close all drops
|
||||
for (let drop of Drop.drops) {
|
||||
drop.destroy();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// Licence MIT, Copyright (c) 2015 Mohsen Azimi
|
||||
|
||||
/*
|
||||
* Escapes `"` charachters from string
|
||||
* Escapes `"` characters from string
|
||||
*/
|
||||
function escapeString(str: string): string {
|
||||
return str.replace('"', '"');
|
||||
@@ -100,7 +100,7 @@ export function cssClass(className: string): string {
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates a new DOM element wiht given type and class
|
||||
* Creates a new DOM element with given type and class
|
||||
* TODO: move me to helpers
|
||||
*/
|
||||
export function createElement(type: string, className?: string, content?: Element | string): Element {
|
||||
|
||||
@@ -146,7 +146,7 @@ export class JsonExplorer {
|
||||
}
|
||||
|
||||
/*
|
||||
* did we recieve a key argument?
|
||||
* did we receive a key argument?
|
||||
* This means that the formatter was called as a sub formatter of a parent formatter
|
||||
*/
|
||||
private get hasKey(): boolean {
|
||||
|
||||
@@ -108,7 +108,7 @@ function (_, $, coreModule) {
|
||||
$input.val('');
|
||||
$button.show();
|
||||
$button.focus();
|
||||
// clicking the function dropdown menu wont
|
||||
// clicking the function dropdown menu won't
|
||||
// work if you remove class at once
|
||||
setTimeout(function() {
|
||||
elem.removeClass('open');
|
||||
@@ -222,7 +222,7 @@ function (_, $, coreModule) {
|
||||
$input.val('');
|
||||
$button.show();
|
||||
$button.focus();
|
||||
// clicking the function dropdown menu wont
|
||||
// clicking the function dropdown menu won't
|
||||
// work if you remove class at once
|
||||
setTimeout(function() {
|
||||
elem.removeClass('open');
|
||||
|
||||
@@ -1,283 +0,0 @@
|
||||
define([
|
||||
'angular',
|
||||
'lodash',
|
||||
'../core_module',
|
||||
],
|
||||
function (angular, _, coreModule) {
|
||||
'use strict';
|
||||
|
||||
coreModule.default.controller('ValueSelectDropdownCtrl', function($q) {
|
||||
var vm = this;
|
||||
|
||||
vm.show = function() {
|
||||
vm.oldVariableText = vm.variable.current.text;
|
||||
vm.highlightIndex = -1;
|
||||
|
||||
vm.options = vm.variable.options;
|
||||
vm.selectedValues = _.filter(vm.options, {selected: true});
|
||||
|
||||
vm.tags = _.map(vm.variable.tags, function(value) {
|
||||
var tag = { text: value, selected: false };
|
||||
_.each(vm.variable.current.tags, function(tagObj) {
|
||||
if (tagObj.text === value) {
|
||||
tag = tagObj;
|
||||
}
|
||||
});
|
||||
return tag;
|
||||
});
|
||||
|
||||
vm.search = {
|
||||
query: '',
|
||||
options: vm.options.slice(0, Math.min(vm.options.length, 1000))
|
||||
};
|
||||
|
||||
vm.dropdownVisible = true;
|
||||
};
|
||||
|
||||
vm.updateLinkText = function() {
|
||||
var current = vm.variable.current;
|
||||
|
||||
if (current.tags && current.tags.length) {
|
||||
// filer out values that are in selected tags
|
||||
var selectedAndNotInTag = _.filter(vm.variable.options, function(option) {
|
||||
if (!option.selected) { return false; }
|
||||
for (var i = 0; i < current.tags.length; i++) {
|
||||
var tag = current.tags[i];
|
||||
if (_.indexOf(tag.values, option.value) !== -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
// convert values to text
|
||||
var currentTexts = _.map(selectedAndNotInTag, 'text');
|
||||
|
||||
// join texts
|
||||
vm.linkText = currentTexts.join(' + ');
|
||||
if (vm.linkText.length > 0) {
|
||||
vm.linkText += ' + ';
|
||||
}
|
||||
} else {
|
||||
vm.linkText = vm.variable.current.text;
|
||||
}
|
||||
};
|
||||
|
||||
vm.clearSelections = function() {
|
||||
_.each(vm.options, function(option) {
|
||||
option.selected = false;
|
||||
});
|
||||
|
||||
vm.selectionsChanged(false);
|
||||
};
|
||||
|
||||
vm.selectTag = function(tag) {
|
||||
tag.selected = !tag.selected;
|
||||
var tagValuesPromise;
|
||||
if (!tag.values) {
|
||||
tagValuesPromise = vm.variable.getValuesForTag(tag.text);
|
||||
} else {
|
||||
tagValuesPromise = $q.when(tag.values);
|
||||
}
|
||||
|
||||
tagValuesPromise.then(function(values) {
|
||||
tag.values = values;
|
||||
tag.valuesText = values.join(' + ');
|
||||
_.each(vm.options, function(option) {
|
||||
if (_.indexOf(tag.values, option.value) !== -1) {
|
||||
option.selected = tag.selected;
|
||||
}
|
||||
});
|
||||
|
||||
vm.selectionsChanged(false);
|
||||
});
|
||||
};
|
||||
|
||||
vm.keyDown = function (evt) {
|
||||
if (evt.keyCode === 27) {
|
||||
vm.hide();
|
||||
}
|
||||
if (evt.keyCode === 40) {
|
||||
vm.moveHighlight(1);
|
||||
}
|
||||
if (evt.keyCode === 38) {
|
||||
vm.moveHighlight(-1);
|
||||
}
|
||||
if (evt.keyCode === 13) {
|
||||
if (vm.search.options.length === 0) {
|
||||
vm.commitChanges();
|
||||
} else {
|
||||
vm.selectValue(vm.search.options[vm.highlightIndex], {}, true, false);
|
||||
}
|
||||
}
|
||||
if (evt.keyCode === 32) {
|
||||
vm.selectValue(vm.search.options[vm.highlightIndex], {}, false, false);
|
||||
}
|
||||
};
|
||||
|
||||
vm.moveHighlight = function(direction) {
|
||||
vm.highlightIndex = (vm.highlightIndex + direction) % vm.search.options.length;
|
||||
};
|
||||
|
||||
vm.selectValue = function(option, event, commitChange, excludeOthers) {
|
||||
if (!option) { return; }
|
||||
|
||||
option.selected = vm.variable.multi ? !option.selected: true;
|
||||
|
||||
commitChange = commitChange || false;
|
||||
excludeOthers = excludeOthers || false;
|
||||
|
||||
var setAllExceptCurrentTo = function(newValue) {
|
||||
_.each(vm.options, function(other) {
|
||||
if (option !== other) { other.selected = newValue; }
|
||||
});
|
||||
};
|
||||
|
||||
// commit action (enter key), should not deselect it
|
||||
if (commitChange) {
|
||||
option.selected = true;
|
||||
}
|
||||
|
||||
if (option.text === 'All' || excludeOthers) {
|
||||
setAllExceptCurrentTo(false);
|
||||
commitChange = true;
|
||||
}
|
||||
else if (!vm.variable.multi) {
|
||||
setAllExceptCurrentTo(false);
|
||||
commitChange = true;
|
||||
} else if (event.ctrlKey || event.metaKey || event.shiftKey) {
|
||||
commitChange = true;
|
||||
setAllExceptCurrentTo(false);
|
||||
}
|
||||
|
||||
vm.selectionsChanged(commitChange);
|
||||
};
|
||||
|
||||
vm.selectionsChanged = function(commitChange) {
|
||||
vm.selectedValues = _.filter(vm.options, {selected: true});
|
||||
|
||||
if (vm.selectedValues.length > 1) {
|
||||
if (vm.selectedValues[0].text === 'All') {
|
||||
vm.selectedValues[0].selected = false;
|
||||
vm.selectedValues = vm.selectedValues.slice(1, vm.selectedValues.length);
|
||||
}
|
||||
}
|
||||
|
||||
// validate selected tags
|
||||
_.each(vm.tags, function(tag) {
|
||||
if (tag.selected) {
|
||||
_.each(tag.values, function(value) {
|
||||
if (!_.find(vm.selectedValues, {value: value})) {
|
||||
tag.selected = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
vm.selectedTags = _.filter(vm.tags, {selected: true});
|
||||
vm.variable.current.value = _.map(vm.selectedValues, 'value');
|
||||
vm.variable.current.text = _.map(vm.selectedValues, 'text').join(' + ');
|
||||
vm.variable.current.tags = vm.selectedTags;
|
||||
|
||||
if (!vm.variable.multi) {
|
||||
vm.variable.current.value = vm.selectedValues[0].value;
|
||||
}
|
||||
|
||||
if (commitChange) {
|
||||
vm.commitChanges();
|
||||
}
|
||||
};
|
||||
|
||||
vm.commitChanges = function() {
|
||||
// if we have a search query and no options use that
|
||||
if (vm.search.options.length === 0 && vm.search.query.length > 0) {
|
||||
vm.variable.current = {text: vm.search.query, value: vm.search.query};
|
||||
}
|
||||
else if (vm.selectedValues.length === 0) {
|
||||
// make sure one option is selected
|
||||
vm.options[0].selected = true;
|
||||
vm.selectionsChanged(false);
|
||||
}
|
||||
|
||||
vm.dropdownVisible = false;
|
||||
vm.updateLinkText();
|
||||
|
||||
if (vm.variable.current.text !== vm.oldVariableText) {
|
||||
vm.onUpdated();
|
||||
}
|
||||
};
|
||||
|
||||
vm.queryChanged = function() {
|
||||
vm.highlightIndex = -1;
|
||||
vm.search.options = _.filter(vm.options, function(option) {
|
||||
return option.text.toLowerCase().indexOf(vm.search.query.toLowerCase()) !== -1;
|
||||
});
|
||||
|
||||
vm.search.options = vm.search.options.slice(0, Math.min(vm.search.options.length, 1000));
|
||||
};
|
||||
|
||||
vm.init = function() {
|
||||
vm.selectedTags = vm.variable.current.tags || [];
|
||||
vm.updateLinkText();
|
||||
};
|
||||
|
||||
});
|
||||
|
||||
coreModule.default.directive('valueSelectDropdown', function($compile, $window, $timeout, $rootScope) {
|
||||
return {
|
||||
scope: { variable: "=", onUpdated: "&"},
|
||||
templateUrl: 'public/app/partials/valueSelectDropdown.html',
|
||||
controller: 'ValueSelectDropdownCtrl',
|
||||
controllerAs: 'vm',
|
||||
bindToController: true,
|
||||
link: function(scope, elem) {
|
||||
var bodyEl = angular.element($window.document.body);
|
||||
var linkEl = elem.find('.variable-value-link');
|
||||
var inputEl = elem.find('input');
|
||||
|
||||
function openDropdown() {
|
||||
inputEl.css('width', Math.max(linkEl.width(), 80) + 'px');
|
||||
|
||||
inputEl.show();
|
||||
linkEl.hide();
|
||||
|
||||
inputEl.focus();
|
||||
$timeout(function() { bodyEl.on('click', bodyOnClick); }, 0, false);
|
||||
}
|
||||
|
||||
function switchToLink() {
|
||||
inputEl.hide();
|
||||
linkEl.show();
|
||||
bodyEl.off('click', bodyOnClick);
|
||||
}
|
||||
|
||||
function bodyOnClick (e) {
|
||||
if (elem.has(e.target).length === 0) {
|
||||
scope.$apply(function() {
|
||||
scope.vm.commitChanges();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
scope.$watch('vm.dropdownVisible', function(newValue) {
|
||||
if (newValue) {
|
||||
openDropdown();
|
||||
} else {
|
||||
switchToLink();
|
||||
}
|
||||
});
|
||||
|
||||
var cleanUp = $rootScope.$on('template-variable-value-updated', function() {
|
||||
scope.vm.updateLinkText();
|
||||
});
|
||||
|
||||
scope.$on("$destroy", function() {
|
||||
cleanUp();
|
||||
});
|
||||
|
||||
scope.vm.init();
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
});
|
||||
305
public/app/core/directives/value_select_dropdown.ts
Normal file
305
public/app/core/directives/value_select_dropdown.ts
Normal file
@@ -0,0 +1,305 @@
|
||||
import angular from 'angular';
|
||||
import _ from 'lodash';
|
||||
import coreModule from '../core_module';
|
||||
|
||||
export class ValueSelectDropdownCtrl {
|
||||
dropdownVisible: any;
|
||||
highlightIndex: any;
|
||||
linkText: any;
|
||||
oldVariableText: any;
|
||||
options: any;
|
||||
search: any;
|
||||
selectedTags: any;
|
||||
selectedValues: any;
|
||||
tags: any;
|
||||
variable: any;
|
||||
|
||||
hide: any;
|
||||
onUpdated: any;
|
||||
|
||||
/** @ngInject */
|
||||
constructor(private $q) {}
|
||||
|
||||
show() {
|
||||
this.oldVariableText = this.variable.current.text;
|
||||
this.highlightIndex = -1;
|
||||
|
||||
this.options = this.variable.options;
|
||||
this.selectedValues = _.filter(this.options, { selected: true });
|
||||
|
||||
this.tags = _.map(this.variable.tags, value => {
|
||||
let tag = { text: value, selected: false };
|
||||
_.each(this.variable.current.tags, tagObj => {
|
||||
if (tagObj.text === value) {
|
||||
tag = tagObj;
|
||||
}
|
||||
});
|
||||
return tag;
|
||||
});
|
||||
|
||||
this.search = {
|
||||
query: '',
|
||||
options: this.options.slice(0, Math.min(this.options.length, 1000)),
|
||||
};
|
||||
|
||||
this.dropdownVisible = true;
|
||||
}
|
||||
|
||||
updateLinkText() {
|
||||
let current = this.variable.current;
|
||||
|
||||
if (current.tags && current.tags.length) {
|
||||
// filer out values that are in selected tags
|
||||
let selectedAndNotInTag = _.filter(this.variable.options, option => {
|
||||
if (!option.selected) {
|
||||
return false;
|
||||
}
|
||||
for (let i = 0; i < current.tags.length; i++) {
|
||||
let tag = current.tags[i];
|
||||
if (_.indexOf(tag.values, option.value) !== -1) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
// convert values to text
|
||||
let currentTexts = _.map(selectedAndNotInTag, 'text');
|
||||
|
||||
// join texts
|
||||
this.linkText = currentTexts.join(' + ');
|
||||
if (this.linkText.length > 0) {
|
||||
this.linkText += ' + ';
|
||||
}
|
||||
} else {
|
||||
this.linkText = this.variable.current.text;
|
||||
}
|
||||
}
|
||||
|
||||
clearSelections() {
|
||||
_.each(this.options, option => {
|
||||
option.selected = false;
|
||||
});
|
||||
|
||||
this.selectionsChanged(false);
|
||||
}
|
||||
|
||||
selectTag(tag) {
|
||||
tag.selected = !tag.selected;
|
||||
let tagValuesPromise;
|
||||
if (!tag.values) {
|
||||
tagValuesPromise = this.variable.getValuesForTag(tag.text);
|
||||
} else {
|
||||
tagValuesPromise = this.$q.when(tag.values);
|
||||
}
|
||||
|
||||
tagValuesPromise.then(values => {
|
||||
tag.values = values;
|
||||
tag.valuesText = values.join(' + ');
|
||||
_.each(this.options, option => {
|
||||
if (_.indexOf(tag.values, option.value) !== -1) {
|
||||
option.selected = tag.selected;
|
||||
}
|
||||
});
|
||||
|
||||
this.selectionsChanged(false);
|
||||
});
|
||||
}
|
||||
|
||||
keyDown(evt) {
|
||||
if (evt.keyCode === 27) {
|
||||
this.hide();
|
||||
}
|
||||
if (evt.keyCode === 40) {
|
||||
this.moveHighlight(1);
|
||||
}
|
||||
if (evt.keyCode === 38) {
|
||||
this.moveHighlight(-1);
|
||||
}
|
||||
if (evt.keyCode === 13) {
|
||||
if (this.search.options.length === 0) {
|
||||
this.commitChanges();
|
||||
} else {
|
||||
this.selectValue(this.search.options[this.highlightIndex], {}, true, false);
|
||||
}
|
||||
}
|
||||
if (evt.keyCode === 32) {
|
||||
this.selectValue(this.search.options[this.highlightIndex], {}, false, false);
|
||||
}
|
||||
}
|
||||
|
||||
moveHighlight(direction) {
|
||||
this.highlightIndex = (this.highlightIndex + direction) % this.search.options.length;
|
||||
}
|
||||
|
||||
selectValue(option, event, commitChange, excludeOthers) {
|
||||
if (!option) {
|
||||
return;
|
||||
}
|
||||
|
||||
option.selected = this.variable.multi ? !option.selected : true;
|
||||
|
||||
commitChange = commitChange || false;
|
||||
excludeOthers = excludeOthers || false;
|
||||
|
||||
let setAllExceptCurrentTo = function(newValue) {
|
||||
_.each(this.options, other => {
|
||||
if (option !== other) {
|
||||
other.selected = newValue;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// commit action (enter key), should not deselect it
|
||||
if (commitChange) {
|
||||
option.selected = true;
|
||||
}
|
||||
|
||||
if (option.text === 'All' || excludeOthers) {
|
||||
setAllExceptCurrentTo(false);
|
||||
commitChange = true;
|
||||
} else if (!this.variable.multi) {
|
||||
setAllExceptCurrentTo(false);
|
||||
commitChange = true;
|
||||
} else if (event.ctrlKey || event.metaKey || event.shiftKey) {
|
||||
commitChange = true;
|
||||
setAllExceptCurrentTo(false);
|
||||
}
|
||||
|
||||
this.selectionsChanged(commitChange);
|
||||
}
|
||||
|
||||
selectionsChanged(commitChange) {
|
||||
this.selectedValues = _.filter(this.options, { selected: true });
|
||||
|
||||
if (this.selectedValues.length > 1) {
|
||||
if (this.selectedValues[0].text === 'All') {
|
||||
this.selectedValues[0].selected = false;
|
||||
this.selectedValues = this.selectedValues.slice(1, this.selectedValues.length);
|
||||
}
|
||||
}
|
||||
|
||||
// validate selected tags
|
||||
_.each(this.tags, tag => {
|
||||
if (tag.selected) {
|
||||
_.each(tag.values, value => {
|
||||
if (!_.find(this.selectedValues, { value: value })) {
|
||||
tag.selected = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
this.selectedTags = _.filter(this.tags, { selected: true });
|
||||
this.variable.current.value = _.map(this.selectedValues, 'value');
|
||||
this.variable.current.text = _.map(this.selectedValues, 'text').join(' + ');
|
||||
this.variable.current.tags = this.selectedTags;
|
||||
|
||||
if (!this.variable.multi) {
|
||||
this.variable.current.value = this.selectedValues[0].value;
|
||||
}
|
||||
|
||||
if (commitChange) {
|
||||
this.commitChanges();
|
||||
}
|
||||
}
|
||||
|
||||
commitChanges() {
|
||||
// if we have a search query and no options use that
|
||||
if (this.search.options.length === 0 && this.search.query.length > 0) {
|
||||
this.variable.current = { text: this.search.query, value: this.search.query };
|
||||
} else if (this.selectedValues.length === 0) {
|
||||
// make sure one option is selected
|
||||
this.options[0].selected = true;
|
||||
this.selectionsChanged(false);
|
||||
}
|
||||
|
||||
this.dropdownVisible = false;
|
||||
this.updateLinkText();
|
||||
|
||||
if (this.variable.current.text !== this.oldVariableText) {
|
||||
this.onUpdated();
|
||||
}
|
||||
}
|
||||
|
||||
queryChanged() {
|
||||
this.highlightIndex = -1;
|
||||
this.search.options = _.filter(this.options, option => {
|
||||
return option.text.toLowerCase().indexOf(this.search.query.toLowerCase()) !== -1;
|
||||
});
|
||||
|
||||
this.search.options = this.search.options.slice(0, Math.min(this.search.options.length, 1000));
|
||||
}
|
||||
|
||||
init() {
|
||||
this.selectedTags = this.variable.current.tags || [];
|
||||
this.updateLinkText();
|
||||
}
|
||||
}
|
||||
|
||||
/** @ngInject */
|
||||
export function valueSelectDropdown($compile, $window, $timeout, $rootScope) {
|
||||
return {
|
||||
scope: { variable: '=', onUpdated: '&' },
|
||||
templateUrl: 'public/app/partials/valueSelectDropdown.html',
|
||||
controller: 'ValueSelectDropdownCtrl',
|
||||
controllerAs: 'vm',
|
||||
bindToController: true,
|
||||
link: function(scope, elem) {
|
||||
let bodyEl = angular.element($window.document.body);
|
||||
let linkEl = elem.find('.variable-value-link');
|
||||
let inputEl = elem.find('input');
|
||||
|
||||
function openDropdown() {
|
||||
inputEl.css('width', Math.max(linkEl.width(), 80) + 'px');
|
||||
|
||||
inputEl.show();
|
||||
linkEl.hide();
|
||||
|
||||
inputEl.focus();
|
||||
$timeout(
|
||||
function() {
|
||||
bodyEl.on('click', bodyOnClick);
|
||||
},
|
||||
0,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
function switchToLink() {
|
||||
inputEl.hide();
|
||||
linkEl.show();
|
||||
bodyEl.off('click', bodyOnClick);
|
||||
}
|
||||
|
||||
function bodyOnClick(e) {
|
||||
if (elem.has(e.target).length === 0) {
|
||||
scope.$apply(function() {
|
||||
scope.vm.commitChanges();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
scope.$watch('vm.dropdownVisible', newValue => {
|
||||
if (newValue) {
|
||||
openDropdown();
|
||||
} else {
|
||||
switchToLink();
|
||||
}
|
||||
});
|
||||
|
||||
let cleanUp = $rootScope.$on('template-variable-value-updated', () => {
|
||||
scope.vm.updateLinkText();
|
||||
});
|
||||
|
||||
scope.$on('$destroy', () => {
|
||||
cleanUp();
|
||||
});
|
||||
|
||||
scope.vm.init();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
coreModule.controller('ValueSelectDropdownCtrl', ValueSelectDropdownCtrl);
|
||||
coreModule.directive('valueSelectDropdown', valueSelectDropdown);
|
||||
@@ -67,7 +67,7 @@ export function fetch(load): any {
|
||||
return '';
|
||||
}
|
||||
|
||||
// dont reload styles loaded in the head
|
||||
// don't reload styles loaded in the head
|
||||
for (var i = 0; i < linkHrefs.length; i++) {
|
||||
if (load.address === linkHrefs[i]) {
|
||||
return '';
|
||||
|
||||
@@ -620,13 +620,13 @@ kbn.valueFormats.ms = function(size, decimals, scaledDecimals) {
|
||||
// Less than 1 min
|
||||
return kbn.toFixedScaled(size / 1000, decimals, scaledDecimals, 3, ' s');
|
||||
} else if (Math.abs(size) < 3600000) {
|
||||
// Less than 1 hour, devide in minutes
|
||||
// Less than 1 hour, divide in minutes
|
||||
return kbn.toFixedScaled(size / 60000, decimals, scaledDecimals, 5, ' min');
|
||||
} else if (Math.abs(size) < 86400000) {
|
||||
// Less than one day, devide in hours
|
||||
// Less than one day, divide in hours
|
||||
return kbn.toFixedScaled(size / 3600000, decimals, scaledDecimals, 7, ' hour');
|
||||
} else if (Math.abs(size) < 31536000000) {
|
||||
// Less than one year, devide in days
|
||||
// Less than one year, divide in days
|
||||
return kbn.toFixedScaled(size / 86400000, decimals, scaledDecimals, 8, ' day');
|
||||
}
|
||||
|
||||
@@ -638,15 +638,15 @@ kbn.valueFormats.s = function(size, decimals, scaledDecimals) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// Less than 1 µs, devide in ns
|
||||
// Less than 1 µs, divide in ns
|
||||
if (Math.abs(size) < 0.000001) {
|
||||
return kbn.toFixedScaled(size * 1e9, decimals, scaledDecimals - decimals, -9, ' ns');
|
||||
}
|
||||
// Less than 1 ms, devide in µs
|
||||
// Less than 1 ms, divide in µs
|
||||
if (Math.abs(size) < 0.001) {
|
||||
return kbn.toFixedScaled(size * 1e6, decimals, scaledDecimals - decimals, -6, ' µs');
|
||||
}
|
||||
// Less than 1 second, devide in ms
|
||||
// Less than 1 second, divide in ms
|
||||
if (Math.abs(size) < 1) {
|
||||
return kbn.toFixedScaled(size * 1e3, decimals, scaledDecimals - decimals, -3, ' ms');
|
||||
}
|
||||
@@ -654,16 +654,16 @@ kbn.valueFormats.s = function(size, decimals, scaledDecimals) {
|
||||
if (Math.abs(size) < 60) {
|
||||
return kbn.toFixed(size, decimals) + ' s';
|
||||
} else if (Math.abs(size) < 3600) {
|
||||
// Less than 1 hour, devide in minutes
|
||||
// Less than 1 hour, divide in minutes
|
||||
return kbn.toFixedScaled(size / 60, decimals, scaledDecimals, 1, ' min');
|
||||
} else if (Math.abs(size) < 86400) {
|
||||
// Less than one day, devide in hours
|
||||
// Less than one day, divide in hours
|
||||
return kbn.toFixedScaled(size / 3600, decimals, scaledDecimals, 4, ' hour');
|
||||
} else if (Math.abs(size) < 604800) {
|
||||
// Less than one week, devide in days
|
||||
// Less than one week, divide in days
|
||||
return kbn.toFixedScaled(size / 86400, decimals, scaledDecimals, 5, ' day');
|
||||
} else if (Math.abs(size) < 31536000) {
|
||||
// Less than one year, devide in week
|
||||
// Less than one year, divide in week
|
||||
return kbn.toFixedScaled(size / 604800, decimals, scaledDecimals, 6, ' week');
|
||||
}
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ function joinEvalMatches(matches, separator: string) {
|
||||
}
|
||||
|
||||
function getAlertAnnotationInfo(ah) {
|
||||
// backward compatability, can be removed in grafana 5.x
|
||||
// backward compatibility, can be removed in grafana 5.x
|
||||
// old way stored evalMatches in data property directly,
|
||||
// new way stores it in evalMatches property on new data object
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { ThresholdMapper } from '../threshold_mapper';
|
||||
|
||||
describe('ThresholdMapper', () => {
|
||||
describe('with greater than evaluator', () => {
|
||||
it('can mapp query conditions to thresholds', () => {
|
||||
it('can map query conditions to thresholds', () => {
|
||||
var panel: any = {
|
||||
type: 'graph',
|
||||
alert: {
|
||||
@@ -25,7 +25,7 @@ describe('ThresholdMapper', () => {
|
||||
});
|
||||
|
||||
describe('with outside range evaluator', () => {
|
||||
it('can mapp query conditions to thresholds', () => {
|
||||
it('can map query conditions to thresholds', () => {
|
||||
var panel: any = {
|
||||
type: 'graph',
|
||||
alert: {
|
||||
@@ -49,7 +49,7 @@ describe('ThresholdMapper', () => {
|
||||
});
|
||||
|
||||
describe('with inside range evaluator', () => {
|
||||
it('can mapp query conditions to thresholds', () => {
|
||||
it('can map query conditions to thresholds', () => {
|
||||
var panel: any = {
|
||||
type: 'graph',
|
||||
alert: {
|
||||
|
||||
@@ -56,7 +56,7 @@ function isStartOfRegion(event): boolean {
|
||||
export function dedupAnnotations(annotations) {
|
||||
let dedup = [];
|
||||
|
||||
// Split events by annotationId property existance
|
||||
// Split events by annotationId property existence
|
||||
let events = _.partition(annotations, 'id');
|
||||
|
||||
let eventsById = _.groupBy(events[0], 'id');
|
||||
|
||||
@@ -129,7 +129,7 @@ export class DashboardModel {
|
||||
this.meta = meta;
|
||||
}
|
||||
|
||||
// cleans meta data and other non peristent state
|
||||
// cleans meta data and other non persistent state
|
||||
getSaveModelClone() {
|
||||
// make clone
|
||||
var copy: any = {};
|
||||
@@ -606,7 +606,7 @@ export class DashboardModel {
|
||||
if (panel.gridPos.x + panel.gridPos.w * 2 <= GRID_COLUMN_COUNT) {
|
||||
newPanel.gridPos.x += panel.gridPos.w;
|
||||
} else {
|
||||
// add bellow
|
||||
// add below
|
||||
newPanel.gridPos.y += panel.gridPos.h;
|
||||
}
|
||||
|
||||
|
||||
@@ -133,7 +133,7 @@ export class HistoryListCtrl {
|
||||
return this.historySrv
|
||||
.getHistoryList(this.dashboard, options)
|
||||
.then(revisions => {
|
||||
// set formated dates & default values
|
||||
// set formatted dates & default values
|
||||
for (let rev of revisions) {
|
||||
rev.createdDateString = this.formatDate(rev.created);
|
||||
rev.ageString = this.formatBasicDate(rev.created);
|
||||
|
||||
@@ -56,7 +56,7 @@ describe('DashboardImportCtrl', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('when specifing grafana.com url', function() {
|
||||
describe('when specifying grafana.com url', function() {
|
||||
beforeEach(function() {
|
||||
ctx.ctrl.gnetUrl = 'http://grafana.com/dashboards/123';
|
||||
// setup api mock
|
||||
@@ -73,7 +73,7 @@ describe('DashboardImportCtrl', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('when specifing dashbord id', function() {
|
||||
describe('when specifying dashboard id', function() {
|
||||
beforeEach(function() {
|
||||
ctx.ctrl.gnetUrl = '2342';
|
||||
// setup api mock
|
||||
|
||||
@@ -44,7 +44,7 @@ describe('timeSrv', function() {
|
||||
expect(time.raw.to).to.be('now');
|
||||
});
|
||||
|
||||
it('should handle formated dates', function() {
|
||||
it('should handle formatted dates', function() {
|
||||
ctx.$location.search({ from: '20140410T052010', to: '20140520T031022' });
|
||||
ctx.service.init(_dashboard);
|
||||
var time = ctx.service.timeRange(true);
|
||||
@@ -52,7 +52,7 @@ describe('timeSrv', function() {
|
||||
expect(time.to.valueOf()).to.equal(new Date('2014-05-20T03:10:22Z').getTime());
|
||||
});
|
||||
|
||||
it('should handle formated dates without time', function() {
|
||||
it('should handle formatted dates without time', function() {
|
||||
ctx.$location.search({ from: '20140410', to: '20140520' });
|
||||
ctx.service.init(_dashboard);
|
||||
var time = ctx.service.timeRange(true);
|
||||
|
||||
@@ -38,7 +38,7 @@ export class DashboardViewState {
|
||||
});
|
||||
|
||||
// this marks changes to location during this digest cycle as not to add history item
|
||||
// dont want url changes like adding orgId to add browser history
|
||||
// don't want url changes like adding orgId to add browser history
|
||||
$location.replace();
|
||||
this.update(this.getQueryStringState());
|
||||
}
|
||||
@@ -196,7 +196,7 @@ export class DashboardViewState {
|
||||
this.oldTimeRange = ctrl.range;
|
||||
this.fullscreenPanel = panelScope;
|
||||
|
||||
// Firefox doesn't return scrollTop postion properly if 'dash-scroll' is emitted after setViewMode()
|
||||
// Firefox doesn't return scrollTop position properly if 'dash-scroll' is emitted after setViewMode()
|
||||
this.$scope.appEvent('dash-scroll', { animate: false, pos: 0 });
|
||||
this.dashboard.setViewMode(ctrl.panel, true, ctrl.editMode);
|
||||
this.$scope.appEvent('panel-fullscreen-enter', { panelId: ctrl.panel.id });
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
New Organization
|
||||
</h2>
|
||||
|
||||
<p class="playlist-description">Each organization contains their own dashboards, data sources and configuration, and cannot be shared between orgs. While users may belong to more than one, mutiple organization are most frequently used in multi-tenant deployments. </p>
|
||||
<p class="playlist-description">Each organization contains their own dashboards, data sources and configuration, and cannot be shared between orgs. While users may belong to more than one, multiple organization are most frequently used in multi-tenant deployments. </p>
|
||||
|
||||
<form>
|
||||
<div class="gf-form-group">
|
||||
|
||||
@@ -73,7 +73,7 @@ class MetricsPanelCtrl extends PanelCtrl {
|
||||
if (this.panel.snapshotData) {
|
||||
this.updateTimeRange();
|
||||
var data = this.panel.snapshotData;
|
||||
// backward compatability
|
||||
// backward compatibility
|
||||
if (!_.isArray(data)) {
|
||||
data = data.data;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ export class DatasourceVariable implements Variable {
|
||||
getSaveModel() {
|
||||
assignModelProperties(this.model, this, this.defaults);
|
||||
|
||||
// dont persist options
|
||||
// don't persist options
|
||||
this.model.options = [];
|
||||
return this.model;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import { AdhocVariable } from '../adhoc_variable';
|
||||
|
||||
describe('AdhocVariable', function() {
|
||||
describe('when serializing to url', function() {
|
||||
it('should set return key value and op seperated by pipe', function() {
|
||||
it('should set return key value and op separated by pipe', function() {
|
||||
var variable = new AdhocVariable({
|
||||
filters: [
|
||||
{ key: 'key1', operator: '=', value: 'value1' },
|
||||
|
||||
@@ -282,7 +282,7 @@ describe('templateSrv', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('can hightlight variables in string', function() {
|
||||
describe('can highlight variables in string', function() {
|
||||
beforeEach(function() {
|
||||
initTemplateSrv([{ type: 'query', name: 'test', current: { value: 'oogle' } }]);
|
||||
});
|
||||
|
||||
@@ -204,7 +204,7 @@ export class TemplateSrv {
|
||||
value = variable.current.value;
|
||||
if (this.isAllValue(value)) {
|
||||
value = this.getAllValue(variable);
|
||||
// skip formating of custom all values
|
||||
// skip formatting of custom all values
|
||||
if (variable.allValue) {
|
||||
return value;
|
||||
}
|
||||
|
||||
@@ -392,7 +392,7 @@
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "2 yaxis and axis lables",
|
||||
"title": "2 yaxis and axis labels",
|
||||
"tooltip": {
|
||||
"msResolution": false,
|
||||
"shared": true,
|
||||
@@ -894,7 +894,7 @@
|
||||
"thresholds": [],
|
||||
"timeFrom": null,
|
||||
"timeShift": null,
|
||||
"title": "Legend Table Single Series Should Take Minium Height",
|
||||
"title": "Legend Table Single Series Should Take Minimum Height",
|
||||
"tooltip": {
|
||||
"shared": true,
|
||||
"sort": 0,
|
||||
|
||||
@@ -175,7 +175,7 @@ export class ElasticResponse {
|
||||
}
|
||||
|
||||
// This is quite complex
|
||||
// neeed to recurise down the nested buckets to build series
|
||||
// need to recurise down the nested buckets to build series
|
||||
processBuckets(aggs, target, seriesList, table, props, depth) {
|
||||
var bucket, aggDef, esAgg, aggId;
|
||||
var maxDepth = target.bucketAggs.length - 1;
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<input type="text" class="gf-form-input max-width-10" ng-model='ctrl.annotation.tagsField' placeholder="tags"></input>
|
||||
</div>
|
||||
<div class="gf-form" ng-show="ctrl.annotation.titleField">
|
||||
<span class="gf-form-label">Title <em class="muted">(depricated)</em></span>
|
||||
<span class="gf-form-label">Title <em class="muted">(deprecated)</em></span>
|
||||
<input type="text" class="gf-form-input max-width-16" ng-model='ctrl.annotation.titleField' placeholder="desc"></input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
</div>
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form">
|
||||
<span class="gf-form-label width-9">Min interval</span>
|
||||
<span class="gf-form-label width-9">Min time interval</span>
|
||||
<input type="text" class="gf-form-input width-6" ng-model="ctrl.current.jsonData.timeInterval" spellcheck='false' placeholder="10s"></input>
|
||||
<info-popover mode="right-absolute">
|
||||
A lower limit for the auto group by time interval. Recommended to be set to write frequency,
|
||||
|
||||
@@ -53,7 +53,7 @@ describe('ElasticDatasource', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('When issueing metric query with interval pattern', function() {
|
||||
describe('When issuing metric query with interval pattern', function() {
|
||||
var requestOptions, parts, header;
|
||||
|
||||
beforeEach(function() {
|
||||
@@ -98,7 +98,7 @@ describe('ElasticDatasource', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('When issueing document query', function() {
|
||||
describe('When issuing document query', function() {
|
||||
var requestOptions, parts, header;
|
||||
|
||||
beforeEach(function() {
|
||||
|
||||
@@ -68,7 +68,7 @@ export function graphiteAddFunc($compile) {
|
||||
});
|
||||
|
||||
$input.blur(function() {
|
||||
// clicking the function dropdown menu wont
|
||||
// clicking the function dropdown menu won't
|
||||
// work if you remove class at once
|
||||
setTimeout(function() {
|
||||
$input.val('');
|
||||
|
||||
@@ -97,7 +97,7 @@ describe('GraphiteQueryCtrl', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('when initalizing target without metric expression and only function', function() {
|
||||
describe('when initializing target without metric expression and only function', function() {
|
||||
beforeEach(function() {
|
||||
ctx.ctrl.target.target = 'asPercent(#A, #B)';
|
||||
ctx.ctrl.datasource.metricFindQuery.returns(ctx.$q.when([]));
|
||||
@@ -130,7 +130,7 @@ describe('GraphiteQueryCtrl', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('when initalizing target without metric expression and function with series-ref', function() {
|
||||
describe('when initializing target without metric expression and function with series-ref', function() {
|
||||
beforeEach(function() {
|
||||
ctx.ctrl.target.target = 'asPercent(metric.node.count, #A)';
|
||||
ctx.ctrl.datasource.metricFindQuery.returns(ctx.$q.when([]));
|
||||
@@ -146,7 +146,7 @@ describe('GraphiteQueryCtrl', function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe('when getting altSegments and metricFindQuery retuns empty array', function() {
|
||||
describe('when getting altSegments and metricFindQuery returns empty array', function() {
|
||||
beforeEach(function() {
|
||||
ctx.ctrl.target.target = 'test.count';
|
||||
ctx.ctrl.datasource.metricFindQuery.returns(ctx.$q.when([]));
|
||||
|
||||
@@ -54,7 +54,7 @@ export default class InfluxDatasource {
|
||||
|
||||
queryTargets.push(target);
|
||||
|
||||
// backward compatability
|
||||
// backward compatibility
|
||||
scopedVars.interval = scopedVars.__interval;
|
||||
|
||||
queryModel = new InfluxQuery(target, this.templateSrv, scopedVars);
|
||||
@@ -82,7 +82,7 @@ export default class InfluxDatasource {
|
||||
// replace templated variables
|
||||
allQueries = this.templateSrv.replace(allQueries, scopedVars);
|
||||
|
||||
return this._seriesQuery(allQueries).then((data): any => {
|
||||
return this._seriesQuery(allQueries, options).then((data): any => {
|
||||
if (!data || !data.results) {
|
||||
return [];
|
||||
}
|
||||
@@ -135,7 +135,7 @@ export default class InfluxDatasource {
|
||||
var query = options.annotation.query.replace('$timeFilter', timeFilter);
|
||||
query = this.templateSrv.replace(query, null, 'regex');
|
||||
|
||||
return this._seriesQuery(query).then(data => {
|
||||
return this._seriesQuery(query, options).then(data => {
|
||||
if (!data || !data.results || !data.results[0]) {
|
||||
throw { message: 'No results in response from InfluxDB' };
|
||||
}
|
||||
@@ -164,30 +164,30 @@ export default class InfluxDatasource {
|
||||
return false;
|
||||
}
|
||||
|
||||
metricFindQuery(query) {
|
||||
metricFindQuery(query: string, options?: any) {
|
||||
var interpolated = this.templateSrv.replace(query, null, 'regex');
|
||||
|
||||
return this._seriesQuery(interpolated).then(_.curry(this.responseParser.parse)(query));
|
||||
return this._seriesQuery(interpolated, options).then(_.curry(this.responseParser.parse)(query));
|
||||
}
|
||||
|
||||
getTagKeys(options) {
|
||||
var queryBuilder = new InfluxQueryBuilder({ measurement: '', tags: [] }, this.database);
|
||||
var query = queryBuilder.buildExploreQuery('TAG_KEYS');
|
||||
return this.metricFindQuery(query);
|
||||
return this.metricFindQuery(query, options);
|
||||
}
|
||||
|
||||
getTagValues(options) {
|
||||
var queryBuilder = new InfluxQueryBuilder({ measurement: '', tags: [] }, this.database);
|
||||
var query = queryBuilder.buildExploreQuery('TAG_VALUES', options.key);
|
||||
return this.metricFindQuery(query);
|
||||
return this.metricFindQuery(query, options);
|
||||
}
|
||||
|
||||
_seriesQuery(query) {
|
||||
_seriesQuery(query: string, options?: any) {
|
||||
if (!query) {
|
||||
return this.$q.when({ results: [] });
|
||||
}
|
||||
|
||||
return this._influxRequest('GET', '/query', { q: query, epoch: 'ms' });
|
||||
return this._influxRequest('GET', '/query', { q: query, epoch: 'ms' }, options);
|
||||
}
|
||||
|
||||
serializeParams(params) {
|
||||
@@ -225,21 +225,21 @@ export default class InfluxDatasource {
|
||||
});
|
||||
}
|
||||
|
||||
_influxRequest(method, url, data) {
|
||||
var self = this;
|
||||
_influxRequest(method: string, url: string, data: any, options?: any) {
|
||||
const currentUrl = this.urls.shift();
|
||||
this.urls.push(currentUrl);
|
||||
|
||||
var currentUrl = self.urls.shift();
|
||||
self.urls.push(currentUrl);
|
||||
let params: any = {};
|
||||
|
||||
var params: any = {};
|
||||
|
||||
if (self.username) {
|
||||
params.u = self.username;
|
||||
params.p = self.password;
|
||||
if (this.username) {
|
||||
params.u = this.username;
|
||||
params.p = this.password;
|
||||
}
|
||||
|
||||
if (self.database) {
|
||||
params.db = self.database;
|
||||
if (options && options.database) {
|
||||
params.db = options.database;
|
||||
} else if (this.database) {
|
||||
params.db = this.database;
|
||||
}
|
||||
|
||||
if (method === 'GET') {
|
||||
@@ -247,7 +247,7 @@ export default class InfluxDatasource {
|
||||
data = null;
|
||||
}
|
||||
|
||||
var options: any = {
|
||||
let req: any = {
|
||||
method: method,
|
||||
url: currentUrl + url,
|
||||
params: params,
|
||||
@@ -257,15 +257,15 @@ export default class InfluxDatasource {
|
||||
paramSerializer: this.serializeParams,
|
||||
};
|
||||
|
||||
options.headers = options.headers || {};
|
||||
req.headers = req.headers || {};
|
||||
if (this.basicAuth || this.withCredentials) {
|
||||
options.withCredentials = true;
|
||||
req.withCredentials = true;
|
||||
}
|
||||
if (self.basicAuth) {
|
||||
options.headers.Authorization = self.basicAuth;
|
||||
if (this.basicAuth) {
|
||||
req.headers.Authorization = this.basicAuth;
|
||||
}
|
||||
|
||||
return this.backendSrv.datasourceRequest(options).then(
|
||||
return this.backendSrv.datasourceRequest(req).then(
|
||||
result => {
|
||||
return result.data;
|
||||
},
|
||||
|
||||
@@ -230,7 +230,7 @@ export default class InfluxQuery {
|
||||
for (i = 0; i < this.groupByParts.length; i++) {
|
||||
var part = this.groupByParts[i];
|
||||
if (i > 0) {
|
||||
// for some reason fill has no seperator
|
||||
// for some reason fill has no separator
|
||||
groupBySection += part.def.type === 'fill' ? ' ' : ', ';
|
||||
}
|
||||
groupBySection += part.render('');
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<input type="text" class="gf-form-input max-width-10" ng-model='ctrl.annotation.tagsColumn' placeholder=""></input>
|
||||
</div>
|
||||
<div class="gf-form" ng-show="ctrl.annotation.titleColumn">
|
||||
<span class="gf-form-label width-4">Title <em class="muted">(depricated)</em></span>
|
||||
<span class="gf-form-label width-4">Title <em class="muted">(deprecated)</em></span>
|
||||
<input type="text" class="gf-form-input max-width-10" ng-model='ctrl.annotation.titleColumn' placeholder=""></input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -23,6 +23,20 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="gf-form-group">
|
||||
<div class="grafana-info-box">
|
||||
<h5>Database Access</h5>
|
||||
<p>
|
||||
Setting the database for this datasource does not deny access to other databases. The InfluxDB query syntax allows
|
||||
switching the database in the query. For example:
|
||||
<code>SHOW MEASUREMENTS ON _internal</code> or <code>SELECT * FROM "_internal".."database" LIMIT 10</code>
|
||||
<br/><br/>
|
||||
To support data isolation and security, make sure appropriate permissions are configured in InfluxDB.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="gf-form-group">
|
||||
<div class="gf-form-inline">
|
||||
<div class="gf-form">
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
- When stacking is enabled it is important that points align
|
||||
- If there are missing points for one series it can cause gaps or missing bars
|
||||
- You must use fill(0), and select a group by time low limit
|
||||
- Use the group by time option below your queries and specify for example >10s if your metrics are written every 10 seconds
|
||||
- Use the group by time option below your queries and specify for example 10s if your metrics are written every 10 seconds
|
||||
- This will insert zeros for series that are missing measurements and will make stacking work properly
|
||||
|
||||
#### Group by time
|
||||
@@ -18,8 +18,7 @@
|
||||
- Leave the group by time field empty for each query and it will be calculated based on time range and pixel width of the graph
|
||||
- If you use fill(0) or fill(null) set a low limit for the auto group by time interval
|
||||
- The low limit can only be set in the group by time option below your queries
|
||||
- You set a low limit by adding a greater sign before the interval
|
||||
- Example: >60s if you write metrics to InfluxDB every 60 seconds
|
||||
- Example: 60s if you write metrics to InfluxDB every 60 seconds
|
||||
|
||||
#### Documentation links:
|
||||
|
||||
|
||||
@@ -97,7 +97,7 @@ describe('InfluxQueryBuilder', function() {
|
||||
expect(query).toBe('SHOW TAG VALUES FROM "one_week"."cpu" WITH KEY = "app" WHERE "host" = \'server1\'');
|
||||
});
|
||||
|
||||
it('should not includ policy when policy is default', function() {
|
||||
it('should not include policy when policy is default', function() {
|
||||
var builder = new InfluxQueryBuilder({
|
||||
measurement: 'cpu',
|
||||
policy: 'default',
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
<div class="gf-form" ng-show="ctrl.showHelp">
|
||||
<pre class="gf-form-pre alert alert-info"><h6>Annotation Query Format</h6>
|
||||
An annotation is an event that is overlayed on top of graphs. The query can have up to three columns per row, the <b>time</b> column is mandatory. Annotation rendering is expensive so it is important to limit the number of rows returned.
|
||||
An annotation is an event that is overlaid on top of graphs. The query can have up to three columns per row, the <b>time</b> column is mandatory. Annotation rendering is expensive so it is important to limit the number of rows returned.
|
||||
|
||||
- column with alias: <b>time</b> for the annotation event time. Use epoch time or any native date data type.
|
||||
- column with alias: <b>text</b> for the annotation text.
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
|
||||
<div class="gf-form" ng-show="ctrl.showHelp">
|
||||
<pre class="gf-form-pre alert alert-info"><h6>Annotation Query Format</h6>
|
||||
An annotation is an event that is overlayed on top of graphs. The query can have up to three columns per row, the <i>time</i> or <i>time_sec</i> column is mandatory. Annotation rendering is expensive so it is important to limit the number of rows returned.
|
||||
An annotation is an event that is overlaid on top of graphs. The query can have up to three columns per row, the <i>time</i> or <i>time_sec</i> column is mandatory. Annotation rendering is expensive so it is important to limit the number of rows returned.
|
||||
|
||||
- column with alias: <b>time</b> or <i>time_sec</i> for the annotation event time. Use epoch time or any native date data type.
|
||||
- column with alias: <b>text</b> for the annotation text
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
|
||||
<svg width="432.071pt" height="445.383pt" viewBox="0 0 432.071 445.383" xml:space="preserve" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="orginal" style="fill-rule:nonzero;clip-rule:nonzero;stroke:#000000;stroke-miterlimit:4;">
|
||||
<g id="original" style="fill-rule:nonzero;clip-rule:nonzero;stroke:#000000;stroke-miterlimit:4;">
|
||||
</g>
|
||||
<g id="Layer_x0020_3" style="fill-rule:nonzero;clip-rule:nonzero;fill:none;stroke:#FFFFFF;stroke-width:12.4651;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;">
|
||||
<path style="fill:#000000;stroke:#000000;stroke-width:37.3953;stroke-linecap:butt;stroke-linejoin:miter;" d="M323.205,324.227c2.833-23.601,1.984-27.062,19.563-23.239l4.463,0.392c13.517,0.615,31.199-2.174,41.587-7c22.362-10.376,35.622-27.7,13.572-23.148c-50.297,10.376-53.755-6.655-53.755-6.655c53.111-78.803,75.313-178.836,56.149-203.322 C352.514-5.534,262.036,26.049,260.522,26.869l-0.482,0.089c-9.938-2.062-21.06-3.294-33.554-3.496c-22.761-0.374-40.032,5.967-53.133,15.904c0,0-161.408-66.498-153.899,83.628c1.597,31.936,45.777,241.655,98.47,178.31 c19.259-23.163,37.871-42.748,37.871-42.748c9.242,6.14,20.307,9.272,31.912,8.147l0.897-0.765c-0.281,2.876-0.157,5.689,0.359,9.019c-13.572,15.167-9.584,17.83-36.723,23.416c-27.457,5.659-11.326,15.734-0.797,18.367c12.768,3.193,42.305,7.716,62.268-20.224 l-0.795,3.188c5.325,4.26,4.965,30.619,5.72,49.452c0.756,18.834,2.017,36.409,5.856,46.771c3.839,10.36,8.369,37.05,44.036,29.406c29.809-6.388,52.6-15.582,54.677-101.107"/>
|
||||
@@ -19,4 +19,4 @@
|
||||
<path d="M350.676,123.432c0.863,15.994-3.445,26.888-3.988,43.914c-0.804,24.748,11.799,53.074-7.191,81.435"/>
|
||||
<path style="stroke-width:3;" d="M0,60.232"/>
|
||||
</g>
|
||||
</svg>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.4 KiB |
@@ -18,7 +18,7 @@
|
||||
|
||||
<div class="gf-form" ng-show="ctrl.showHelp">
|
||||
<pre class="gf-form-pre alert alert-info"><h6>Annotation Query Format</h6>
|
||||
An annotation is an event that is overlayed on top of graphs. The query can have up to three columns per row, the time column is mandatory. Annotation rendering is expensive so it is important to limit the number of rows returned.
|
||||
An annotation is an event that is overlaid on top of graphs. The query can have up to three columns per row, the time column is mandatory. Annotation rendering is expensive so it is important to limit the number of rows returned.
|
||||
|
||||
- column with alias: <b>time</b> for the annotation event time. Use epoch time or any native date data type.
|
||||
- column with alias: <b>text</b> for the annotation text
|
||||
|
||||
@@ -52,14 +52,14 @@ function ($, _, angular, Drop) {
|
||||
var eventManager = plot.getOptions().events.manager;
|
||||
if (eventManager.editorOpen) {
|
||||
// update marker element to attach to (needed in case of legend on the right
|
||||
// when there is a double render pass and the inital marker element is removed)
|
||||
// when there is a double render pass and the initial marker element is removed)
|
||||
markerElementToAttachTo = element;
|
||||
return;
|
||||
}
|
||||
|
||||
// mark as openend
|
||||
eventManager.editorOpened();
|
||||
// set marker elment to attache to
|
||||
// set marker element to attache to
|
||||
markerElementToAttachTo = element;
|
||||
|
||||
// wait for element to be attached and positioned
|
||||
|
||||
@@ -129,7 +129,7 @@ module.directive('graphLegend', function(popoverSrv, $timeout) {
|
||||
|
||||
elem.empty();
|
||||
|
||||
// Set min-width if side style and there is a value, otherwise remove the CSS propery
|
||||
// Set min-width if side style and there is a value, otherwise remove the CSS property
|
||||
// Set width so it works with IE11
|
||||
var width: any = panel.legend.rightSide && panel.legend.sideWidth ? panel.legend.sideWidth + 'px' : '';
|
||||
var ieWidth: any = panel.legend.rightSide && panel.legend.sideWidth ? panel.legend.sideWidth - 1 + 'px' : '';
|
||||
|
||||
@@ -31,7 +31,7 @@ export class SeriesOverridesCtrl {
|
||||
|
||||
$scope.override[item.propertyName] = subItem.value;
|
||||
|
||||
// automatically disable lines for this series and the fill bellow to series
|
||||
// automatically disable lines for this series and the fill below to series
|
||||
// can be removed by the user if they still want lines
|
||||
if (item.propertyName === 'fillBelowTo') {
|
||||
$scope.override['lines'] = false;
|
||||
|
||||
@@ -221,7 +221,7 @@ describe('when transforming time series table', () => {
|
||||
expect(table.rows[0][2]).toBe(42);
|
||||
});
|
||||
|
||||
it('should return 2 rows for a mulitple queries with same label values plus one extra row', () => {
|
||||
it('should return 2 rows for a multiple queries with same label values plus one extra row', () => {
|
||||
table = transformDataToTable(multipleQueriesDataSameLabels, panel);
|
||||
expect(table.rows.length).toBe(2);
|
||||
expect(table.rows[0][0]).toBe(time);
|
||||
@@ -238,7 +238,7 @@ describe('when transforming time series table', () => {
|
||||
expect(table.rows[1][5]).toBe(7);
|
||||
});
|
||||
|
||||
it('should return 2 rows for mulitple queries with different label values', () => {
|
||||
it('should return 2 rows for multiple queries with different label values', () => {
|
||||
table = transformDataToTable(multipleQueriesDataDifferentLabels, panel);
|
||||
expect(table.rows.length).toBe(2);
|
||||
expect(table.columns.length).toBe(6);
|
||||
|
||||
@@ -243,7 +243,7 @@ transformers['table'] = {
|
||||
row[columnIndex] = matchedRow[columnIndex];
|
||||
}
|
||||
}
|
||||
// Dont visit this row again
|
||||
// Don't visit this row again
|
||||
mergedRows[match] = matchedRow;
|
||||
// Keep looking for more rows to merge
|
||||
offset = match + 1;
|
||||
|
||||
@@ -22,7 +22,7 @@ var dashboard;
|
||||
// All url parameters are available via the ARGS object
|
||||
var ARGS;
|
||||
|
||||
// Intialize a skeleton with nothing but a rows array and service object
|
||||
// Initialize a skeleton with nothing but a rows array and service object
|
||||
dashboard = {
|
||||
rows : [],
|
||||
schemaVersion: 13,
|
||||
|
||||
Reference in New Issue
Block a user