Commit 4b5eadf7 by Torkel Ödegaard

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

parents 2423f470 62b58d8b
# 1.9.0 (unreleased)
**Fixes**
- [Issue #1087](https://github.com/grafana/grafana/issues/1087). Panel: Fixed IE9 crash due to angular drag drop
- [Issue #1093](https://github.com/grafana/grafana/issues/1093). SingleStatPanel: Fixed position for drilldown link tooltip when dashboard requires scrolling
- [Issue #1095](https://github.com/grafana/grafana/issues/1095). DrilldownLink: template variables in params property was not interpolated
# 1.9.0-rc1 (2014-11-17)
**UI Improvements*
- [Issue #770](https://github.com/grafana/grafana/issues/770). UI: Panel dropdown menu replaced with a new panel menu
......@@ -14,6 +21,7 @@
- [Issue #951](https://github.com/grafana/grafana/issues/951). SingleStat: New singlestat panel
**Misc**
- [Issue #864](https://github.com/grafana/grafana/issues/846). Panel: Share panel feature, get a link to panel with the current time range
- [Issue #938](https://github.com/grafana/grafana/issues/938). Panel: Plugin panels now reside outside of app/panels directory
- [Issue #952](https://github.com/grafana/grafana/issues/952). Help: Shortcut "?" to open help modal with list of all shortcuts
- [Issue #991](https://github.com/grafana/grafana/issues/991). ScriptedDashboard: datasource services are now available in scripted dashboards, you can query datasource for metric keys, generate dashboards, and even save them in a scripted dashboard (see scripted_gen_and_save.js for example)
......
{
"version": "1.8.1",
"url": "http://grafanarel.s3.amazonaws.com/grafana-1.8.1.tar.gz"
"version": "1.9.0-rc1",
"url": "http://grafanarel.s3.amazonaws.com/grafana-1.9.0-rc1.tar.gz"
}
......@@ -4,7 +4,7 @@
"company": "Coding Instinct AB"
},
"name": "grafana",
"version": "1.9.0",
"version": "1.9.0-rc1",
"repository": {
"type": "git",
"url": "http://github.com/torkelo/grafana.git"
......
......@@ -61,7 +61,7 @@ function (angular, $, _, appLevelRequire, config) {
var apps_deps = [
'ngRoute',
'$strap.directives',
'ngDragDrop',
'ang-drag-drop',
'grafana',
'pasvaz.bindonce'
];
......
......@@ -12,12 +12,12 @@ function () {
this.extendedMenu = [];
if (options.fullscreen) {
this.addMenuItem('view', 'icon-eye-open', 'toggleFullscreen(false)');
this.addMenuItem('view', 'icon-eye-open', 'toggleFullscreen(false); dismiss();');
}
this.addMenuItem('edit', 'icon-cog', 'editPanel()');
this.addMenuItem('edit', 'icon-cog', 'editPanel(); dismiss();');
this.addMenuItem('duplicate', 'icon-copy', 'duplicatePanel()');
this.addMenuItem('share', 'icon-share', 'sharePanel()');
this.addMenuItem('share', 'icon-share', 'sharePanel(); dismiss();');
this.addEditorTab('General', 'app/partials/panelgeneral.html');
......@@ -25,7 +25,7 @@ function () {
this.addEditorTab('Metrics', 'app/partials/metrics.html');
}
this.addExtendedMenuItem('Panel JSON', '', 'editPanelJson()');
this.addExtendedMenuItem('Panel JSON', '', 'editPanelJson(); dismiss();');
}
PanelMeta.prototype.addMenuItem = function(text, icon, click) {
......
......@@ -107,7 +107,7 @@ function (angular, app, _) {
var _as = 12 - $scope.dashboard.rowSpan($scope.row);
$scope.panel = {
title: 'no title [click here]',
title: 'no title (click here)',
error : false,
span : _as < defaultSpan && _as > 0 ? _as : defaultSpan,
editable: true,
......
......@@ -22,9 +22,6 @@ var dashboard, timspan;
// All url parameters are available via the ARGS object
var ARGS;
// Set a default timespan if one isn't specified
timspan = '1d';
// Intialize a skeleton with nothing but a rows array and service object
dashboard = {
rows : [],
......@@ -32,8 +29,12 @@ dashboard = {
// Set a title
dashboard.title = 'Scripted dash';
// set default time
// time can be overriden in the url using from/to parameteres, but this is
// handled automatically in grafana core during dashboard initialization
dashboard.time = {
from: "now-" + (ARGS.from || timspan),
from: 'now-6h',
to: "now"
};
......
......@@ -25,7 +25,7 @@ return function(callback) {
var dashboard, timspan;
// Set a default timespan if one isn't specified
timspan = '1d';
timspan = ARGS.from || 'now-1d';
// Intialize a skeleton with nothing but a rows array and service object
dashboard = {
......@@ -36,7 +36,7 @@ return function(callback) {
// Set a title
dashboard.title = 'Scripted dash';
dashboard.time = {
from: "now-" + (ARGS.from || timspan),
from: timspan,
to: "now"
};
......
......@@ -23,7 +23,7 @@ var dashboard, timspan;
var ARGS;
// Set a default timespan if one isn't specified
timspan = '1d';
timspan = ARGS.from || 'now-1d';
// Intialize a skeleton with nothing but a rows array and service object
dashboard = {
......@@ -33,7 +33,7 @@ dashboard = {
// Set a title
dashboard.title = 'Scripted dash';
dashboard.time = {
from: "now-" + (ARGS.from || timspan),
from: timspan,
to: "now"
};
dashboard.templating = {
......
......@@ -206,6 +206,7 @@ function (angular, _, $) {
if ($target.hasClass('icon-arrow-left')) {
$scope.$apply(function() {
_.move($scope.functions, $scope.$index, $scope.$index - 1);
$scope.targetChanged();
});
return;
}
......@@ -213,6 +214,7 @@ function (angular, _, $) {
if ($target.hasClass('icon-arrow-right')) {
$scope.$apply(function() {
_.move($scope.functions, $scope.$index, $scope.$index + 1);
$scope.targetChanged();
});
return;
}
......
......@@ -72,7 +72,7 @@ function (angular, $, _) {
$link.toggleClass('has-panel-links', showIcon);
});
function dismiss(time) {
function dismiss(time, force) {
clearTimeout(timeout);
timeout = null;
......@@ -82,9 +82,11 @@ function (angular, $, _) {
}
// if hovering or draging pospone close
if ($menu.is(':hover') || $scope.dashboard.$$panelDragging) {
dismiss(2500);
return;
if (force !== true) {
if ($menu.is(':hover') || $scope.dashboard.$$panelDragging) {
dismiss(2200);
return;
}
}
if (menuScope) {
......@@ -97,7 +99,12 @@ function (angular, $, _) {
}
}
var showMenu = function() {
var showMenu = function(e) {
// if menu item is clicked and menu was just removed from dom ignore this event
if (!$.contains(document, e.target)) {
return;
}
if ($menu) {
dismiss();
return;
......@@ -124,6 +131,9 @@ function (angular, $, _) {
menuScope = $scope.$new();
menuScope.extendedMenu = getExtendedMenu($scope);
menuScope.dismiss = function() {
dismiss(null, true);
};
$('.panel-menu').remove();
elem.append($menu);
......@@ -134,7 +144,7 @@ function (angular, $, _) {
$(".panel-container").removeClass('panel-highlight');
$panelContainer.toggleClass('panel-highlight');
dismiss(2500);
dismiss(2200);
};
if ($scope.panelMeta.titlePos && $scope.panel.title) {
......
......@@ -29,7 +29,7 @@ function (angular, kbn) {
info.href += '&to=' + range.to;
if (link.params) {
info.href += "&" + link.params;
info.href += "&" + templateSrv.replace(link.params);
}
return info;
......
......@@ -72,10 +72,11 @@ function (angular, $, kbn, moment, _, GraphTooltip) {
height = parseInt(height.replace('px', ''), 10);
}
height -= 5; // padding
height -= scope.panel.title ? 24 : 9; // subtract panel title bar
if (scope.panel.legend.show && !scope.panel.legend.rightSide) {
height = height - 21; // subtract one line legend
height = height - 26; // subtract one line legend
}
elem.css('height', height + 'px');
......@@ -114,7 +115,12 @@ function (angular, $, kbn, moment, _, GraphTooltip) {
var series = data[i];
var axis = yaxis[series.yaxis - 1];
var formater = kbn.valueFormats[scope.panel.y_formats[series.yaxis - 1]];
series.updateLegendValues(formater, axis.tickDecimals, axis.scaledDecimals + 2);
// legend and tooltip gets one more decimal precision
// than graph legend ticks
var tickDecimals = (axis.tickDecimals || -1) + 1;
series.updateLegendValues(formater, tickDecimals, axis.scaledDecimals + 2);
if(!scope.$$phase) { scope.$digest(); }
}
}
......
......@@ -38,18 +38,26 @@ function ($) {
};
this.getMultiSeriesPlotHoverInfo = function(seriesList, pos) {
var value, i, series, hoverIndex;
var value, i, series, hoverIndex, seriesTmp;
var results = [];
var pointCount = seriesList[0].data.length;
for (i = 1; i < seriesList.length; i++) {
if (seriesList[i].data.length !== pointCount) {
var pointCount;
for (i = 0; i < seriesList.length; i++) {
seriesTmp = seriesList[i];
if (!seriesTmp.data.length) { continue; }
if (!pointCount) {
series = seriesTmp;
pointCount = series.data.length;
continue;
}
if (seriesTmp.data.length !== pointCount) {
results.pointCountMismatch = true;
return results;
}
}
series = seriesList[0];
hoverIndex = this.findHoverIndexFromData(pos.x, series);
var lasthoverIndex = 0;
if(!scope.panel.steppedLine) {
......@@ -62,6 +70,7 @@ function ($) {
for (i = 0; i < seriesList.length; i++) {
series = seriesList[i];
if (!series.data.length) { continue; }
if (scope.panel.stack) {
if (scope.panel.tooltip.value_type === 'individual') {
......
......@@ -4,7 +4,9 @@
<div class="graph-canvas-wrapper">
<div ng-if="datapointsWarning" class="datapoints-warning">
<span class="small" ng-show="!datapointsCount">No datapoints <tip>Can be caused by timezone mismatch between browser and graphite server</tip></span>
<span class="small" ng-show="!datapointsCount">
No datapoints <tip>No datapoints returned from metric query</tip>
</span>
<span class="small" ng-show="datapointsOutside">Datapoints outside time range <tip>Can be caused by timezone mismatch between browser and graphite server</tip></span>
</div>
......
......@@ -42,12 +42,12 @@
<h5>Coloring</h5>
<editor-opt-bool text="Background" model="panel.colorBackground" change="setColoring({background: true})"></editor-opt-bool>
<editor-opt-bool text="Value" model="panel.colorValue" change="setColoring({value: true})"></editor-opt-bool>
<div class="editor-option">
<div class="editor-option" ng-show="panel.colorBackground || panel.colorValue">
<label class="small">Thresholds<tip>Comma seperated values</tip></label>
<input type="text" class="input-large" ng-model="panel.thresholds" ng-blur="render()" placeholder="0,50,80"></input>
</div>
<div class="editor-option">
<label class="small">Color</label>
<div class="editor-option" ng-show="panel.colorBackground || panel.colorValue">
<label class="small">Colors</label>
<spectrum-picker ng-model="panel.colors[0]" ng-change="render()" ></spectrum-picker>
<spectrum-picker ng-model="panel.colors[1]" ng-change="render()" ></spectrum-picker>
<spectrum-picker ng-model="panel.colors[2]" ng-change="render()" ></spectrum-picker>
......
......@@ -125,7 +125,7 @@ function (angular, app, _, TimeSeries, kbn, PanelMeta) {
$scope.getDecimalsForValue = function(value) {
var opts = {};
if (value === 0) {
if (value === 0 || value === 1) {
return { decimals: 0, scaledDecimals: 0 };
}
......
......@@ -29,6 +29,7 @@ function (angular, app, _, $) {
height = parseInt(height.replace('px', ''), 10);
}
height -= 5; // padding
height -= panel.title ? 24 : 9; // subtract panel title bar
elem.css('height', height + 'px');
......@@ -195,7 +196,7 @@ function (angular, app, _, $) {
drilldownTooltip.text('click to go to: ' + panel.links[0].title);
drilldownTooltip.place_tt(e.clientX+20, e.clientY-15);
drilldownTooltip.place_tt(e.pageX+20, e.pageY-15);
});
}
};
......
......@@ -88,7 +88,7 @@ function (_) {
_.each(series.points, function (point) {
var data = {
annotation: self.annotation,
time: point[timeCol] * 1000,
time: point[timeCol],
title: point[titleCol],
tags: point[tagsCol],
text: point[textCol]
......
......@@ -575,3 +575,12 @@ a:hover {
// MEDIA QUERIES
// -----------------------------------------------------
.caret {
color: @textColor
}
.dropdown-submenu > a:after {
border-left-color: @textColor;
}
......@@ -111,28 +111,6 @@
font-size: 12px;
}
.panel-fullscreen {
z-index: 100;
display: block;
position: fixed;
left: 0px;
right: 0px;
top: 51px;
height: 100%;
padding: 0 10px;
background: @grafanaPanelBackground;
overflow-y: scroll;
height: 100%;
.panel-content {
padding-bottom: 130px;
}
.dropdown-menu {
margin-bottom: 70px;
}
}
.dashboard-fullscreen {
.main-view-container {
overflow: hidden;
......@@ -462,8 +440,6 @@ select.grafana-target-segment-input {
line-height: 14px;
}
.grafana-tooltip hr {
padding: 2px;
color: #c8c8c8;
......
......@@ -10,6 +10,11 @@
background: @grafanaPanelBackground;
margin: 5px;
position: relative;
&:hover {
.panel-actions {
display: block;
}
}
}
.panel-content {
......@@ -27,6 +32,8 @@
font-weight: bold;
position: relative;
cursor: context-menu;
width: 100%;
display: block;
&.has-panel-links {
.panel-title-text:after {
......@@ -72,6 +79,32 @@
bottom: 0;
}
.panel-fullscreen {
z-index: 100;
display: block;
position: fixed;
left: 0px;
right: 0px;
top: 51px;
height: 100%;
padding: 0 10px;
background: @grafanaPanelBackground;
overflow-y: scroll;
height: 100%;
.panel-content {
padding-bottom: 130px;
}
.dropdown-menu {
margin-bottom: 70px;
}
.panel-menu {
top: 0px;
}
}
.panel-menu {
z-index: 1000;
position: absolute;
......@@ -124,3 +157,5 @@
border: 1px solid @grayDark;
}
}
......@@ -277,7 +277,7 @@
// Tooltips and popovers
// -------------------------
@tooltipColor: #fff;
@tooltipBackground: @heroUnitBackground;
@tooltipBackground: rgb(58, 57, 57);
@tooltipArrowWidth: 5px;
@tooltipArrowColor: @tooltipBackground;
......
......@@ -59,6 +59,34 @@ define([
});
});
describeSharedTooltip("point count missmatch", function(ctx) {
ctx.setup(function() {
ctx.data = [
{ data: [[10, 15], [12, 20]], },
{ data: [[10, 2]] }
];
ctx.pos = { x: 11 };
});
it('should set pointCountMismatch to true', function() {
expect(ctx.results.pointCountMismatch).to.be(true);
});
});
describeSharedTooltip("one series is hidden", function(ctx) {
ctx.setup(function() {
ctx.data = [
{ data: [[10, 15], [12, 20]], },
{ data: [] }
];
ctx.pos = { x: 11 };
});
it('should set pointCountMismatch to false', function() {
expect(ctx.results.pointCountMismatch).to.be(undefined);
});
});
describeSharedTooltip("steppedLine false, stack true, individual false", function(ctx) {
ctx.setup(function() {
ctx.data = [
......
......@@ -146,7 +146,7 @@ define([
{
columns: ['time', 'text', 'sequence_number', 'title', 'tags'],
name: 'events1',
points: [[1402596000, 'some text', 1, 'Hello', 'B'], [1402596001, 'asd', 2, 'Hello2', 'B']]
points: [[1402596000000, 'some text', 1, 'Hello', 'B'], [1402596001000, 'asd', 2, 'Hello2', 'B']]
}
],
annotation: {
......@@ -176,7 +176,7 @@ define([
{
columns: ['time', 'text', 'sequence_number'],
name: 'events1',
points: [[1402596000, 'some text', 1]]
points: [[1402596000000, 'some text', 1]]
}
],
annotation: { query: 'select' }
......
......@@ -6,13 +6,14 @@
* To change this template use File | Settings | File Templates.
*/
(function(){
(function(angular){
function isDnDsSupported(){
return 'draggable' in document.createElement("span");
return 'ondrag' in document.createElement("a");
}
if(!isDnDsSupported()){
angular.module("ang-drag-drop", []);
return;
}
......@@ -22,7 +23,7 @@ if (window.jQuery && (-1 == window.jQuery.event.props.indexOf("dataTransfer")))
var currentData;
angular.module("ngDragDrop",[])
angular.module("ang-drag-drop",[])
.directive("uiDraggable", [
'$parse',
'$rootScope',
......@@ -71,13 +72,13 @@ angular.module("ngDragDrop",[])
if (e.dataTransfer && e.dataTransfer.dropEffect !== "none") {
if (attrs.onDropSuccess) {
var fn = $parse(attrs.onDropSuccess);
scope.$apply(function () {
scope.$evalAsync(function () {
fn(scope, {$event: e});
});
} else {
if (attrs.onDropFailure) {
var fn = $parse(attrs.onDropFailure);
scope.$apply(function () {
scope.$evalAsync(function () {
fn(scope, {$event: e});
});
}
......@@ -101,7 +102,7 @@ angular.module("ngDragDrop",[])
if (dragImage) {
var dragImageFn = $parse(attrs.dragImage);
scope.$apply(function() {
scope.$evalAsync(function() {
var dragImageParameters = dragImageFn(scope, {$event: e});
if (dragImageParameters) {
if (angular.isString(dragImageParameters)) {
......@@ -116,10 +117,10 @@ angular.module("ngDragDrop",[])
});
}
e.dataTransfer.setData("Text", sendData);
e.dataTransfer.setData("dataToSend", sendData);
currentData = angular.fromJson(sendData);
e.dataTransfer.effectAllowed = "copyMove";
$rootScope.$broadcast("ANGULAR_DRAG_START", sendChannel);
$rootScope.$broadcast("ANGULAR_DRAG_START", sendChannel, currentData.data);
}
else {
e.preventDefault();
......@@ -138,6 +139,8 @@ angular.module("ngDragDrop",[])
var dragChannel = "";
var dragEnterClass = attr.dragEnterClass || "on-drag-enter";
var dragHoverClass = attr.dragHoverClass || "on-drag-hover";
var customDragEnterEvent = $parse(attr.onDragEnter);
var customDragLeaveEvent = $parse(attr.onDragLeave);
function onDragOver(e) {
if (e.preventDefault) {
......@@ -148,20 +151,57 @@ angular.module("ngDragDrop",[])
e.stopPropagation();
}
var fn = $parse(attr.uiOnDragOver);
scope.$evalAsync(function () {
fn(scope, {$event: e, $channel: dropChannel});
});
e.dataTransfer.dropEffect = e.shiftKey ? 'copy' : 'move';
return false;
}
function onDragLeave(e) {
dragging--;
if (dragging == 0) {
element.removeClass(dragHoverClass);
}
if (e.preventDefault) {
e.preventDefault();
}
if (e.stopPropagation) {
e.stopPropagation();
}
dragging--;
if (dragging == 0) {
scope.$evalAsync(function () {
customDragEnterEvent(scope, {$event: e});
});
element.removeClass(dragHoverClass);
}
var fn = $parse(attr.uiOnDragLeave);
scope.$evalAsync(function () {
fn(scope, {$event: e, $channel: dropChannel});
});
}
function onDragEnter(e) {
if (e.preventDefault) {
e.preventDefault();
}
if (e.stopPropagation) {
e.stopPropagation();
}
dragging++;
var fn = $parse(attr.uiOnDragEnter);
scope.$evalAsync(function () {
fn(scope, {$event: e, $channel: dropChannel});
});
$rootScope.$broadcast("ANGULAR_HOVER", dragChannel);
scope.$evalAsync(function () {
customDragLeaveEvent(scope, {$event: e});
});
element.addClass(dragHoverClass);
}
......@@ -173,11 +213,11 @@ angular.module("ngDragDrop",[])
e.stopPropagation(); // Necessary. Allows us to drop.
}
var sendData = e.dataTransfer.getData("Text");
var sendData = e.dataTransfer.getData("dataToSend");
sendData = angular.fromJson(sendData);
var fn = $parse(attr.uiOnDrop);
scope.$apply(function () {
scope.$evalAsync(function () {
fn(scope, {$data: sendData.data, $event: e, $channel: sendData.channel});
});
element.removeClass(dragEnterClass);
......@@ -338,4 +378,4 @@ angular.module("ngDragDrop",[])
}
]);
}());
}(angular));
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