diff --git a/public/app/angular/bsTooltip.ts b/public/app/angular/bsTooltip.ts new file mode 100644 index 00000000000..38bb09b769c --- /dev/null +++ b/public/app/angular/bsTooltip.ts @@ -0,0 +1,59 @@ +import angular from 'angular'; +import $ from 'jquery'; + +import coreModule from './core_module'; + +coreModule.directive('bsTooltip', [ + '$parse', + '$compile', + function ($parse: any, $compile: any) { + return { + restrict: 'A', + scope: true, + link: function postLink(scope: any, element: any, attrs: any) { + var getter = $parse(attrs.bsTooltip), + value = getter(scope); + scope.$watch(attrs.bsTooltip, function (newValue: any, oldValue: any) { + if (newValue !== oldValue) { + value = newValue; + } + }); + // Grafana change, always hide other tooltips + if (true) { + element.on('show', function (ev: any) { + $('.tooltip.in').each(function () { + var $this = $(this), + tooltip = $this.data('tooltip'); + if (tooltip && !tooltip.$element.is(element)) { + $this.tooltip('hide'); + } + }); + }); + } + element.tooltip({ + title: function () { + return angular.isFunction(value) ? value.apply(null, arguments) : value; + }, + html: true, + container: 'body', // Grafana change + }); + var tooltip = element.data('tooltip'); + tooltip.show = function () { + var r = $.fn.tooltip.Constructor.prototype.show.apply(this, arguments); + this.tip().data('tooltip', this); + return r; + }; + scope._tooltip = function (event: any) { + element.tooltip(event); + }; + scope.hide = function () { + element.tooltip('hide'); + }; + scope.show = function () { + element.tooltip('show'); + }; + scope.dismiss = scope.hide; + }, + }; + }, +]); diff --git a/public/app/angular/bsTypeahead.ts b/public/app/angular/bsTypeahead.ts new file mode 100644 index 00000000000..515f82994ba --- /dev/null +++ b/public/app/angular/bsTypeahead.ts @@ -0,0 +1,63 @@ +import angular from 'angular'; +import $ from 'jquery'; +import { isFunction } from 'lodash'; + +import coreModule from './core_module'; + +coreModule.directive('bsTypeahead', [ + '$parse', + function ($parse: any) { + return { + restrict: 'A', + require: '?ngModel', + link: function postLink(scope: any, element: any, attrs: any, controller: any) { + var getter = $parse(attrs.bsTypeahead), + value = getter(scope); + scope.$watch(attrs.bsTypeahead, function (newValue: any, oldValue: any) { + if (newValue !== oldValue) { + value = newValue; + } + }); + element.attr('data-provide', 'typeahead'); + element.typeahead({ + source: function () { + return angular.isFunction(value) ? value.apply(null, arguments) : value; + }, + minLength: attrs.minLength || 1, + items: attrs.item, + updater: function (value: any) { + if (controller) { + scope.$apply(function () { + controller.$setViewValue(value); + }); + } + scope.$emit('typeahead-updated', value); + return value; + }, + }); + var typeahead = element.dat('typeahead'); + typeahead.lookup = function (ev: any) { + var items; + this.query = this.$element.val() || ''; + if (this.query.length < this.options.minLength) { + return this.shown ? this.hide() : this; + } + items = isFunction(this.source) ? this.source(this.query, $.proxy(this.process, this)) : this.source; + return items ? this.process(items) : this; + }; + if (!!attrs.matchAll) { + typeahead.matcher = function () { + return true; + }; + } + if (attrs.minLength === '0') { + setTimeout(function () { + element.on('focus', function () { + element.val().length === 0 && setTimeout(element.typeahead.bind(element, 'lookup'), 200); + }); + }); + } + }, + }; + }, +]); diff --git a/public/app/angular/index.ts b/public/app/angular/index.ts index ada6fe8f6a5..3fbf6ae93f2 100644 --- a/public/app/angular/index.ts +++ b/public/app/angular/index.ts @@ -14,6 +14,8 @@ import './dropdown_typeahead'; import './autofill_event_fix'; import './metric_segment'; import './misc'; +import './bsTooltip'; +import './bsTypeahead'; import './ng_model_on_blur'; import './tags'; import './rebuild_on_change'; diff --git a/public/app/plugins/datasource/mssql/partials/config.html b/public/app/plugins/datasource/mssql/partials/config.html index 6d3cb01e3d5..680ba4dd75b 100644 --- a/public/app/plugins/datasource/mssql/partials/config.html +++ b/public/app/plugins/datasource/mssql/partials/config.html @@ -1,46 +1,45 @@ -
1m if your data is written every minute.
- 1m if your data is written every minute.
+
- The database user should only be granted SELECT permissions on the specified database and tables you want to query.
- Grafana does not validate that queries are safe so queries can contain any SQL statement. For example, statements
- like USE otherdb; and DROP TABLE user; would be executed. To protect against this we
-
+ The database user should only be granted SELECT permissions on the specified database and tables you want to
+ query.
+ Grafana does not validate that queries are safe so queries can contain any SQL statement. For example, statements
+ like USE otherdb; and DROP TABLE user; would be executed. To protect against this we
+