Merge branch 'master' into settings-icons-fix

This commit is contained in:
Marcus Efraimsson
2018-04-16 17:16:54 +02:00
135 changed files with 2696 additions and 1010 deletions

View File

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

View File

@@ -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 {

View File

@@ -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 {

View File

@@ -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');

View File

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

View 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);

View File

@@ -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 '';

View File

@@ -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');
}

View File

@@ -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

View File

@@ -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: {

View File

@@ -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');

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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

View File

@@ -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);

View File

@@ -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 });

View File

@@ -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">

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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' },

View File

@@ -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' } }]);
});

View File

@@ -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;
}

View File

@@ -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,

View File

@@ -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;

View File

@@ -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>

View File

@@ -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,

View File

@@ -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() {

View File

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

View File

@@ -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([]));

View File

@@ -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;
},

View File

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

View File

@@ -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>

View File

@@ -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">

View File

@@ -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 &gt;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: &gt;60s if you write metrics to InfluxDB every 60 seconds
- Example: 60s if you write metrics to InfluxDB every 60 seconds
#### Documentation links:

View File

@@ -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',

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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' : '';

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -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,