Merge remote-tracking branch 'origin/master' into pro

This commit is contained in:
Torkel Ödegaard
2014-08-11 15:30:45 +02:00
49 changed files with 417 additions and 4343 deletions
+1
View File
@@ -6,6 +6,7 @@ dist
# locally required config files
web.config
config.js
src/css/*.min.css
# Editor junk
*.sublime-workspace
+2
View File
@@ -1,6 +1,8 @@
language: node_js
node_js:
- "0.10"
git:
depth: 1
before_script:
- npm install -g grunt-cli
after_script:
+20 -2
View File
@@ -1,9 +1,27 @@
# 1.7.0 (unreleased)
# 1.8.0 (unreleased)
**New features and improvements**
- [Issue #578](https://github.com/grafana/grafana/issues/578). Dashboard: Row option to display row title even when the row is visible
**Tech**
- Upgraded from angularjs 1.1.5 to 1.3 beta 17;
- Switch from underscore to lodash
- helpers to easily unit test angularjs controllers and services
- Test coverage through coveralls
# 1.7.0 (2014-08-11)
**Fixes**
- [Issue #655](https://github.com/grafana/grafana/issues/655). General: Auto refresh not initiated / started after dashboard loading
- [Issue #652](https://github.com/grafana/grafana/issues/652). Timepicker: Entering custom date range impossible when refresh is low (now is constantly reset)
- [Issue #450](https://github.com/grafana/grafana/issues/450). Graph: Tooltip does not disappear sometimes and would get stuck
- [Issue #655](https://github.com/grafana/grafana/issues/655). General: Auto refresh not initiated / started after dashboard loading
- [Issue #657](https://github.com/grafana/grafana/issues/657). General: Fix for refresh icon in IE browsers
- [Issue #661](https://github.com/grafana/grafana/issues/661). Annotations: Elasticsearch querystring with filter template replacements was not interpolated
- [Issue #660](https://github.com/grafana/grafana/issues/660). OpenTSDB: fix opentsdb queries that returned more than one series
**Change**
- [Issue #681](https://github.com/grafana/grafana/issues/681). Dashboard: The panel error bar has been replaced with a small error indicator, this indicator does not change panel height and is a lot less intrusive. Hover over it for short details, click on it for more details.
# 1.7.0-rc1 (2014-08-05)
+1 -1
View File
@@ -1,4 +1,4 @@
[Grafana](http://grafana.org) [![Build Status](https://api.travis-ci.org/grafana/grafana.png)](https://travis-ci.org/grafana/grafana) [![Gittip](http://img.shields.io/gittip/torkelo.svg)](https://www.gittip.com/torkelo)
[Grafana](http://grafana.org) [![Build Status](https://api.travis-ci.org/grafana/grafana.svg)](https://travis-ci.org/grafana/grafana) [![Coverage Status](https://coveralls.io/repos/grafana/grafana/badge.png?branch=develop)](https://coveralls.io/r/grafana/grafana?branch=develop)
================
[Website](http://grafana.org) |
[Twitter](http://twitter.com/grafana) |
+3 -3
View File
@@ -1,4 +1,4 @@
{
"version": "1.7.0-rc1",
"url": "http://grafanarel.s3.amazonaws.com/grafana-1.7.0-rc1.tar.gz"
}
"version": "1.7.0",
"url": "http://grafanarel.s3.amazonaws.com/grafana-1.7.0"
}
+2 -1
View File
@@ -4,7 +4,7 @@
"company": "Coding Instinct AB"
},
"name": "grafana",
"version": "1.7.0-rc1",
"version": "1.7.0",
"repository": {
"type": "git",
"url": "http://github.com/torkelo/grafana.git"
@@ -26,6 +26,7 @@
"grunt-contrib-less": "~0.7.0",
"grunt-contrib-requirejs": "~0.4.1",
"grunt-contrib-uglify": "~0.2.4",
"grunt-contrib-watch": "^0.6.1",
"grunt-filerev": "^0.2.1",
"grunt-git-describe": "~2.3.2",
"grunt-karma": "~0.8.3",
+1 -1
View File
@@ -51,13 +51,13 @@ function (angular, $, _, appLevelRequire, config) {
app.config(function ($routeProvider, $controllerProvider, $compileProvider, $filterProvider, $provide) {
$routeProvider.otherwise({ redirectTo: config.default_route });
// this is how the internet told me to dynamically add modules :/
register_fns.controller = $controllerProvider.register;
register_fns.directive = $compileProvider.directive;
register_fns.factory = $provide.factory;
register_fns.service = $provide.service;
register_fns.filter = $filterProvider.register;
});
var apps_deps = [
+1
View File
@@ -13,4 +13,5 @@ define([
'./playlistCtrl',
'./inspectCtrl',
'./opentsdbTargetCtrl',
'./console-ctrl',
], function () {});
+121
View File
@@ -0,0 +1,121 @@
define([
'angular',
'lodash',
'moment',
],
function (angular, _, moment) {
'use strict';
var module = angular.module('grafana.controllers');
var consoleEnabled = window.localStorage && window.localStorage.grafanaConsole === 'true';
if (!consoleEnabled) {
return;
}
var events = [];
var oldLog = console.log;
console.log = function (message) {
try {
if (_.isObject(message)) {
message = angular.toJson(message);
if (message.length > 50) {
message = message.substring(0, 50);
}
}
events.push(new ConsoleEvent('log', message, {}));
oldLog.apply(console, arguments);
} catch (e) { }
};
function ConsoleEvent(type, title, data) {
this.type = type;
this.title = title;
this.data = data;
this.time = moment().format('hh:mm:ss');
if (data.config) {
this.method = data.config.method;
this.elapsed = (new Date().getTime() - data.config.$grafana_timestamp) + ' ms';
if (data.config.params && data.config.params.q) {
this.field2 = data.config.params.q;
}
if (_.isString(data.config.data)) {
this.field2 = data.config.data;
}
if (data.status !== 200) {
this.error = true;
this.field3 = data.data;
}
if (_.isArray(data.data)) {
this.extractTimeseriesInfo(data.data);
}
}
}
ConsoleEvent.prototype.extractTimeseriesInfo = function(series) {
if (series.length === 0) {
return;
}
var points = 0;
var ok = false;
if (series[0].datapoints) {
points = _.reduce(series, function(memo, val) {
return memo + val.datapoints.length;
}, 0);
ok = true;
}
if (series[0].columns) {
points = _.reduce(series, function(memo, val) {
return memo + val.points.length;
}, 0);
ok = true;
}
if (ok) {
this.field1 = '(' + series.length + ' series';
this.field1 += ', ' + points + ' points)';
}
};
module.config(function($provide, $httpProvider) {
$provide.factory('mupp', function($q) {
return {
'request': function(config) {
if (config.inspect) {
config.$grafana_timestamp = new Date().getTime();
}
return config;
},
'response': function(response) {
if (response.config.inspect) {
events.push(new ConsoleEvent(response.config.inspect.type, response.config.url, response));
}
return response;
},
'requestError': function(rejection) {
console.log('requestError', rejection);
return $q.reject(rejection);
},
'responseError': function (rejection) {
var inspect = rejection.config.inspect || { type: 'error' };
events.push(new ConsoleEvent(inspect.type, rejection.config.url, rejection));
return $q.reject(rejection);
}
};
});
$httpProvider.interceptors.push('mupp');
});
module.controller('ConsoleCtrl', function($scope) {
$scope.events = events;
});
});
+7
View File
@@ -18,6 +18,13 @@ function (angular, config, _) {
$scope.grafana = {
style: 'dark'
};
$scope.consoleEnabled = (window.localStorage && window.localStorage.grafanaConsole === 'true');
};
$scope.toggleConsole = function() {
$scope.consoleEnabled = !$scope.consoleEnabled;
window.localStorage.grafanaConsole = $scope.consoleEnabled ? 'true' : 'false';
};
$rootScope.onAppEvent = function(name, callback) {
+14 -3
View File
@@ -1,7 +1,8 @@
define([
'angular'
'angular',
'lodash'
],
function (angular) {
function (angular, _) {
'use strict';
var module = angular.module('grafana.controllers');
@@ -28,6 +29,16 @@ function (angular) {
return;
}
if (_.isString(model.error.data)) {
$scope.response = model.error.data;
}
if (model.error.config && model.error.config.params) {
$scope.request_parameters = _.map(model.error.config.params, function(value, key) {
return { key: key, value: value};
});
}
if (model.error.stack) {
$scope.editor.index = 2;
$scope.stack_trace = model.error.stack;
@@ -72,4 +83,4 @@ function (angular) {
};
});
});
});
+2 -5
View File
@@ -33,11 +33,8 @@ function (angular, app, _) {
};
$scope.rowSpan = function(row) {
var panels = _.filter(row.panels, function(p) {
return $scope.isPanel(p);
});
return _.reduce(_.pluck(panels,'span'), function(p,v) {
return p+v;
return _.reduce(row.panels, function(p,v) {
return p + v.span;
},0);
};
+5 -9
View File
@@ -15,16 +15,12 @@ function (angular, $) {
var panelHeader =
'<div class="panel-header">'+
'<div class="row-fluid">' +
'<div class="span12 alert-error panel-error small" ng-show="panel.error">' +
'<a class="close" ng-click="panel.error=false">&times;</a>' +
'<span><i class="icon-exclamation-sign"></i> <strong>Oops!</strong> {{panel.error}} </span>' +
'<span class="pointer panel-error-inspector-link" config-modal="app/partials/inspector.html">View details</span>' +
'</div>' +
'</div>\n' +
'<div class="row-fluid panel-extra">' +
'<div class="row-fluid panel-extra">' +
'<div class="panel-extra-container">' +
'<span class="alert-error panel-error small pointer"' +
'config-modal="app/partials/inspector.html" ng-show="panel.error" data-placement="right" bs-tooltip="panel.error">' +
'<i class="icon-exclamation-sign"></i><span class="panel-error-arrow"></span>' +
'</span>' +
'<span class="panel-loading" ng-show="panelMeta.loading == true">' +
'<i class="icon-spinner icon-spin icon-large"></i>' +
+5 -10
View File
@@ -13,20 +13,15 @@
{{series.alias}}
</a>
</div>
<div class="graph-legend-value small" ng-show="panel.legend.values && panel.legend.current">
Current: {{series.current}}
<div class="graph-legend-value current small" ng-show="panel.legend.values && panel.legend.current" ng-bind="series.current">
</div>
<div class="graph-legend-value small" ng-show="panel.legend.values && panel.legend.min">
Min: {{series.min}}
<div class="graph-legend-value min small" ng-show="panel.legend.values && panel.legend.min" ng-bind="series.min">
</div>
<div class="graph-legend-value small" ng-show="panel.legend.values && panel.legend.max">
Max: {{series.max}}
<div class="graph-legend-value max small" ng-show="panel.legend.values && panel.legend.max" ng-bind="series.max">
</div>
<div class="graph-legend-value small" ng-show="panel.legend.values && panel.legend.total">
Total: {{series.total}}
<div class="graph-legend-value total small" ng-show="panel.legend.values && panel.legend.total" ng-bind="series.total">
</div>
<div class="graph-legend-value small" ng-show="panel.legend.values && panel.legend.avg">
Avg: {{series.avg}}
<div class="graph-legend-value avg small" ng-show="panel.legend.values && panel.legend.avg" ng-bind="series.avg">
</div>
</div>
+6 -4
View File
@@ -82,11 +82,13 @@ function (angular, app, _, require) {
$scope.updateContent = function(html) {
try {
$scope.content = $sce.trustAsHtml(filterSrv.applyTemplateToTarget(html));
if(!$scope.$$phase) {
$scope.$apply();
}
} catch(e) {
console.log('Text panel error: ', e);
$scope.content = $sce.trustAsHtml(html);
}
if(!$scope.$$phase) {
$scope.$apply();
}
};
+1 -1
View File
@@ -52,7 +52,7 @@
</li>
<li ng-show="!dashboard.refresh" class="grafana-menu-refresh">
<a class="icon-refresh" ng-click="dashboard.emit_refresh()"></a>
<a ng-click="dashboard.emit_refresh()"><i class="icon-refresh"></i></a>
</li>
</ul>
+19
View File
@@ -0,0 +1,19 @@
<div class="grafana-console" ng-controller="ConsoleCtrl">
<div class="grafana-console-header">
<span class="grafana-console-title large"><i class="icon-terminal"></i></span>
</div>
<div class="grafana-console-body">
<div class="grafana-console-item" ng-repeat="item in events" ng-class="{'grafana-console-error': item.error}">
<span class="grafana-console-time gfc-col" ng-bind="item.time"></span>
<span class="grafana-console-type gfc-col">
<span class="label label-info" ng-bind="item.type"></span>
</span>
<span class="gfc-col grafana-console-method" ng-bind="item.method"></span>
<span class="gfc-col grafana-console-title" ng-bind="item.title"></span>
<span class="gfc-col grafana-console-elapsed" ng-bind="item.elapsed"></span>
<span class="gfc-col grafana-console-field1" ng-bind="item.field1"></span>
<span class="gfc-col grafana-console-field2" ng-bind="item.field2"></span>
<span class="gfc-col grafana-console-field3" ng-bind="item.field3"></span>
</div>
</div>
</div>
+14 -7
View File
@@ -31,13 +31,15 @@
<div class="row-control">
<div class="row-control-inner" style="padding:0px;margin:0px;position:relative;">
<div class="row-close" ng-show="row.collapse" data-placement="bottom" >
<span class="row-button bgWarning" config-modal="app/partials/roweditor.html" class="pointer">
<i bs-tooltip="'Configure row'" data-placement="right" ng-show="row.editable" class="icon-cog pointer"></i>
</span>
<span class="row-button bgPrimary" ng-click="toggle_row(row)">
<i bs-tooltip="'Expand row'" data-placement="right" class="icon-caret-left pointer" ></i>
</span>
<span class="row-button row-text" ng-click="toggle_row(row)">{{row.title || 'Row '+$index}}</span>
<div class="row-close-buttons">
<span class="row-button bgWarning" config-modal="app/partials/roweditor.html" class="pointer">
<i bs-tooltip="'Configure row'" data-placement="right" ng-show="row.editable" class="icon-cog pointer"></i>
</span>
<span class="row-button bgPrimary" ng-click="toggle_row(row)">
<i bs-tooltip="'Expand row'" data-placement="right" class="icon-caret-left pointer" ></i>
</span>
</div>
<span class="row-text pointer" ng-click="toggle_row(row)" ng-bind="row.title"></span>
</div>
<div class="row-open" ng-show="!row.collapse">
<div class='row-tab bgPrimary' ng-click="toggle_row(row)">
@@ -92,6 +94,8 @@
</div>
<div style="padding-top:0px" ng-if="!row.collapse">
<div class="row-text pointer" ng-click="toggle_row(row)" ng-if="row.showTitle" ng-bind="row.title">
</div>
<!-- Panels -->
<div ng-repeat="(name, panel) in row.panels|filter:isPanel" ng-hide="panel.hide" class="panel nospace" ng-style="{'width':(panel.span/1.2)*10+'%'}" data-drop="true" ng-model="row.panels" data-jqyoui-options jqyoui-droppable="{index:$index,mutate:false,onDrop:'panelMoveDrop',onOver:'panelMoveOver(true)',onOut:'panelMoveOut'}" ng-class="{'dragInProgress':dashboard.$$panelDragging}">
@@ -121,4 +125,7 @@
</div>
</div>
<div ng-include="'app/partials/console.html'" ng-if="consoleEnabled">
</div>
</div>
+2 -1
View File
@@ -25,7 +25,7 @@
<label class="small">Hide controls (CTRL+H)</label>
<input type="checkbox" ng-model="dashboard.hideControls" ng-checked="dashboard.hideControls">
</div>
</div>
</div>
</div>
<div class="editor-row">
<div class="section">
@@ -98,6 +98,7 @@
<span class="editor-option small">
Grafana version: {{grafanaVersion}}
</span>
<span> | <a ng-click="toggleConsole()" ng-show="!consoleEnabled">enable console</a> <a ng-click="toggleConsole()" ng-show="consoleEnabled">disable console</a></span>
<div class="small" grafana-version-check>
</div>
</div>
+2 -1
View File
@@ -41,6 +41,7 @@
</div>
<div ng-if="editor.index == 1">
<h5 ng-if="response" ng-bind="response"></h5>
<div ng-if="response_html">
<div iframe-content="response_html"></div>
@@ -65,4 +66,4 @@
</div>
<div class="modal-footer">
<button type="button" class="btn btn-info" ng-click="dismiss()">Close</button>
</div>
</div>
+2 -2
View File
@@ -17,9 +17,9 @@
<label class="small"> Editable </label><input type="checkbox" ng-model="row.editable" ng-checked="row.editable" />
</div>
<div class="editor-option">
<label class="small"> Collapsable </label><input type="checkbox" ng-model="row.collapsable" ng-checked="row.collapsable" />
<label class="small"> Show title </label><input type="checkbox" ng-model="row.showTitle" ng-checked="row.showTitle" />
</div>
</div>
</div>
<div class="row-fluid" ng-if="editor.index == 1">
<div class="span12">
<h4>Panels</h4>
+3 -3
View File
@@ -7,7 +7,7 @@ function (angular, _) {
var module = angular.module('grafana.services');
module.service('alertSrv', function($timeout) {
module.service('alertSrv', function($timeout, $sce) {
var self = this;
// List of all alert objects
@@ -17,7 +17,7 @@ function (angular, _) {
var
_a = {
title: title || '',
text: text || '',
text: $sce.trustAsHtml(text || ''),
severity: severity || 'info',
},
_ca = angular.toJson(_a),
@@ -46,4 +46,4 @@ function (angular, _) {
self.list = [];
};
});
});
});
@@ -73,8 +73,9 @@ function (angular, _, $, config, kbn, moment) {
to: rangeUnparsed.to,
};
var queryInterpolated = filterSrv.applyTemplateToTarget(queryString);
var filter = { "bool": { "must": [{ "range": range }] } };
var query = { "bool": { "should": [{ "query_string": { "query": queryString } }] } };
var query = { "bool": { "should": [{ "query_string": { "query": queryInterpolated } }] } };
var data = { "query" : { "filtered": { "query" : query, "filter": filter } }, "size": 100 };
return this._request('POST', '/_search', annotation.index, data).then(function(results) {
@@ -205,6 +205,7 @@ function (angular, _, $, config, kbn, moment) {
}
options.url = this.url + options.url;
options.inspect = { type: 'graphite' };
return $http(options);
};
@@ -132,8 +132,8 @@ function (angular, _, kbn, InfluxSeries) {
return new InfluxSeries({ seriesList: results, annotation: annotation }).getAnnotations();
});
};
InfluxDatasource.prototype.listColumns = function(seriesName) {
return this._seriesQuery('select * from /' + seriesName + '/ limit 1').then(function(data) {
if (!data) {
return [];
@@ -184,6 +184,7 @@ function (angular, _, kbn, InfluxSeries) {
function retry(deferred, callback, delay) {
return callback().then(undefined, function(reason) {
if (reason.status !== 0 || reason.status >= 300) {
reason.message = 'InfluxDB Error: <br/>' + reason.data;
deferred.reject(reason);
}
else {
@@ -223,7 +224,8 @@ function (angular, _, kbn, InfluxSeries) {
method: method,
url: currentUrl + url,
params: params,
data: data
data: data,
inspect: { type: 'influxdb' },
};
return $http(options).success(function (data) {
@@ -106,7 +106,7 @@ function (angular, _, kbn) {
}
function createMetricLabel(metric, tagData, options) {
if (options.alias) {
if (!_.isUndefined(options) && options.alias) {
return options.alias;
}
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
-4223
View File
File diff suppressed because one or more lines are too long
-21
View File
@@ -12,22 +12,6 @@ body {
//url('../img/light.png') repeat right top;
}
h1 {
font-size: 50px;
}
h2, h3 {
font-size: 26px;
}
h4 {
font-size: 14px;
}
h5, h6 {
font-size: 11px;
}
blockquote {
padding: 10px 15px;
@@ -527,11 +511,6 @@ a:hover {
.box-shadow(none);
}
[class^="icon-"], [class*=" icon-"] {
margin: 0 2px;
vertical-align: -2px;
}
a.thumbnail {
background-color: @grayLight;
+71
View File
@@ -0,0 +1,71 @@
.grafana-console {
position: fixed;
width: 100%;
bottom: 0px;
height: 300px;
background: @grafanaPanelBackground;
border-top: 1px solid @fullEditBorder;
}
.grafana-console-header {
background: @fullEditTabsBackground;
border-top: @fullEditTabsBorder;
padding: 2px 5px;
}
.grafana-console-item {
.icon-caret-right {
font-size: 14px;
color: @blue;
}
margin: 2px 0;
display: table-row;
}
.grafana-console-body {
overflow-y: auto;
display: table;
width: 100%;
}
.gfc-col {
display: table-cell;
padding: 2px 4px;
white-space: nowrap;
overflow: hidden;
vertical-align: middle;
}
.grafana-console-method {
text-align: center;
}
.grafana-console-error {
.grafana-console-method {
color: red;
}
}
.grafana-console-field2 {
width: 90%;
}
.grafana-console-time:before {
content: '(';
color: rgb(106, 253, 81);
}
.grafana-console-time:after {
content: ')';
color: rgb(106, 253, 81);
}
.grafana-console-time {
color: rgb(162, 196, 253);
}
.grafana-console-elapsed {
text-align: right;
color: rgb(162, 196, 253);
}
+9
View File
@@ -1,5 +1,6 @@
@import "submenu.less";
@import "graph.less";
@import "console.less";
@import "bootstrap-tagsinput.less";
.hide-controls {
@@ -494,3 +495,11 @@ select.grafana-target-segment-input {
border-radius: 5px;
z-index: 9999;
}
.tooltip.in {
.opacity(100);
}
.tooltip-inner {
max-width: 400px;
}
+15
View File
@@ -25,6 +25,21 @@
.graph-legend-value {
float: left;
white-space: nowrap;
&.current:before {
content: "Current: "
}
&.max:before {
content: "Max: "
}
&.min:before {
content: "Min: "
}
&.total:before {
content: "Total: "
}
&.avg:before {
content: "Avg: "
}
}
.graph-legend-series {
+28 -11
View File
@@ -112,15 +112,27 @@ code, pre {
.panel-error {
color: @white;
padding: 5px 10px 0px 10px;
//padding: 5px 10px 0px 10px;
position: absolute;
left: 5px;
padding: 0px 17px 6px 5px;
top: 0;
i {
position: relative;
top: -2px;
}
}
.panel-error-inspector-link {
float: right;
margin-right: 10px;
.panel-error-arrow {
width: 0;
height: 0;
position: absolute;
border-left: 31px solid transparent;
border-right: 30px solid transparent;
border-bottom: 27px solid @grafanaPanelBackground;
left: 0;
bottom: 0;
}
div.editor-row {
vertical-align: top;
}
@@ -223,9 +235,9 @@ form input.ng-invalid {
.row-button {
width: 30px;
text-align: center;
float: left;
cursor: pointer;
line-height: 31px;
}
.row-text {
@@ -233,15 +245,20 @@ form input.ng-invalid {
text-transform: uppercase;
font-weight: bold;
font-size: 0.9em;
margin: 0px 10px;
text-align: center;
line-height: 31px;
}
.row-close {
padding: 0px;
margin: 0px;
min-height: 30px !important;
line-height: 30px;
background: @grafanaPanelBackground;
text-align: center;
}
.row-close-buttons {
position: absolute;
left: 0;
}
.row-open {
@@ -614,4 +631,4 @@ div.flot-text {
code, pre {
background-color: @grafanaPanelBackground;
color: @textColor;
}
}
+1 -1
View File
@@ -19,7 +19,7 @@
@blue: #33B5E5;
@blueDark: #0099CC;
@green: #669900;
@red: #CC0000;
@red: #CC3900;
@yellow: #ECBB13;
@orange: #FF8800;
@pink: #FF4444;
+2 -4
View File
@@ -7,7 +7,7 @@
<meta name="viewport" content="width=device-width">
<title>Grafana</title>
<link rel="stylesheet" href="css/default.min.css" title="Dark">
<link rel="stylesheet" href="css/grafana.dark.min.css" title="Dark">
<!-- build:js app/app.js -->
<script src="vendor/require/require.js"></script>
@@ -20,9 +20,7 @@
<body ng-cloak ng-controller="GrafanaCtrl">
<link rel="stylesheet" href="css/bootstrap.light.min.css" ng-if="grafana.style === 'light'">
<link rel="stylesheet" href="css/bootstrap-responsive.min.css">
<link rel="stylesheet" href="css/font-awesome.min.css">
<link rel="stylesheet" href="css/grafana.light.min.css" ng-if="grafana.style === 'light'">
<div ng-repeat='alert in dashAlerts.list' class="alert-{{alert.severity}} dashboard-notice" ng-show="$last">
<button type="button" class="close" ng-click="dashAlerts.clear(alert)" style="padding-right:50px">&times;</button>
+3 -2
View File
@@ -797,7 +797,8 @@ angular.module('$strap.directives').directive('bsTooltip', [
title: function () {
return angular.isFunction(value) ? value.apply(null, arguments) : value;
},
html: true
html: true,
container: 'body', // Grafana change
});
var tooltip = element.data('tooltip');
tooltip.show = function () {
@@ -875,4 +876,4 @@ angular.module('$strap.directives').directive('bsTypeahead', [
}
};
}
]);
]);
+2 -1
View File
@@ -6,7 +6,8 @@ module.exports = function(grunt) {
'jshint:tests',
'clean:on_start',
'less:src',
'concat:css',
'concat:cssDark',
'concat:cssLight',
'copy:everything_but_less_to_temp',
'htmlmin:build',
'ngtemplates',
+2 -1
View File
@@ -1,5 +1,6 @@
// Lint and build CSS
module.exports = function(grunt) {
grunt.registerTask('default', ['jscs', 'jshint', 'less:src', 'concat:css']);
grunt.registerTask('css', ['less:src', 'concat:cssDark', 'concat:cssLight']);
grunt.registerTask('default', ['jscs', 'jshint', 'css']);
grunt.registerTask('test', ['default', 'karma:test']);
};
+22 -7
View File
@@ -1,15 +1,30 @@
module.exports = function(config) {
return {
css: {
cssDark: {
src: [
'<%= srcDir %>/css/normalize.min.css',
'<%= srcDir %>/css/timepicker.css',
'<%= srcDir %>/css/spectrum.css',
'<%= srcDir %>/css/animate.min.css',
'<%= srcDir %>/css/bootstrap.dark.min.css'
'<%= srcDir %>/vendor/css/normalize.min.css',
'<%= srcDir %>/vendor/css/timepicker.css',
'<%= srcDir %>/vendor/css/spectrum.css',
'<%= srcDir %>/vendor/css/animate.min.css',
'<%= srcDir %>/css/bootstrap.dark.min.css',
'<%= srcDir %>/css/bootstrap-responsive.min.css',
'<%= srcDir %>/vendor/css/font-awesome.min.css'
],
dest: '<%= srcDir %>/css/default.min.css'
dest: '<%= srcDir %>/css/grafana.dark.min.css'
},
cssLight: {
src: [
'<%= srcDir %>/vendor/css/normalize.min.css',
'<%= srcDir %>/vendor/css/timepicker.css',
'<%= srcDir %>/vendor/css/spectrum.css',
'<%= srcDir %>/vendor/css/animate.min.css',
'<%= srcDir %>/css/bootstrap.light.min.css',
'<%= srcDir %>/css/bootstrap-responsive.min.css',
'<%= srcDir %>/vendor/css/font-awesome.min.css'
],
dest: '<%= srcDir %>/css/grafana.light.min.css'
},
js: {
src: [
'<%= destDir %>/vendor/require/require.js',
+6 -2
View File
@@ -5,8 +5,12 @@ module.exports = function(config) {
algorithm: 'md5',
length: 8,
},
css: {
src: '<%= destDir %>/css/default.min.css',
cssDark: {
src: '<%= destDir %>/css/grafana.dark.min.css',
dest: '<%= destDir %>/css'
},
cssLight: {
src: '<%= destDir %>/css/grafana.light.min.css',
dest: '<%= destDir %>/css'
},
js: {
+1 -1
View File
@@ -51,7 +51,7 @@ module.exports = function(config,grunt) {
'modernizr',
'timepicker',
'datepicker',
'underscore',
'lodash',
'filters/all',
'jquery.flot',
'services/all',
+11
View File
@@ -0,0 +1,11 @@
module.exports = function(config) {
return {
css: {
files: [ '<%= srcDir %>/css/**/*.less' ],
tasks: ['css'],
options: {
spawn: false
}
}
};
};