Commit 4c73d970 by Torkel Ödegaard

Merge branch 'master' of github.com:torkelo/grafana-private into pro

parents 9d1dacb8 becdaafd
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
**Fixes** **Fixes**
- [Issue #1298](https://github.com/grafana/grafana/issues/1298). InfluxDB: Fix handling of empty array in templating variable query - [Issue #1298](https://github.com/grafana/grafana/issues/1298). InfluxDB: Fix handling of empty array in templating variable query
- [Issue #1309](https://github.com/grafana/grafana/issues/1309). Graph: Fixed issue when using zero as a grid threshold - [Issue #1309](https://github.com/grafana/grafana/issues/1309). Graph: Fixed issue when using zero as a grid threshold
- [Issue #1345](https://github.com/grafana/grafana/issues/1345). UI: Fixed position of confirm modal when scrolled down
**Tech** **Tech**
- [Issue #1311](https://github.com/grafana/grafana/issues/1311). Tech: Updated Font-Awesome from 3.2 to 4.2 - [Issue #1311](https://github.com/grafana/grafana/issues/1311). Tech: Updated Font-Awesome from 3.2 to 4.2
......
# Courtesy of https://github.com/sgzijl
# config.js includes elasticsearch: "https://"+window.location.hostname+":443",
<VirtualHost 1.2.3.4:80>
ServerName your.domain.tld
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI}
</VirtualHost>
<VirtualHost 1.2.3.4:443>
ServerName your.domain.tld
SSLEngine on
SSLCertificateFile /path/to/public.crt
SSLCertificateKeyFile /path/to/private.key
DocumentRoot /path/to/kibana3
<Directory /path/to/kibana3>
Allow from all
Options -Multiviews
</Directory>
LogLevel debug
ErrorLog /path/to/logs/error_log
CustomLog /path/to/logs/access_log combined
# Set global proxy timeouts
<Proxy http://127.0.0.1:9200>
ProxySet connectiontimeout=5 timeout=90
</Proxy>
# Proxy for _aliases and .*/_search
<LocationMatch "^/(_nodes|_aliases|_search|.*/_search|_mapping|.*/_mapping)$">
ProxyPassMatch http://127.0.0.1:9200/$1
ProxyPassReverse http://127.0.0.1:9200/$1
</LocationMatch>
# Proxy for kibana-int/{dashboard,temp} stuff (if you don't want auth on /, then you will want these to be protected)
<LocationMatch "^/(kibana-int/dashboard/|kibana-int/temp)(.*)$">
ProxyPassMatch http://127.0.0.1:9200/$1$2
ProxyPassReverse http://127.0.0.1:9200/$1$2
</LocationMatch>
# Optional disable auth for a src IP (eg: your monitoring host or subnet)
<Location />
Allow from 5.6.7.8
Deny from all
Satisfy any
AuthLDAPBindDN "CN=_ldapbinduser,OU=Users,DC=example,DC=com"
AuthLDAPBindPassword "ldapbindpass"
AuthLDAPURL "ldaps://ldap01.example.com ldap02.example.com/OU=Users,DC=example,DC=com?sAMAccountName?sub?(objectClass=*)"
AuthType Basic
AuthBasicProvider ldap
AuthName "Please authenticate for Example dot com"
AuthLDAPGroupAttributeIsDN on
require valid-user
</Location>
</VirtualHost>
$HTTP["host"] =~ "kibana" {
server.document-root = "/var/ww/kibana/src"
auth.backend = "plain"
auth.backend.plain.userfile = "/etc/lighttpd/kibanapassword"
index-file.names = ( "index.html", "index.htm" )
auth.require = ( "/" => (
"method" => "basic",
"realm" => "Password Protected",
"require" => "valid-user"
)
)
$HTTP["url"] =~ "^/kibana-int/(dashboard/|temp).*$" {
proxy.balance = "hash"
proxy.server = ( "" => ( ( "host" => "127.0.0.1", "port" => "9200" ) ) )
}
$HTTP["url"] =~ "^.*/_(mapping|search|nodes|aliases)$" {
proxy.balance = "hash"
proxy.server = ( "" => ( ( "host" => "127.0.0.1", "port" => "9200" ) ) )
}
}
#
# Nginx proxy for Elasticsearch + Kibana
#
# In this setup, we are password protecting the saving of dashboards. You may
# wish to extend the password protection to all paths.
#
# Even though these paths are being called as the result of an ajax request, the
# browser will prompt for a username/password on the first request
#
# If you use this, you'll want to point config.js at http://FQDN:80/ instead of
# http://FQDN:9200
#
server {
listen *:80 ;
server_name kibana.myhost.org;
access_log /var/log/nginx/kibana.myhost.org.access.log;
location / {
root /usr/share/kibana3;
index index.html index.htm;
}
location ~ ^/_aliases$ {
proxy_pass http://127.0.0.1:9200;
proxy_read_timeout 90;
}
location ~ ^/_nodes$ {
proxy_pass http://127.0.0.1:9200;
proxy_read_timeout 90;
}
location ~ ^/.*/_search$ {
proxy_pass http://127.0.0.1:9200;
proxy_read_timeout 90;
}
location ~ ^/.*/_mapping$ {
proxy_pass http://127.0.0.1:9200;
proxy_read_timeout 90;
}
# Password protected end points
location ~ ^/kibana-int/dashboard/.*$ {
proxy_pass http://127.0.0.1:9200;
proxy_read_timeout 90;
limit_except GET {
proxy_pass http://127.0.0.1:9200;
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/conf.d/kibana.myhost.org.htpasswd;
}
}
location ~ ^/kibana-int/temp.*$ {
proxy_pass http://127.0.0.1:9200;
proxy_read_timeout 90;
limit_except GET {
proxy_pass http://127.0.0.1:9200;
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/conf.d/kibana.myhost.org.htpasswd;
}
}
}
#!/usr/bin/env node
var util = require('util'),
http = require('http'),
fs = require('fs'),
url = require('url'),
events = require('events');
var DEFAULT_PORT = 8000;
function main(argv) {
new HttpServer({
'GET': createServlet(StaticServlet),
'HEAD': createServlet(StaticServlet)
}).start(Number(argv[2]) || DEFAULT_PORT);
}
function escapeHtml(value) {
return value.toString().
replace('<', '&lt;').
replace('>', '&gt;').
replace('"', '&quot;');
}
function createServlet(Class) {
var servlet = new Class();
return servlet.handleRequest.bind(servlet);
}
/**
* An Http server implementation that uses a map of methods to decide
* action routing.
*
* @param {Object} Map of method => Handler function
*/
function HttpServer(handlers) {
this.handlers = handlers;
this.server = http.createServer(this.handleRequest_.bind(this));
}
HttpServer.prototype.start = function(port) {
this.port = port;
this.server.listen(port);
util.puts('Http Server running at http://localhost:' + port + '/');
};
HttpServer.prototype.parseUrl_ = function(urlString) {
var parsed = url.parse(urlString);
parsed.pathname = url.resolve('/', parsed.pathname);
return url.parse(url.format(parsed), true);
};
HttpServer.prototype.handleRequest_ = function(req, res) {
var logEntry = req.method + ' ' + req.url;
if (req.headers['user-agent']) {
logEntry += ' ' + req.headers['user-agent'];
}
util.puts(logEntry);
req.url = this.parseUrl_(req.url);
var handler = this.handlers[req.method];
if (!handler) {
res.writeHead(501);
res.end();
} else {
handler.call(this, req, res);
}
};
/**
* Handles static content.
*/
function StaticServlet() {}
StaticServlet.MimeMap = {
'txt': 'text/plain',
'html': 'text/html',
'css': 'text/css',
'xml': 'application/xml',
'json': 'application/json',
'js': 'application/javascript',
'jpg': 'image/jpeg',
'jpeg': 'image/jpeg',
'gif': 'image/gif',
'png': 'image/png',
  'svg': 'image/svg+xml'
};
StaticServlet.prototype.handleRequest = function(req, res) {
var self = this;
var path = ('../src/' + req.url.pathname).replace('//','/').replace(/%(..)/g, function(match, hex){
return String.fromCharCode(parseInt(hex, 16));
});
var parts = path.split('/');
if (parts[parts.length-1].charAt(0) === '.')
return self.sendForbidden_(req, res, path);
fs.stat(path, function(err, stat) {
if (err)
return self.sendMissing_(req, res, path);
if (stat.isDirectory())
return self.sendDirectory_(req, res, path);
return self.sendFile_(req, res, path);
});
}
StaticServlet.prototype.sendError_ = function(req, res, error) {
res.writeHead(500, {
'Content-Type': 'text/html'
});
res.write('<!doctype html>\n');
res.write('<title>Internal Server Error</title>\n');
res.write('<h1>Internal Server Error</h1>');
res.write('<pre>' + escapeHtml(util.inspect(error)) + '</pre>');
util.puts('500 Internal Server Error');
util.puts(util.inspect(error));
};
StaticServlet.prototype.sendMissing_ = function(req, res, path) {
path = path.substring(1);
res.writeHead(404, {
'Content-Type': 'text/html'
});
res.write('<!doctype html>\n');
res.write('<title>404 Not Found</title>\n');
res.write('<h1>Not Found</h1>');
res.write(
'<p>The requested URL ' +
escapeHtml(path) +
' was not found on this server.</p>'
);
res.end();
util.puts('404 Not Found: ' + path);
};
StaticServlet.prototype.sendForbidden_ = function(req, res, path) {
path = path.substring(1);
res.writeHead(403, {
'Content-Type': 'text/html'
});
res.write('<!doctype html>\n');
res.write('<title>403 Forbidden</title>\n');
res.write('<h1>Forbidden</h1>');
res.write(
'<p>You do not have permission to access ' +
escapeHtml(path) + ' on this server.</p>'
);
res.end();
util.puts('403 Forbidden: ' + path);
};
StaticServlet.prototype.sendRedirect_ = function(req, res, redirectUrl) {
res.writeHead(301, {
'Content-Type': 'text/html',
'Location': redirectUrl
});
res.write('<!doctype html>\n');
res.write('<title>301 Moved Permanently</title>\n');
res.write('<h1>Moved Permanently</h1>');
res.write(
'<p>The document has moved <a href="' +
redirectUrl +
'">here</a>.</p>'
);
res.end();
util.puts('301 Moved Permanently: ' + redirectUrl);
};
StaticServlet.prototype.sendFile_ = function(req, res, path) {
var self = this;
var file = fs.createReadStream(path);
res.writeHead(200, {
'Content-Type': StaticServlet.
MimeMap[path.split('.').pop()] || 'text/plain'
});
if (req.method === 'HEAD') {
res.end();
} else {
file.on('data', res.write.bind(res));
file.on('close', function() {
res.end();
});
file.on('error', function(error) {
self.sendError_(req, res, error);
});
}
};
StaticServlet.prototype.sendDirectory_ = function(req, res, path) {
var self = this;
if (path.match(/[^\/]$/)) {
req.url.pathname += '/';
var redirectUrl = url.format(url.parse(url.format(req.url)));
return self.sendRedirect_(req, res, redirectUrl);
}
fs.readdir(path, function(err, files) {
if (err)
return self.sendError_(req, res, error);
if (!files.length)
return self.writeDirectoryIndex_(req, res, path, []);
var remaining = files.length;
files.forEach(function(fileName, index) {
fs.stat(path + '/' + fileName, function(err, stat) {
if (err)
return self.sendError_(req, res, err);
if (stat.isDirectory()) {
files[index] = fileName + '/';
}
if (!(--remaining))
return self.writeDirectoryIndex_(req, res, path, files);
});
});
});
};
StaticServlet.prototype.writeDirectoryIndex_ = function(req, res, path, files) {
path = path.substring(1);
res.writeHead(200, {
'Content-Type': 'text/html'
});
if (req.method === 'HEAD') {
res.end();
return;
}
res.write('<!doctype html>\n');
res.write('<title>' + escapeHtml(path) + '</title>\n');
res.write('<style>\n');
res.write(' ol { list-style-type: none; font-size: 1.2em; }\n');
res.write('</style>\n');
res.write('<h1>Directory: ' + escapeHtml(path) + '</h1>');
res.write('<ol>');
files.forEach(function(fileName) {
if (fileName.charAt(0) !== '.') {
res.write('<li><a href="' +
escapeHtml(fileName) + '">' +
escapeHtml(fileName) + '</a></li>');
}
});
res.write('</ol>');
res.end();
};
// Must be last,
main(process.argv);
<br/>
<div class="row-fluid">
<div class="span6">
<ul>
<li>
<a href="http://grafana.org/docs#configuration" target="_blank">Configuration</a>
</li>
<li>
<a href="http://grafana.org/docs/troubleshooting" target="_blank">Troubleshooting</a>
</li>
<li>
<a href="http://grafana.org/docs/support" target="_blank">Support</a>
</li>
<li>
<a href="http://grafana.org/docs/features/intro" target="_blank">Getting started</a> (Must read!)
</li>
</ul>
</div>
<div class="span6">
<ul>
<li>
<a href="http://grafana.org/docs/features/graphing" target="_blank">Graphing</a>
</li>
<li>
<a href="http://grafana.org/docs/features/annotations" target="_blank">Annotations</a>
</li>
<li>
<a href="http://grafana.org/docs/features/graphite" target="_blank">Graphite</a>
</li>
<li>
<a href="http://grafana.org/docs/features/influxdb" target="_blank">InfluxDB</a>
</li>
<li>
<a href="http://grafana.org/docs/features/opentsdb" target="_blank">OpenTSDB</a>
</li>
</ul>
</div>
</div>
<br/>
<div class="row-fluid">
<div class="span12">
<ul>
<li>Ctrl+S saves the current dashboard</li>
<li>Ctrl+F Opens the dashboard finder</li>
<li>Ctrl+H Hide/show row controls</li>
<li>Click and drag graph title to move panel</li>
<li>Hit Escape to exit graph when in fullscreen or edit mode</li>
<li>Click the colored icon in the legend to change series color</li>
<li>Ctrl or Shift + Click legend name to hide other series</li>
</ul>
</div>
</div>
...@@ -12,10 +12,10 @@ function (angular, app, _, $) { ...@@ -12,10 +12,10 @@ function (angular, app, _, $) {
.directive('dropdownTypeahead', function($compile) { .directive('dropdownTypeahead', function($compile) {
var inputTemplate = '<input type="text"'+ var inputTemplate = '<input type="text"'+
' class="grafana-target-segment-input input-medium grafana-target-segment-input"' + ' class="tight-form-input input-medium tight-form-input"' +
' spellcheck="false" style="display:none"></input>'; ' spellcheck="false" style="display:none"></input>';
var buttonTemplate = '<a class="grafana-target-segment grafana-target-function dropdown-toggle"' + var buttonTemplate = '<a class="tight-form-item tight-form-func dropdown-toggle"' +
' tabindex="1" gf-dropdown="menuItems" data-toggle="dropdown"' + ' tabindex="1" gf-dropdown="menuItems" data-toggle="dropdown"' +
' data-placement="top"><i class="fa fa-plus"></i></a>'; ' data-placement="top"><i class="fa fa-plus"></i></a>';
......
...@@ -11,10 +11,10 @@ function (angular, app, _, $) { ...@@ -11,10 +11,10 @@ function (angular, app, _, $) {
.module('grafana.directives') .module('grafana.directives')
.directive('graphiteSegment', function($compile, $sce) { .directive('graphiteSegment', function($compile, $sce) {
var inputTemplate = '<input type="text" data-provide="typeahead" ' + var inputTemplate = '<input type="text" data-provide="typeahead" ' +
' class="grafana-target-text-input input-medium"' + ' class="tight-form-clear-input input-medium"' +
' spellcheck="false" style="display:none"></input>'; ' spellcheck="false" style="display:none"></input>';
var buttonTemplate = '<a class="grafana-target-segment" tabindex="1" focus-me="segment.focus" ng-bind-html="segment.html"></a>'; var buttonTemplate = '<a class="tight-form-item" tabindex="1" focus-me="segment.focus" ng-bind-html="segment.html"></a>';
return { return {
link: function($scope, elem) { link: function($scope, elem) {
......
...@@ -11,10 +11,10 @@ function (angular, app, _, $) { ...@@ -11,10 +11,10 @@ function (angular, app, _, $) {
.module('grafana.directives') .module('grafana.directives')
.directive('templateParamSelector', function($compile) { .directive('templateParamSelector', function($compile) {
var inputTemplate = '<input type="text" data-provide="typeahead" ' + var inputTemplate = '<input type="text" data-provide="typeahead" ' +
' class="grafana-target-text-input input-medium"' + ' class="tight-form-clear-input input-medium"' +
' spellcheck="false" style="display:none"></input>'; ' spellcheck="false" style="display:none"></input>';
var buttonTemplate = '<a class="grafana-target-segment tabindex="1">{{variable.current.text}}</a>'; var buttonTemplate = '<a class="tight-form-item tabindex="1">{{variable.current.text}}</a>';
return { return {
link: function($scope, elem) { link: function($scope, elem) {
......
...@@ -12,10 +12,10 @@ function (angular, app, _, $, gfunc) { ...@@ -12,10 +12,10 @@ function (angular, app, _, $, gfunc) {
.module('grafana.directives') .module('grafana.directives')
.directive('graphiteAddFunc', function($compile) { .directive('graphiteAddFunc', function($compile) {
var inputTemplate = '<input type="text"'+ var inputTemplate = '<input type="text"'+
' class="grafana-target-segment-input input-medium grafana-target-segment-input"' + ' class="tight-form-input input-medium tight-form-input"' +
' spellcheck="false" style="display:none"></input>'; ' spellcheck="false" style="display:none"></input>';
var buttonTemplate = '<a class="grafana-target-segment grafana-target-function dropdown-toggle"' + var buttonTemplate = '<a class="tight-form-item tight-form-func dropdown-toggle"' +
' tabindex="1" gf-dropdown="functionMenu" data-toggle="dropdown"' + ' tabindex="1" gf-dropdown="functionMenu" data-toggle="dropdown"' +
' data-placement="top"><i class="fa fa-plus"></i></a>'; ' data-placement="top"><i class="fa fa-plus"></i></a>';
......
...@@ -12,10 +12,10 @@ function (angular, _, $) { ...@@ -12,10 +12,10 @@ function (angular, _, $) {
var funcSpanTemplate = '<a ng-click="">{{func.def.name}}</a><span>(</span>'; var funcSpanTemplate = '<a ng-click="">{{func.def.name}}</a><span>(</span>';
var paramTemplate = '<input type="text" style="display:none"' + var paramTemplate = '<input type="text" style="display:none"' +
' class="input-mini grafana-function-param-input"></input>'; ' class="input-mini tight-form-func-param"></input>';
var funcControlsTemplate = var funcControlsTemplate =
'<div class="graphite-func-controls">' + '<div class="tight-form-func-controls">' +
'<span class="pointer fa fa-arrow-left"></span>' + '<span class="pointer fa fa-arrow-left"></span>' +
'<span class="pointer fa fa-question-circle"></span>' + '<span class="pointer fa fa-question-circle"></span>' +
'<span class="pointer fa fa-remove" ></span>' + '<span class="pointer fa fa-remove" ></span>' +
...@@ -126,7 +126,7 @@ function (angular, _, $) { ...@@ -126,7 +126,7 @@ function (angular, _, $) {
} }
function toggleFuncControls() { function toggleFuncControls() {
var targetDiv = elem.closest('.grafana-target-inner'); var targetDiv = elem.closest('.tight-form');
if (elem.hasClass('show-function-controls')) { if (elem.hasClass('show-function-controls')) {
elem.removeClass('show-function-controls'); elem.removeClass('show-function-controls');
......
<div class="editor-row"> <div class="editor-row">
<div ng-repeat="target in panel.targets" <div ng-repeat="target in panel.targets"
class="grafana-target" class="tight-form"
ng-class="{'grafana-target-hidden': target.hide}" ng-class="{'tight-form-disabled': target.hide}"
ng-controller="GraphiteQueryCtrl" ng-controller="GraphiteQueryCtrl"
ng-init="init()"> ng-init="init()">
<ul class="tight-form-list pull-right">
<div class="grafana-target-inner"> <li ng-show="parserError" class="tight-form-item">
<ul class="grafana-segment-list pull-right">
<li ng-show="parserError" class="grafana-target-segment">
<a bs-tooltip="parserError" style="color: rgb(229, 189, 28)" role="menuitem"> <a bs-tooltip="parserError" style="color: rgb(229, 189, 28)" role="menuitem">
<i class="fa fa-warning"></i> <i class="fa fa-warning"></i>
</a> </a>
</li> </li>
<li class="grafana-target-segment"> <li class="tight-form-item">
<a class="pointer" tabindex="1" ng-click="showTextEditor = !showTextEditor"> <a class="pointer" tabindex="1" ng-click="showTextEditor = !showTextEditor">
<i class="fa fa-pencil"></i> <i class="fa fa-pencil"></i>
</a> </a>
</li> </li>
<li class="grafana-target-segment"> <li class="tight-form-item">
<div class="dropdown"> <div class="dropdown">
<a class="pointer dropdown-toggle" <a class="pointer dropdown-toggle"
data-toggle="dropdown" data-toggle="dropdown"
...@@ -47,19 +45,19 @@ ...@@ -47,19 +45,19 @@
</ul> </ul>
</div> </div>
</li> </li>
<li class="grafana-target-segment last"> <li class="tight-form-item last">
<a class="pointer" tabindex="1" ng-click="removeDataQuery(target)"> <a class="pointer" tabindex="1" ng-click="removeDataQuery(target)">
<i class="fa fa-remove"></i> <i class="fa fa-remove"></i>
</a> </a>
</li> </li>
</ul> </ul>
<ul class="grafana-segment-list"> <ul class="tight-form-list">
<li class="grafana-target-segment" style="min-width: 15px; text-align: center"> <li class="tight-form-item" style="min-width: 15px; text-align: center">
{{targetLetters[$index]}} {{targetLetters[$index]}}
</li> </li>
<li> <li>
<a class="grafana-target-segment" <a class="tight-form-item"
ng-click="target.hide = !target.hide; get_data();" ng-click="target.hide = !target.hide; get_data();"
role="menuitem"> role="menuitem">
<i class="fa fa-eye"></i> <i class="fa fa-eye"></i>
...@@ -68,17 +66,17 @@ ...@@ -68,17 +66,17 @@
</ul> </ul>
<input type="text" <input type="text"
class="grafana-target-text-input span10" class="tight-form-clear-input span10"
ng-model="target.target" ng-model="target.target"
focus-me="showTextEditor" focus-me="showTextEditor"
spellcheck='false' spellcheck='false'
ng-model-onblur ng-change="targetTextChanged()" ng-model-onblur ng-change="targetTextChanged()"
ng-show="showTextEditor" /> ng-show="showTextEditor" />
<ul class="grafana-segment-list" role="menu" ng-hide="showTextEditor"> <ul class="tight-form-list" role="menu" ng-hide="showTextEditor">
<li ng-repeat="segment in segments" role="menuitem" graphite-segment></li> <li ng-repeat="segment in segments" role="menuitem" graphite-segment></li>
<li ng-repeat="func in functions"> <li ng-repeat="func in functions">
<span graphite-func-editor class="grafana-target-segment grafana-target-function"> <span graphite-func-editor class="tight-form-item tight-form-func">
</span> </span>
</li> </li>
<li class="dropdown" graphite-add-func> <li class="dropdown" graphite-add-func>
...@@ -86,80 +84,75 @@ ...@@ -86,80 +84,75 @@
</ul> </ul>
<div class="clearfix"></div> <div class="clearfix"></div>
</div> </div>
</div>
</div> </div>
<section class="grafana-metric-options"> <section class="grafana-metric-options">
<div class="grafana-target"> <div class="tight-form">
<div class="grafana-target-inner"> <ul class="tight-form-list">
<ul class="grafana-segment-list"> <li class="tight-form-item tight-form-item-icon">
<li class="grafana-target-segment grafana-target-segment-icon"> <i class="fa fa-wrench"></i>
<i class="fa fa-wrench"></i> </li>
</li> <li class="tight-form-item">
<li class="grafana-target-segment"> Cache timeout
Cache timeout </li>
</li> <li>
<li> <input type="text"
<input type="text" class="input-mini tight-form-input"
class="input-mini grafana-target-segment-input" ng-model="panel.cacheTimeout"
ng-model="panel.cacheTimeout" bs-tooltip="'Graphite parameter to override memcache default timeout (unit is seconds)'"
bs-tooltip="'Graphite parameter to override memcache default timeout (unit is seconds)'" data-placement="right"
data-placement="right" spellcheck='false'
spellcheck='false' placeholder="60">
placeholder="60"> </li>
</li> <li class="tight-form-item">
<li class="grafana-target-segment"> Max data points
Max data points </li>
</li> <li>
<li> <input type="text"
<input type="text" class="input-mini tight-form-input"
class="input-mini grafana-target-segment-input" ng-model="panel.maxDataPoints"
ng-model="panel.maxDataPoints" bs-tooltip="'Override max data points, automatically set to graph width in pixels.'"
bs-tooltip="'Override max data points, automatically set to graph width in pixels.'" data-placement="right"
data-placement="right" ng-model-onblur ng-change="get_data()"
ng-model-onblur ng-change="get_data()" spellcheck='false'
spellcheck='false' placeholder="auto">
placeholder="auto"> </li>
</li> </ul>
</ul> <div class="clearfix"></div>
<div class="clearfix"></div> </div>
</div> <div class="tight-form">
<div class="grafana-target-inner"> <ul class="tight-form-list">
<ul class="grafana-segment-list"> <li class="tight-form-item tight-form-item-icon">
<li class="grafana-target-segment grafana-target-segment-icon"> <i class="fa fa-info-circle"></i>
<i class="fa fa-info-circle"></i> </li>
</li> <li class="tight-form-item">
<li class="grafana-target-segment"> <a ng-click="toggleEditorHelp(1);" bs-tooltip="'click to show helpful info'" data-placement="bottom">
<a ng-click="toggleEditorHelp(1);" bs-tooltip="'click to show helpful info'" data-placement="bottom"> shorter legend names
shorter legend names </a>
</a> </li>
</li> <li class="tight-form-item">
<li class="grafana-target-segment"> <a ng-click="toggleEditorHelp(2);" bs-tooltip="'click to show helpful info'" data-placement="bottom">
<a ng-click="toggleEditorHelp(2);" bs-tooltip="'click to show helpful info'" data-placement="bottom"> series as parameters
series as parameters </a>
</a> </li>
</li> <li class="tight-form-item">
<li class="grafana-target-segment"> <a ng-click="toggleEditorHelp(3)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
<a ng-click="toggleEditorHelp(3)" bs-tooltip="'click to show helpful info'" data-placement="bottom"> stacking
stacking </a>
</a> </li>
</li> <li class="tight-form-item">
<li class="grafana-target-segment"> <a ng-click="toggleEditorHelp(4)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
<a ng-click="toggleEditorHelp(4)" bs-tooltip="'click to show helpful info'" data-placement="bottom"> templating
templating </a>
</a> </li>
</li> <li class="tight-form-item">
<li class="grafana-target-segment"> <a ng-click="toggleEditorHelp(5)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
<a ng-click="toggleEditorHelp(5)" bs-tooltip="'click to show helpful info'" data-placement="bottom"> max data points
max data points </a>
</a> </li>
</li> </ul>
</ul> <div class="clearfix"></div>
<div class="clearfix"></div>
</div>
</div> </div>
</div>
</section> </section>
<div class="editor-row"> <div class="editor-row">
......
...@@ -14,7 +14,7 @@ function (angular, _, $) { ...@@ -14,7 +14,7 @@ function (angular, _, $) {
'data-toggle="dropdown">{{target.function}}</a><span>(</span>'; 'data-toggle="dropdown">{{target.function}}</a><span>(</span>';
var paramTemplate = '<input type="text" style="display:none"' + var paramTemplate = '<input type="text" style="display:none"' +
' class="input-mini grafana-function-param-input"></input>'; ' class="input-mini tight-form-func-param"></input>';
return { return {
restrict: 'A', restrict: 'A',
......
...@@ -2,45 +2,43 @@ ...@@ -2,45 +2,43 @@
<div class="section"> <div class="section">
<h5>Drilldown / detail link<tip>These links appear in the dropdown menu in the panel menu. </tip></h5> <h5>Drilldown / detail link<tip>These links appear in the dropdown menu in the panel menu. </tip></h5>
<div class="grafana-target" ng-repeat="link in panel.links"j> <div class="tight-form" ng-repeat="link in panel.links"j>
<div class="grafana-target-inner"> <ul class="tight-form-list">
<ul class="grafana-segment-list"> <li class="tight-form-item">
<li class="grafana-target-segment"> <i class="fa fa-remove pointer" ng-click="deleteLink(link)"></i>
<i class="fa fa-remove pointer" ng-click="deleteLink(link)"></i> </li>
</li>
<li class="grafana-target-segment">title</li> <li class="tight-form-item">title</li>
<li> <li>
<input type="text" ng-model="link.title" class="input-medium grafana-target-segment-input"> <input type="text" ng-model="link.title" class="input-medium tight-form-input">
</li> </li>
<li class="grafana-target-segment">type</li> <li class="tight-form-item">type</li>
<li> <li>
<select class="input-medium grafana-target-segment-input" style="width: 101px;" ng-model="link.type" ng-options="f for f in ['dashboard','absolute']"></select> <select class="input-medium tight-form-input" style="width: 101px;" ng-model="link.type" ng-options="f for f in ['dashboard','absolute']"></select>
</li> </li>
<li class="grafana-target-segment" ng-show="link.type === 'dashboard'">dashboard</li> <li class="tight-form-item" ng-show="link.type === 'dashboard'">dashboard</li>
<li ng-show="link.type === 'dashboard'"> <li ng-show="link.type === 'dashboard'">
<input type="text" <input type="text"
ng-model="link.dashboard" ng-model="link.dashboard"
bs-typeahead="searchDashboards" bs-typeahead="searchDashboards"
class="input-large grafana-target-segment-input"> class="input-large tight-form-input">
</li> </li>
<li class="grafana-target-segment" ng-show="link.type === 'absolute'">url</li> <li class="tight-form-item" ng-show="link.type === 'absolute'">url</li>
<li ng-show="link.type === 'absolute'"> <li ng-show="link.type === 'absolute'">
<input type="text" ng-model="link.url" class="input-large grafana-target-segment-input"> <input type="text" ng-model="link.url" class="input-large tight-form-input">
</li> </li>
<li class="grafana-target-segment">params <li class="tight-form-item">params
<tip>Use var-variableName=value to pass templating variables.</tip> <tip>Use var-variableName=value to pass templating variables.</tip>
</li> </li>
<li> <li>
<input type="text" ng-model="link.params" class="input-medium grafana-target-segment-input"> <input type="text" ng-model="link.params" class="input-medium tight-form-input">
</li> </li>
</ul> </ul>
<div class="clearfix"></div> <div class="clearfix"></div>
</div>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -66,35 +66,33 @@ ...@@ -66,35 +66,33 @@
<div class="section"> <div class="section">
<h5>Series specific overrides <tip>Regex match example: /server[0-3]/i </tip></h5> <h5>Series specific overrides <tip>Regex match example: /server[0-3]/i </tip></h5>
<div> <div>
<div class="grafana-target" ng-repeat="override in panel.seriesOverrides" ng-controller="SeriesOverridesCtrl"> <div class="tight-form" ng-repeat="override in panel.seriesOverrides" ng-controller="SeriesOverridesCtrl">
<div class="grafana-target-inner"> <ul class="tight-form-list">
<ul class="grafana-segment-list"> <li class="tight-form-item">
<li class="grafana-target-segment"> <i class="fa fa-remove pointer" ng-click="removeSeriesOverride(override)"></i>
<i class="fa fa-remove pointer" ng-click="removeSeriesOverride(override)"></i> </li>
</li>
<li class="grafana-target-segment"> <li class="tight-form-item">
alias or regex alias or regex
</li> </li>
<li> <li>
<input type="text" <input type="text"
ng-model="override.alias" ng-model="override.alias"
bs-typeahead="getSeriesNames" bs-typeahead="getSeriesNames"
ng-blur="render()" ng-blur="render()"
data-min-length=0 data-items=100 data-min-length=0 data-items=100
class="input-medium grafana-target-segment-input" > class="input-medium tight-form-input" >
</li> </li>
<li class="grafana-target-segment" ng-repeat="option in currentOverrides"> <li class="tight-form-item" ng-repeat="option in currentOverrides">
<i class="pointer fa fa-remove" ng-click="removeOverride(option)"></i> <i class="pointer fa fa-remove" ng-click="removeOverride(option)"></i>
{{option.name}}: {{option.value}} {{option.name}}: {{option.value}}
</li> </li>
<li class="dropdown" dropdown-typeahead="overrideMenu" dropdown-typeahead-on-select="setOverride($item, $subItem)"> <li class="dropdown" dropdown-typeahead="overrideMenu" dropdown-typeahead-on-select="setOverride($item, $subItem)">
</li> </li>
</ul> </ul>
<div class="clearfix"></div> <div class="clearfix"></div>
</div>
</div> </div>
</div> </div>
......
<div class="submenu-controls" ng-controller="SubmenuCtrl"> <div class="submenu-controls" ng-controller="SubmenuCtrl">
<div class="grafana-target"> <div class="tight-form" style="border-top: none">
<div class="grafana-target-inner" style="border-top: none">
<ul class="grafana-segment-list"> <ul class="tight-form-list">
<li class="grafana-target-segment"> <li class="tight-form-item">
<div class="dropdown"> <div class="dropdown">
<a class="pointer" data-toggle="dropdown"> <a class="pointer" data-toggle="dropdown">
<i class="fa fa-cog"></i> <i class="fa fa-cog"></i>
</a> </a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a class="pointer" dash-editor-link="app/partials/templating_editor.html">Templating</a></li> <li><a class="pointer" dash-editor-link="app/partials/templating_editor.html">Templating</a></li>
<li><a class="pointer" dash-editor-link="app/features/annotations/partials/editor.html">Annotations</a></li> <li><a class="pointer" dash-editor-link="app/features/annotations/partials/editor.html">Annotations</a></li>
</ul> </ul>
</div> </div>
</li> </li>
</ul> </ul>
<ul class="grafana-segment-list" ng-if="dashboard.templating.enable"> <ul class="tight-form-list" ng-if="dashboard.templating.enable">
<li ng-repeat-start="variable in variables" class="grafana-target-segment template-param-name"> <li ng-repeat-start="variable in variables" class="tight-form-item template-param-name">
<span class="template-variable "> <span class="template-variable ">
${{variable.name}}: ${{variable.name}}:
</span> </span>
</li> </li>
<li ng-repeat-end template-param-selector> <li ng-repeat-end template-param-selector>
</li> </li>
</ul> </ul>
<ul class="grafana-segment-list" ng-if="dashboard.annotations.enable"> <ul class="tight-form-list" ng-if="dashboard.annotations.enable">
<li ng-repeat="annotation in dashboard.annotations.list" class="grafana-target-segment annotation-segment" ng-class="{'annotation-disabled': !annotation.enable}"> <li ng-repeat="annotation in dashboard.annotations.list" class="tight-form-item annotation-segment" ng-class="{'annotation-disabled': !annotation.enable}">
<a ng-click="disableAnnotation(annotation)"> <a ng-click="disableAnnotation(annotation)">
<i class="annotation-color-icon fa fa-bolt"></i> <i class="annotation-color-icon fa fa-bolt"></i>
{{annotation.name}} {{annotation.name}}
</a> </a>
</li> </li>
</ul> </ul>
<div class="clearfix"></div> <div class="clearfix"></div>
</div>
</div>
</div> </div>
</div>
...@@ -26,3 +26,4 @@ input[type="checkbox"]:checked+label { ...@@ -26,3 +26,4 @@ input[type="checkbox"]:checked+label {
background: url(@checkboxImageUrl) 0px -18px no-repeat; background: url(@checkboxImageUrl) 0px -18px no-repeat;
} }
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
@import "panel.less"; @import "panel.less";
@import "forms.less"; @import "forms.less";
@import "singlestat.less"; @import "singlestat.less";
@import "tightform.less";
.row-control-inner { .row-control-inner {
padding:0px; padding:0px;
...@@ -67,7 +68,7 @@ ...@@ -67,7 +68,7 @@
right: 0; right: 0;
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
top: 200px; top: 30%;
} }
.grafana-search-metric-actions { .grafana-search-metric-actions {
...@@ -102,175 +103,6 @@ ...@@ -102,175 +103,6 @@
position:relative; position:relative;
} }
.grafana-target:last-child {
border-bottom: 1px solid @grafanaTargetBorder;
}
.grafana-target-inner {
border-top: 1px solid @grafanaTargetBorder;
border-left: 1px solid @grafanaTargetBorder;
border-right: 1px solid @grafanaTargetBorder;
background: @grafanaTargetBackground;
width: 100%;
}
.grafana-target-onoff {
display: inline-block;
padding: 5px 7px;
display: inline-block;
}
.grafana-segment-list {
list-style: none;
margin: 0;
>li {
float: left;
}
}
.grafana-metric-options {
margin-top: 35px;
}
// fix for fixed positioned panel & scrolling
.grafana-segment-dropdown-menu {
margin-bottom: 70px;
}
.grafana-target-segment {
padding: 8px 7px;
display: inline-block;
font-weight: normal;
border-right: 1px solid @grafanaTargetSegmentBorder;
color: @grafanaTargetColor;
display: inline-block;
.has-open-function & {
padding-top: 25px;
}
.grafana-target-hidden & {
color: @grafanaTargetColorHide;
}
&:hover, &:focus {
text-decoration: none;
}
&a:hover {
background: @grafanaTargetFuncBackground;
}
&.template-param-name {
border-right: none;
padding-right: 3px;
}
&.annotation-segment {
padding: 8px 15px;
}
&.last {
border-right: none;
}
}
.grafana-target-segment-icon {
i {
width: 15px;
text-align: center;
display: inline-block;
}
}
.grafana-target-function {
background: @grafanaTargetFuncBackground;
> a {
color: @grafanaTargetColor;
}
> a:hover {
color: @linkColor;
}
&.show-function-controls {
padding-top: 5px;
min-width: 100px;
text-align: center;
}
}
input[type=text].grafana-function-param-input {
background: transparent;
border: none;
margin: 0;
padding: 0;
}
input[type=text].grafana-target-text-input {
padding: 8px 7px;
border: none;
margin: 0px;
background: transparent;
float: left;
color: @grafanaTargetColor;
border-radius: 0;
border-right: 1px solid @grafanaTargetSegmentBorder;
}
[type=text].grafana-target-segment-input, [type=number].grafana-target-segment-input {
border: none;
border-right: 1px solid @grafanaTargetSegmentBorder;
margin: 0px;
border-radius: 0;
padding: 8px 4px;
&.last {
border-right: none;
}
}
input[type=checkbox].grafana-target-option-checkbox {
margin: 0;
}
select.grafana-target-segment-input {
border: none;
border-right: 1px solid @grafanaTargetSegmentBorder;
margin: 0px;
border-radius: 0;
height: 36px;
padding: 8px 5px;
&.last {
border-right: none;
}
}
.grafana-target .dropdown {
padding: 0; margin: 0;
}
.graphite-func-controls {
display: none;
text-align: center;
.fa-arrow-left {
float: left;
position: relative;
top: 2px;
}
.fa-arrow-right {
float: right;
position: relative;
top: 2px;
}
.fa-remove {
margin-left: 10px;
}
}
.grafana-target {
.popover-content {
padding: 0;
}
}
.scrollable { .scrollable {
max-height: 300px; max-height: 300px;
overflow: auto; overflow: auto;
......
.tight-form {
border-top: 1px solid @grafanaTargetBorder;
border-left: 1px solid @grafanaTargetBorder;
border-right: 1px solid @grafanaTargetBorder;
background: @grafanaTargetBackground;
width: 100%;
.dropdown {
padding: 0; margin: 0;
}
&:last-child {
border-bottom: 1px solid @grafanaTargetBorder;
}
}
.tight-form-container {
.tight-form:last-child {
border-bottom: none;
}
&:last-child {
border-bottom: 1px solid @grafanaTargetBorder;
}
}
// old graphite-segment-list
.tight-form-list {
list-style: none;
margin: 0;
>li {
float: left;
}
}
.grafana-metric-options {
margin-top: 35px;
}
// old grafana-target-segment {
.tight-form-item {
padding: 8px 7px;
display: inline-block;
font-weight: normal;
border-right: 1px solid @grafanaTargetSegmentBorder;
color: @grafanaTargetColor;
display: inline-block;
.has-open-function & {
padding-top: 25px;
}
// old .grafana-target-hidden & {
.tight-form-disabled & {
color: @grafanaTargetColorHide;
}
&:hover, &:focus {
text-decoration: none;
}
&a:hover {
background: @grafanaTargetFuncBackground;
}
&.template-param-name {
border-right: none;
padding-right: 3px;
}
&.annotation-segment {
padding: 8px 15px;
}
&.last {
border-right: none;
}
}
//.grafana-target-segment-icon {
.tight-form-item-icon {
i {
width: 15px;
text-align: center;
display: inline-block;
}
}
//.grafana-target-function {
.tight-form-func {
background: @grafanaTargetFuncBackground;
> a {
color: @grafanaTargetColor;
}
> a:hover {
color: @linkColor;
}
&.show-function-controls {
padding-top: 5px;
min-width: 100px;
text-align: center;
}
}
//input[type=text].grafana-function-param-input {
input[type=text].tight-form-func-param {
background: transparent;
border: none;
margin: 0;
padding: 0;
}
//input[type=text].grafana-target-text-input {
input[type=text].tight-form-clear-input {
padding: 8px 7px;
border: none;
margin: 0px;
background: transparent;
float: left;
color: @grafanaTargetColor;
border-radius: 0;
border-right: 1px solid @grafanaTargetSegmentBorder;
}
//[type=text].grafana-target-segment-input, [type=number].grafana-target-segment-input {
[type=text].tight-form-input, [type=number].tight-form-input {
border: none;
border-right: 1px solid @grafanaTargetSegmentBorder;
margin: 0px;
border-radius: 0;
padding: 8px 4px;
&.last {
border-right: none;
}
}
//input[type=checkbox].grafana-target-option-checkbox {
input[type=checkbox].tight-form-checkbox {
margin: 0;
}
select.tight-form-input {
border: none;
border-right: 1px solid @grafanaTargetSegmentBorder;
margin: 0px;
border-radius: 0;
height: 36px;
padding: 8px 5px;
&.last {
border-right: none;
}
}
//.graphite-func-controls {
.tight-form-func-controls {
display: none;
text-align: center;
.fa-arrow-left {
float: left;
position: relative;
top: 2px;
}
.fa-arrow-right {
float: right;
position: relative;
top: 2px;
}
.fa-remove {
margin-left: 10px;
}
}
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
// Base modal // Base modal
.modal { .modal {
position: absolute; position: fixed;
z-index: @zindexModal; z-index: @zindexModal;
width: 100%; width: 100%;
background-color: @white; background-color: @white;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment