Commit 2c852052 by Torkel Ödegaard

SharePanelModal: working on share feature, #864

parent 2d866b92
{
"preset" : "default",
"lineBreak" : {
"before" : {
"VariableDeclarationWithoutInit" : 0,
},
"after": {
"AssignmentOperator": -1,
"ArgumentListArrayExpression": ">=1"
}
},
"whiteSpace" : {
"before" : {
},
"after" : {
}
}
}
...@@ -11,31 +11,64 @@ function (angular, _) { ...@@ -11,31 +11,64 @@ function (angular, _) {
$scope.init = function() { $scope.init = function() {
$scope.editor = { index: 0 }; $scope.editor = { index: 0 };
$scope.forCurrent = true;
$scope.toPanel = true;
$scope.buildUrl();
};
$scope.buildUrl = function() {
var baseUrl = $location.absUrl();
var queryStart = baseUrl.indexOf('?');
if (queryStart !== -1) {
baseUrl = baseUrl.substring(0, queryStart);
}
var currentUrl = $location.absUrl();
var panelId = $scope.panel.id; var panelId = $scope.panel.id;
var range = timeSrv.timeRange(false); var range = timeSrv.timeRange(false);
var from = range.from; var params = $location.search();
var to = range.to;
if (_.isDate(from)) { if (_.isString(range.to) && range.to.indexOf('now')) {
from = from.getTime(); range = timeSrv.timeRange();
}
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.forCurrent) {
delete params.from;
delete params.to;
} }
if (_.isDate(to)) {
to = to.getTime(); if ($scope.toPanel) {
params.panelId = panelId;
params.fullscreen = true;
} else {
delete params.panelId;
delete params.fullscreen;
} }
$scope.shareUrl = currentUrl + "?panelId=" + panelId + "&fullscreen"; var paramsArray = [];
$scope.shareUrl += "&from=" + from; _.each(params, function(value, key) {
$scope.shareUrl += "&to=" + to; var str = key;
if (value !== true) {
str += '=' + encodeURIComponent(value);
}
paramsArray.push(str);
});
$scope.forCurrent = true; $scope.shareUrl = baseUrl + "?" + paramsArray.join('&') ;
$scope.toPanel = true;
$timeout(function() { $timeout(function() {
var input = $element.find('[data-share-panel-url]'); var input = $element.find('[data-share-panel-url]');
input.focus(); input.focus();
input.select(); input.select();
}); }, 10);
}; };
$scope.init(); $scope.init();
......
...@@ -39,7 +39,6 @@ ...@@ -39,7 +39,6 @@
</bootstrap-tagsinput> </bootstrap-tagsinput>
<tip>Press enter to a add tag</tip> <tip>Press enter to a add tag</tip>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -15,13 +15,14 @@ ...@@ -15,13 +15,14 @@
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div class="editor-row"> <div class="editor-row">
<editor-opt-bool name="currentTime" text="Current time range" model="forCurrent"></editor-opt-bool> <editor-opt-bool name="currentTime" text="Current time range" model="forCurrent" change="buildUrl()"></editor-opt-bool>
<editor-opt-bool name="toPanel" text="To this panel only" model="toPanel"></editor-opt-bool> <editor-opt-bool name="toPanel" text="To this panel only" model="toPanel" change="buildUrl()"></editor-opt-bool>
</div> </div>
<div class="editor-row" style="margin-top: 20px;"> <div class="editor-row" style="margin-top: 20px;">
<input type="text" data-share-panel-url ng-model="shareUrl" class="input input-fluid"></input> <input type="text" data-share-panel-url class="input input-fluid" ng-model='shareUrl'></input>
</div> </div>
</div> </div>
......
...@@ -2,108 +2,110 @@ ...@@ -2,108 +2,110 @@
// config.js is where you will find the core Grafana configuration. This file contains parameter that // config.js is where you will find the core Grafana configuration. This file contains parameter that
// must be set before Grafana is run for the first time. // must be set before Grafana is run for the first time.
define(['settings'], define(['settings'], function(Settings) {
function (Settings) {
"use strict"; "use strict";
return new Settings({ return new Settings({
/* Data sources /* Data sources
* ======================================================== * ========================================================
* Datasources are used to fetch metrics, annotations, and serve as dashboard storage * Datasources are used to fetch metrics, annotations, and serve as dashboard storage
* - You can have multiple of the same type. * - You can have multiple of the same type.
* - grafanaDB: true marks it for use for dashboard storage * - grafanaDB: true marks it for use for dashboard storage
* - default: true marks the datasource as the default metric source (if you have multiple) * - default: true marks the datasource as the default metric source (if you have multiple)
* - basic authentication: use url syntax http://username:password@domain:port * - basic authentication: use url syntax http://username:password@domain:port
*/ */
// InfluxDB example setup (the InfluxDB databases specified need to exist) // InfluxDB example setup (the InfluxDB databases specified need to exist)
/* /*
datasources: { datasources: {
influxdb: { influxdb: {
type: 'influxdb', type: 'influxdb',
url: "http://my_influxdb_server:8086/db/database_name", url: "http://my_influxdb_server:8086/db/database_name",
username: 'admin', username: 'admin',
password: 'admin', password: 'admin',
},
grafana: {
type: 'influxdb',
url: "http://my_influxdb_server:8086/db/grafana",
username: 'admin',
password: 'admin',
grafanaDB: true
},
}, },
grafana: { */
type: 'influxdb',
url: "http://my_influxdb_server:8086/db/grafana", // Graphite & Elasticsearch example setup
username: 'admin', /*
password: 'admin', datasources: {
grafanaDB: true graphite: {
type: 'graphite',
url: "http://my.graphite.server.com:8080",
},
elasticsearch: {
type: 'elasticsearch',
url: "http://my.elastic.server.com:9200",
index: 'grafana-dash',
grafanaDB: true,
}
}, },
}, */
*/
// OpenTSDB & Elasticsearch example setup
// Graphite & Elasticsearch example setup /*
/* datasources: {
datasources: { opentsdb: {
graphite: { type: 'opentsdb',
type: 'graphite', url: "http://opentsdb.server:4242",
url: "http://my.graphite.server.com:8080", },
elasticsearch: {
type: 'elasticsearch',
url: "http://my.elastic.server.com:9200",
index: 'grafana-dash',
grafanaDB: true,
}
}, },
elasticsearch: { */
type: 'elasticsearch',
url: "http://my.elastic.server.com:9200", /* Global configuration options
index: 'grafana-dash', * ========================================================
grafanaDB: true, */
}
}, // specify the limit for dashboard search results
*/ search: {
max_results: 20
// OpenTSDB & Elasticsearch example setup
/*
datasources: {
opentsdb: {
type: 'opentsdb',
url: "http://opentsdb.server:4242",
}, },
elasticsearch: {
type: 'elasticsearch', // default home dashboard
url: "http://my.elastic.server.com:9200", default_route: '/dashboard/file/default.json',
index: 'grafana-dash',
grafanaDB: true, // set to false to disable unsaved changes warning
unsaved_changes_warning: true,
// set the default timespan for the playlist feature
// Example: "1m", "1h"
playlist_timespan: "1m",
// If you want to specify password before saving, please specify it below
// The purpose of this password is not security, but to stop some users from accidentally changing dashboards
admin: {
password: ''
},
// Change window title prefix from 'Grafana - <dashboard title>'
window_title_prefix: 'Grafana - ',
// Add your own custom panels
plugins: {
// list of plugin panels
panels: [],
// requirejs modules in plugins folder that should be loaded
// for example custom datasources
dependencies: [],
} }
},
*/ });
/* Global configuration options
* ========================================================
*/
// specify the limit for dashboard search results
search: {
max_results: 20
},
// default home dashboard
default_route: '/dashboard/file/default.json',
// set to false to disable unsaved changes warning
unsaved_changes_warning: true,
// set the default timespan for the playlist feature
// Example: "1m", "1h"
playlist_timespan: "1m",
// If you want to specify password before saving, please specify it below
// The purpose of this password is not security, but to stop some users from accidentally changing dashboards
admin: {
password: ''
},
// Change window title prefix from 'Grafana - <dashboard title>'
window_title_prefix: 'Grafana - ',
// Add your own custom panels
plugins: {
// list of plugin panels
panels: [],
// requirejs modules in plugins folder that should be loaded
// for example custom datasources
dependencies: [],
}
});
}); });
...@@ -2,6 +2,8 @@ input[type=text].input-fluid { ...@@ -2,6 +2,8 @@ input[type=text].input-fluid {
width: 100%; width: 100%;
box-sizing: border-box; box-sizing: border-box;
padding: 14px; padding: 14px;
-moz-box-sizing: border-box;
height: 100%;
} }
input[type="checkbox"].cr1 { input[type="checkbox"].cr1 {
......
...@@ -8,6 +8,7 @@ define([ ...@@ -8,6 +8,7 @@ define([
var self = this; var self = this;
this.datasource = {}; this.datasource = {};
this.$element = {};
this.annotationsSrv = {}; this.annotationsSrv = {};
this.timeSrv = new TimeSrvStub(); this.timeSrv = new TimeSrvStub();
this.templateSrv = new TemplateSrvStub(); this.templateSrv = new TemplateSrvStub();
...@@ -16,18 +17,23 @@ define([ ...@@ -16,18 +17,23 @@ define([
get: function() { return self.datasource; } get: function() { return self.datasource; }
}; };
this.providePhase = function() { this.providePhase = function(mocks) {
return module(function($provide) { return module(function($provide) {
$provide.value('datasourceSrv', self.datasourceSrv); $provide.value('datasourceSrv', self.datasourceSrv);
$provide.value('annotationsSrv', self.annotationsSrv); $provide.value('annotationsSrv', self.annotationsSrv);
$provide.value('timeSrv', self.timeSrv); $provide.value('timeSrv', self.timeSrv);
$provide.value('templateSrv', self.templateSrv); $provide.value('templateSrv', self.templateSrv);
$provide.value('$element', self.$element);
_.each(mocks, function(key, value) {
$provide.value(key, value);
});
}); });
}; };
this.createControllerPhase = function(controllerName) { this.createControllerPhase = function(controllerName) {
return inject(function($controller, $rootScope, $q) { return inject(function($controller, $rootScope, $q, $location) {
self.scope = $rootScope.$new(); self.scope = $rootScope.$new();
self.$location = $location;
self.scope.panel = {}; self.scope.panel = {};
self.scope.row = { panels:[] }; self.scope.row = { panels:[] };
self.scope.dashboard = {}; self.scope.dashboard = {};
......
define([
'./helpers',
'controllers/sharePanelCtrl'
], function(helpers) {
'use strict';
describe('SharePanelCtrl', function() {
var ctx = new helpers.ControllerTestContext();
beforeEach(module('grafana.controllers'));
beforeEach(ctx.providePhase());
beforeEach(ctx.createControllerPhase('SharePanelCtrl'));
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' };
ctx.scope.buildUrl();
expect(ctx.scope.shareUrl).to.be('http://server/#/test?from=now-1h&to=now&panelId=22&fullscreen');
});
it('should generate share url absolute time', function() {
ctx.$location.path('/test');
ctx.scope.panel = { id: 22 };
ctx.timeSrv.time = { from: new Date(2012,1,1), to: new Date(2014,3,5) };
ctx.scope.buildUrl();
expect(ctx.scope.shareUrl).to.be('http://server/#/test?from=1328050800000&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: new Date(2012,1,1).toJSON(), to: new Date(2014,3,5).toJSON() };
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' };
ctx.scope.buildUrl();
expect(ctx.scope.shareUrl).to.be('http://server/#/test?from=now-1h&to=now');
});
});
});
});
...@@ -131,6 +131,7 @@ require([ ...@@ -131,6 +131,7 @@ require([
'specs/grafanaGraph-specs', 'specs/grafanaGraph-specs',
'specs/graph-tooltip-specs', 'specs/graph-tooltip-specs',
'specs/seriesOverridesCtrl-specs', 'specs/seriesOverridesCtrl-specs',
'specs/sharePanelCtrl-specs',
'specs/timeSrv-specs', 'specs/timeSrv-specs',
'specs/templateSrv-specs', 'specs/templateSrv-specs',
'specs/templateValuesSrv-specs', 'specs/templateValuesSrv-specs',
......
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