Angular: Adds back two angular directives that are still used by remaining angular bits and plugins (#50380)

This commit is contained in:
Torkel Ödegaard 2022-06-08 10:34:58 +02:00 committed by GitHub
parent fd408652dc
commit 288eede638
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 237 additions and 111 deletions

View File

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

View File

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

View File

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

View File

@ -1,46 +1,45 @@
<h3 class="page-heading">MS SQL connection</h3>
<div class="gf-form-group">
<div class="gf-form max-width-30">
<span class="gf-form-label width-7">Host</span>
<input type="text" class="gf-form-input" style="width: 352px" ng-model='ctrl.current.url' placeholder="localhost" bs-typeahead="{{['localhost', 'localhost" required></input>
</div>
<div class="gf-form max-width-30">
<span class="gf-form-label width-7">Host</span>
<input type="text" class="gf-form-input" style="width: 352px" ng-model='ctrl.current.url' placeholder="localhost"
bs-typeahead="{{['localhost', 'localhost:1433']}}" required></input>
</div>
<div class="gf-form max-width-30">
<span class="gf-form-label width-7">Database</span>
<input type="text" class="gf-form-input" style="width: 352px" ng-model='ctrl.current.database' placeholder="database name" required></input>
</div>
<div class="gf-form max-width-30">
<span class="gf-form-label width-7">Database</span>
<input type="text" class="gf-form-input" style="width: 352px" ng-model='ctrl.current.database'
placeholder="database name" required></input>
</div>
<div class="gf-form">
<label class="gf-form-label width-7" for="auth-select">Authentication</label>
<div class="gf-form-select-wrapper max-width-15 gf-form-select-wrapper--has-help-icon">
<select id="auth-select" class="gf-form-input" ng-model="ctrl.current.jsonData.authenticationType" ng-options="mode for mode in ['Windows Authentication', 'SQL Server Authentication']" ng-init="ctrl.current.jsonData.authenticationType" ng-change="ctrl.onAuthenticationTypeChange()"></select>
<info-popover mode="right-absolute">
<ul>
<li><i>SQL Server Authentication</i> This is the default mechanism to connect to MS SQL Server. Enter the SQL Server Authentication login or the Windows Authentication login in the DOMAIN\User format.</li>
<li><i>Windows Authentication</i> Windows Integrated Security - single sign on for users who are already logged onto Windows and have enabled this option for MS SQL Server.</li>
</ul>
</info-popover>
</div>
</div>
<div class="gf-form-inline" ng-show="ctrl.showUserCredentials">
<div class="gf-form max-width-15">
<span class="gf-form-label width-7">User</span>
<input type="text" class="gf-form-input" ng-model='ctrl.current.user' placeholder="user"></input>
</div>
<div class="gf-form">
<secret-form-field
isConfigured="ctrl.current.secureJsonFields.password"
value="ctrl.current.secureJsonData.password"
on-reset="ctrl.onPasswordReset"
on-change="ctrl.onPasswordChange"
labelWidth="7"
inputWidth="7"
aria-label="'Password'"
/>
</div>
</div>
<div class="gf-form">
<label class="gf-form-label width-7" for="auth-select">Authentication</label>
<div class="gf-form-select-wrapper max-width-15 gf-form-select-wrapper--has-help-icon">
<select id="auth-select" class="gf-form-input" ng-model="ctrl.current.jsonData.authenticationType"
ng-options="mode for mode in ['Windows Authentication', 'SQL Server Authentication']"
ng-init="ctrl.current.jsonData.authenticationType" ng-change="ctrl.onAuthenticationTypeChange()"></select>
<info-popover mode="right-absolute">
<ul>
<li><i>SQL Server Authentication</i> This is the default mechanism to connect to MS SQL Server. Enter the SQL
Server Authentication login or the Windows Authentication login in the DOMAIN\User format.</li>
<li><i>Windows Authentication</i> Windows Integrated Security - single sign on for users who are already
logged onto Windows and have enabled this option for MS SQL Server.</li>
</ul>
</info-popover>
</div>
</div>
<div class="gf-form-inline" ng-show="ctrl.showUserCredentials">
<div class="gf-form max-width-15">
<span class="gf-form-label width-7">User</span>
<input type="text" class="gf-form-input" ng-model='ctrl.current.user' placeholder="user"></input>
</div>
<div class="gf-form">
<secret-form-field isConfigured="ctrl.current.secureJsonFields.password"
value="ctrl.current.secureJsonData.password" on-reset="ctrl.onPasswordReset" on-change="ctrl.onPasswordChange"
labelWidth="7" inputWidth="7" aria-label="'Password'" />
</div>
</div>
</div>
@ -48,33 +47,37 @@
<div class="gf-form-group">
<div class="gf-form">
<label class="gf-form-label width-15" for="encrypt-select">Encrypt</label>
<div class="gf-form-select-wrapper max-width-15 gf-form-select-wrapper--has-help-icon">
<select id="encrypt-select" class="gf-form-input" ng-model="ctrl.current.jsonData.encrypt" ng-options="mode for mode in ['disable', 'false', 'true']" ng-init="ctrl.current.jsonData.encrypt" ng-change="ctrl.onEncryptChange()" aria-labelledby="encrypt-label"></select>
<info-popover mode="right-absolute">
Determines whether or to which extent a secure SSL TCP/IP connection will be negotiated with the server.
<ul>
<li><i>disable</i> - Data sent between client and server is not encrypted.</li>
<li><i>false</i> - Data sent between client and server is not encrypted beyond the login packet. (default)</li>
<li><i>true</i> - Data sent between client and server is encrypted.</li>
</ul>
If you're using an older version of Microsoft SQL Server like 2008 and 2008R2 you may need to disable encryption to be able to connect.
</info-popover>
</div>
</div>
<div class="gf-form">
<label class="gf-form-label width-15" for="encrypt-select">Encrypt</label>
<div class="gf-form-select-wrapper max-width-15 gf-form-select-wrapper--has-help-icon">
<select id="encrypt-select" class="gf-form-input" ng-model="ctrl.current.jsonData.encrypt"
ng-options="mode for mode in ['disable', 'false', 'true']" ng-init="ctrl.current.jsonData.encrypt"
ng-change="ctrl.onEncryptChange()" aria-labelledby="encrypt-label"></select>
<info-popover mode="right-absolute">
Determines whether or to which extent a secure SSL TCP/IP connection will be negotiated with the server.
<ul>
<li><i>disable</i> - Data sent between client and server is not encrypted.</li>
<li><i>false</i> - Data sent between client and server is not encrypted beyond the login packet. (default)
</li>
<li><i>true</i> - Data sent between client and server is encrypted.</li>
</ul>
If you're using an older version of Microsoft SQL Server like 2008 and 2008R2 you may need to disable encryption
to be able to connect.
</info-popover>
</div>
</div>
<div class="gf-form" ng-show="ctrl.showTlsConfig">
<gf-form-switch class="gf-form" label="Skip TLS/SSL Verify" label-class="width-15"
tooltip="Skip verifying Server Certificate for TLS/SSL. If this is enabled, any certificate presented by the server and any host name in that certificate will be accepted. In this mode, TLS is susceptible to man-in-the-middle attacks. This should be used only for testing."
checked="ctrl.current.jsonData.tlsSkipVerify" switch-class="max-width-8"
on-change="ctrl.onEncryptChange()"></gf-form-switch>
tooltip="Skip verifying Server Certificate for TLS/SSL. If this is enabled, any certificate presented by the server and any host name in that certificate will be accepted. In this mode, TLS is susceptible to man-in-the-middle attacks. This should be used only for testing."
checked="ctrl.current.jsonData.tlsSkipVerify" switch-class="max-width-8" on-change="ctrl.onEncryptChange()">
</gf-form-switch>
</div>
<div class="gf-form max-width-30" ng-show="ctrl.showCertificateConfig">
<span class="gf-form-label width-15">TLS/SSL Root Certificate</span>
<input type="text" class="gf-form-input" style="width: 352px" ng-model='ctrl.current.jsonData.sslRootCertFile'
placeholder="TLS/SSL root certificate file"></input>
placeholder="TLS/SSL root certificate file"></input>
<info-popover mode="right-absolute">
Path to file containing the public key certificate of the CA that signed the SQL Server certificate. Needed when
the server certificate is self signed.
@ -84,7 +87,7 @@
<div class="gf-form max-width-30" ng-show="ctrl.showCertificateConfig">
<span class="gf-form-label width-15">Hostname in server certificate</span>
<input type="text" class="gf-form-input" style="width: 352px" ng-model='ctrl.current.jsonData.serverName'
placeholder="Common Name (CN) in server certificate"></input>
placeholder="Common Name (CN) in server certificate"></input>
<info-popover mode="right-absolute">
Specifies the Common Name (CN) in the server certificate. Default is the server host.
</info-popover>
@ -95,65 +98,64 @@
<h3 class="page-heading">Connection limits</h3>
<div class="gf-form-group">
<div class="gf-form max-width-15">
<span class="gf-form-label width-7">Max open</span>
<input type="number" min="0" class="gf-form-input gf-form-input--has-help-icon" ng-model="ctrl.current.jsonData.maxOpenConns" placeholder="unlimited"></input>
<info-popover mode="right-absolute">
The maximum number of open connections to the database. If <i>Max idle connections</i> is greater than 0 and the
<i>Max open connections</i> is less than <i>Max idle connections</i>, then <i>Max idle connections</i> will be
reduced to match the <i>Max open connections</i> limit. If set to 0, there is no limit on the number of open
connections.
</info-popover>
</div>
<div class="gf-form max-width-15">
<span class="gf-form-label width-7">Max idle</span>
<input type="number" min="0" class="gf-form-input gf-form-input--has-help-icon" ng-model="ctrl.current.jsonData.maxIdleConns" placeholder="2"></input>
<info-popover mode="right-absolute">
The maximum number of connections in the idle connection pool. If <i>Max open connections</i> is greater than 0 but
less than the <i>Max idle connections</i>, then the <i>Max idle connections</i> will be reduced to match the
<i>Max open connections</i> limit. If set to 0, no idle connections are retained.
</info-popover>
</div>
<div class="gf-form max-width-15">
<span class="gf-form-label width-7">Max lifetime</span>
<input type="number" min="0" class="gf-form-input gf-form-input--has-help-icon" ng-model="ctrl.current.jsonData.connMaxLifetime" placeholder="14400"></input>
<info-popover mode="right-absolute">
The maximum amount of time in seconds a connection may be reused. If set to 0, connections are reused forever.
</info-popover>
</div>
<div class="gf-form max-width-15">
<span class="gf-form-label width-7">Max open</span>
<input type="number" min="0" class="gf-form-input gf-form-input--has-help-icon"
ng-model="ctrl.current.jsonData.maxOpenConns" placeholder="unlimited"></input>
<info-popover mode="right-absolute">
The maximum number of open connections to the database. If <i>Max idle connections</i> is greater than 0 and the
<i>Max open connections</i> is less than <i>Max idle connections</i>, then <i>Max idle connections</i> will be
reduced to match the <i>Max open connections</i> limit. If set to 0, there is no limit on the number of open
connections.
</info-popover>
</div>
<div class="gf-form max-width-15">
<span class="gf-form-label width-7">Max idle</span>
<input type="number" min="0" class="gf-form-input gf-form-input--has-help-icon"
ng-model="ctrl.current.jsonData.maxIdleConns" placeholder="2"></input>
<info-popover mode="right-absolute">
The maximum number of connections in the idle connection pool. If <i>Max open connections</i> is greater than 0
but
less than the <i>Max idle connections</i>, then the <i>Max idle connections</i> will be reduced to match the
<i>Max open connections</i> limit. If set to 0, no idle connections are retained.
</info-popover>
</div>
<div class="gf-form max-width-15">
<span class="gf-form-label width-7">Max lifetime</span>
<input type="number" min="0" class="gf-form-input gf-form-input--has-help-icon"
ng-model="ctrl.current.jsonData.connMaxLifetime" placeholder="14400"></input>
<info-popover mode="right-absolute">
The maximum amount of time in seconds a connection may be reused. If set to 0, connections are reused forever.
</info-popover>
</div>
</div>
<h3 class="page-heading">MS SQL details</h3>
<div class="gf-form-group">
<div class="gf-form-inline">
<div class="gf-form">
<span class="gf-form-label width-9">Min time interval</span>
<input
type="text"
class="gf-form-input width-6 gf-form-input--has-help-icon"
ng-model="ctrl.current.jsonData.timeInterval"
spellcheck='false'
placeholder="1m"
ng-pattern="/^\d+(ms|[Mwdhmsy])$/"
></input>
<info-popover mode="right-absolute">
A lower limit for the auto group by time interval. Recommended to be set to write frequency,
for example <code>1m</code> if your data is written every minute.
</info-popover>
</div>
</div>
<div class="gf-form-inline">
<div class="gf-form">
<span class="gf-form-label width-9">Min time interval</span>
<input type="text" class="gf-form-input width-6 gf-form-input--has-help-icon"
ng-model="ctrl.current.jsonData.timeInterval" spellcheck='false' placeholder="1m"
ng-pattern="/^\d+(ms|[Mwdhmsy])$/"></input>
<info-popover mode="right-absolute">
A lower limit for the auto group by time interval. Recommended to be set to write frequency,
for example <code>1m</code> if your data is written every minute.
</info-popover>
</div>
</div>
</div>
<div class="gf-form-group">
<div class="grafana-info-box">
<h5>User Permission</h5>
<p>
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 <code>USE otherdb;</code> and <code>DROP TABLE user;</code> would be executed. To protect against this we
<emphasis>highly</emphasis> recommmend you create a specific MS SQL user with restricted permissions.
</p>
</div>
<div class="grafana-info-box">
<h5>User Permission</h5>
<p>
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 <code>USE otherdb;</code> and <code>DROP TABLE user;</code> would be executed. To protect against this we
<emphasis>highly</emphasis> recommmend you create a specific MS SQL user with restricted permissions.
</p>
</div>
</div>