diff --git a/src/app/components/panellinkeditor/linkSrv.js b/src/app/components/panellinkeditor/linkSrv.js
new file mode 100644
index 00000000000..8737814556d
--- /dev/null
+++ b/src/app/components/panellinkeditor/linkSrv.js
@@ -0,0 +1,39 @@
+define([
+ 'angular',
+ 'kbn',
+],
+function (angular, kbn) {
+ 'use strict';
+
+ angular
+ .module('grafana.services')
+ .service('linkSrv', function(templateSrv, timeSrv) {
+
+ this.getPanelLinkAnchorInfo = function(link) {
+ var info = {};
+ if (link.type === 'absolute') {
+ info.target = '_blank';
+ info.href = templateSrv.replace(link.url);
+ info.title = templateSrv.replace(link.title);
+ info.href += '?';
+
+ }
+ else {
+ info.title = templateSrv.replace(link.title);
+ var slug = kbn.slugifyForUrl(link.dashboard);
+ info.href = '#dashboard/db/' + slug + '?';
+ }
+
+ var range = timeSrv.timeRangeForUrl();
+ info.href += 'from=' + range.from;
+ info.href += '&to=' + range.to;
+
+ if (link.params) {
+ info.href += "&" + link.params;
+ }
+
+ return info;
+ };
+
+ });
+});
diff --git a/src/app/components/panellinkeditor/module.html b/src/app/components/panellinkeditor/module.html
new file mode 100644
index 00000000000..2cbdc50e49b
--- /dev/null
+++ b/src/app/components/panellinkeditor/module.html
@@ -0,0 +1,46 @@
+
+
+
Drilldown / detail linkThese links appear in the dropdown menu in the panel menu
+
+
+
+
+
+
+
+
+
diff --git a/src/app/components/panellinkeditor/module.js b/src/app/components/panellinkeditor/module.js
new file mode 100644
index 00000000000..fe6f9684f7f
--- /dev/null
+++ b/src/app/components/panellinkeditor/module.js
@@ -0,0 +1,38 @@
+define([
+ 'angular',
+ 'lodash',
+ './linkSrv',
+],
+function (angular, _) {
+ 'use strict';
+
+ angular
+ .module('grafana.directives')
+ .directive('panelLinkEditor', function() {
+ return {
+ scope: {
+ panel: "="
+ },
+ restrict: 'E',
+ controller: 'PanelLinkEditorCtrl',
+ templateUrl: 'app/components/panellinkeditor/module.html',
+ link: function() {
+ }
+ };
+ }).controller('PanelLinkEditorCtrl', function($scope) {
+
+ $scope.panel.links = $scope.panel.links || [];
+
+ $scope.addLink = function() {
+ $scope.panel.links.push({
+ type: 'dashboard',
+ name: 'Drilldown dashboard'
+ });
+ };
+
+ $scope.deleteLink = function(link) {
+ $scope.panel.links = _.without($scope.panel.links, link);
+ };
+
+ });
+});
diff --git a/src/app/controllers/sharePanelCtrl.js b/src/app/controllers/sharePanelCtrl.js
index cef550b8bd1..39909b20e19 100644
--- a/src/app/controllers/sharePanelCtrl.js
+++ b/src/app/controllers/sharePanelCtrl.js
@@ -27,19 +27,12 @@ function (angular, _) {
}
var panelId = $scope.panel.id;
- var range = timeSrv.timeRange(false);
var params = angular.copy($location.search());
- if (_.isString(range.to) && range.to.indexOf('now')) {
- range = timeSrv.timeRange();
- }
-
+ var range = timeSrv.timeRangeForUrl();
params.from = range.from;
params.to = range.to;
- if (_.isDate(params.from)) { params.from = params.from.getTime(); }
- if (_.isDate(params.to)) { params.to = params.to.getTime(); }
-
if ($scope.includeTemplateVars) {
_.each(templateSrv.variables, function(variable) {
params['var-' + variable.name] = variable.current.text;
diff --git a/src/app/directives/all.js b/src/app/directives/all.js
index 7f7836728a6..15c2a5c80f7 100644
--- a/src/app/directives/all.js
+++ b/src/app/directives/all.js
@@ -19,5 +19,6 @@ define([
'./graphiteSegment',
'./grafanaVersionCheck',
'./dropdown.typeahead',
+ 'components/panellinkeditor/module',
'./influxdbFuncEditor'
], function () {});
diff --git a/src/app/directives/panelMenu.js b/src/app/directives/panelMenu.js
index b7318f7b9b3..13aed5f6f3e 100644
--- a/src/app/directives/panelMenu.js
+++ b/src/app/directives/panelMenu.js
@@ -8,7 +8,7 @@ function (angular, $, _) {
angular
.module('grafana.directives')
- .directive('panelMenu', function($compile) {
+ .directive('panelMenu', function($compile, linkSrv) {
var linkTemplate = '{{panel.title | interpolateTemplateVars}}';
function createMenuTemplate($scope) {
@@ -22,7 +22,7 @@ function (angular, $, _) {
template += '';
template += '
+
+
+
+
diff --git a/src/app/services/timeSrv.js b/src/app/services/timeSrv.js
index 5a28532eb5a..564f30de7fd 100644
--- a/src/app/services/timeSrv.js
+++ b/src/app/services/timeSrv.js
@@ -95,6 +95,18 @@ define([
$timeout(this.refreshDashboard, 0);
};
+ this.timeRangeForUrl = function() {
+ var range = this.timeRange(false);
+ if (_.isString(range.to) && range.to.indexOf('now')) {
+ range = this.timeRange();
+ }
+
+ if (_.isDate(range.from)) { range.from = range.from.getTime(); }
+ if (_.isDate(range.to)) { range.to = range.to.getTime(); }
+
+ return range;
+ };
+
this.timeRange = function(parse) {
var _t = this.time;
if(_.isUndefined(_t) || _.isUndefined(_t.from)) {
diff --git a/src/test/specs/sharePanelCtrl-specs.js b/src/test/specs/sharePanelCtrl-specs.js
index 8c4eb2a2443..8c83f008ed5 100644
--- a/src/test/specs/sharePanelCtrl-specs.js
+++ b/src/test/specs/sharePanelCtrl-specs.js
@@ -7,6 +7,12 @@ define([
describe('SharePanelCtrl', function() {
var ctx = new helpers.ControllerTestContext();
+ function setTime(range) {
+ ctx.timeSrv.timeRangeForUrl = sinon.stub().returns(range);
+ }
+
+ setTime({ from: 'now-1h', to: 'now' });
+
beforeEach(module('grafana.controllers'));
beforeEach(ctx.providePhase());
@@ -14,10 +20,12 @@ define([
describe('shareUrl with current time range and panel', function() {
+
it('should generate share url relative time', function() {
ctx.$location.path('/test');
ctx.scope.panel = { id: 22 };
- ctx.timeSrv.time = { from: 'now-1h', to: 'now' };
+
+ setTime({ from: 'now-1h', to: 'now' });
ctx.scope.buildUrl();
expect(ctx.scope.shareUrl).to.be('http://server/#/test?from=now-1h&to=now&panelId=22&fullscreen');
@@ -26,26 +34,17 @@ define([
it('should generate share url absolute time', function() {
ctx.$location.path('/test');
ctx.scope.panel = { id: 22 };
- ctx.timeSrv.time = { from: new Date(1362178800000), to: new Date(1396648800000) };
+ setTime({ from: 1362178800000, to: 1396648800000 });
ctx.scope.buildUrl();
expect(ctx.scope.shareUrl).to.be('http://server/#/test?from=1362178800000&to=1396648800000&panelId=22&fullscreen');
});
- it('should generate share url with time as JSON strings', function() {
- ctx.$location.path('/test');
- ctx.scope.panel = { id: 22 };
- ctx.timeSrv.time = { from: "2012-01-31T23:00:00.000Z", to: "2014-04-04T22:00:00.000Z" };
-
- ctx.scope.buildUrl();
- expect(ctx.scope.shareUrl).to.be('http://server/#/test?from=1328050800000&to=1396648800000&panelId=22&fullscreen');
- });
-
it('should remove panel id when toPanel is false', function() {
ctx.$location.path('/test');
ctx.scope.panel = { id: 22 };
ctx.scope.toPanel = false;
- ctx.timeSrv.time = { from: 'now-1h', to: 'now' };
+ setTime({ from: 'now-1h', to: 'now' });
ctx.scope.buildUrl();
expect(ctx.scope.shareUrl).to.be('http://server/#/test?from=now-1h&to=now');
@@ -57,7 +56,7 @@ define([
ctx.scope.includeTemplateVars = true;
ctx.scope.toPanel = false;
ctx.templateSrv.variables = [{ name: 'app', current: {text: 'mupp' }}, {name: 'server', current: {text: 'srv-01'}}];
- ctx.timeSrv.time = { from: 'now-1h', to: 'now' };
+ setTime({ from: 'now-1h', to: 'now' });
ctx.scope.buildUrl();
expect(ctx.scope.shareUrl).to.be('http://server/#/test?from=now-1h&to=now&var-app=mupp&var-server=srv-01');