Commit 0bde1bb8 by Torkel Ödegaard

Dashboard and nav links are near completion now, #1944

parent 4b4f398e
......@@ -107,7 +107,7 @@
</div>
<div ng-if="editor.index == 2">
<dash-links-editor dashboard="dashboard"></dash-links-editor>
<dash-links-editor></dash-links-editor>
</div>
<div ng-repeat="pulldown in dashboard.nav" ng-controller="SubmenuCtrl" ng-show="editor.index == 3+$index">
......
......@@ -9,7 +9,8 @@ function (angular, _, require, config) {
var module = angular.module('grafana.controllers');
module.controller('ShareModalCtrl', function($scope, $rootScope, $location, $timeout, timeSrv, $element, templateSrv) {
module.controller('ShareModalCtrl', function($scope, $rootScope, $location, $timeout, timeSrv, $element, templateSrv, linkSrv) {
$scope.options = { forCurrent: true, includeTemplateVars: true, theme: 'current' };
$scope.editor = { index: 0 };
......@@ -47,14 +48,7 @@ function (angular, _, require, config) {
params.to = range.to;
if ($scope.options.includeTemplateVars) {
_.each(templateSrv.variables, function(variable) {
params['var-' + variable.name] = variable.current.text;
});
}
else {
_.each(templateSrv.variables, function(variable) {
delete params['var-' + variable.name];
});
templateSrv.fillVariableValuesForUrl(params);
}
if (!$scope.options.forCurrent) {
......@@ -74,19 +68,7 @@ function (angular, _, require, config) {
delete params.fullscreen;
}
var paramsArray = [];
_.each(params, function(value, key) {
if (value === null) { return; }
if (value === true) {
paramsArray.push(key);
} else {
key += '=' + encodeURIComponent(value);
paramsArray.push(key);
}
});
var queryParams = "?" + paramsArray.join('&');
$scope.shareUrl = baseUrl + queryParams;
$scope.shareUrl = linkSrv.addParamsToUrl(baseUrl, params);
var soloUrl = $scope.shareUrl;
soloUrl = soloUrl.replace('/dashboard/db/', '/dashboard/solo/db/');
......
......@@ -9,7 +9,7 @@
<i ng-click="moveLink($index, 1)" ng-hide="$last" class="pointer fa fa-fw fa-arrow-down"></i>
</li>
<li class="tight-form-item last">
<i class="fa fa-remove pointer" ng-click="deleteLink(link)"></i>
<i class="fa fa-remove pointer" ng-click="deleteLink($index)"></i>
</li>
</ul>
......@@ -36,8 +36,6 @@
<li ng-show="link.type === 'dashboards' && link.asDropdown">
<input type="text" ng-model="link.title" class="input-medium tight-form-input" ng-model-onblur ng-change="updated()">
</li>
<li class="tight-form-item" ng-show="link.type === 'link'" style="width: 51px">Url</li>
<li ng-show="link.type === 'link'">
<input type="text" ng-model="link.url" class="input-xlarge tight-form-input" style="width: 302px;" ng-model-onblur ng-change="updated()">
......@@ -68,24 +66,22 @@
</ul>
<div class="clearfix"></div>
</div>
<div class="tight-form">
<ul class="tight-form-list">
<li class="tight-form-item" style="width: 20px">
<i class="fa fa-fw fa-unlink invisible"></i>
</li>
<li class="tight-form-item">
<editor-checkbox text="Keep current time range" model="link.keepTime" change="updated()"></editor-checkbox>
</li>
<li class="tight-form-item">
<editor-checkbox text="Add current variable values" model="link.includeVars" change="updated()"></editor-checkbox>
</li>
</ul>
<div class="clearfix"></div>
</div>
</div>
</div>
<!-- <div class="tight&#45;form"> -->
<!-- <ul class="tight&#45;form&#45;list" role="menu"> -->
<!-- <li class="tight&#45;form&#45;item"> -->
<!-- <i class="fa fa&#45;remove invisible"></i> -->
<!-- </li> -->
<!-- <li class="tight&#45;form&#45;item" style="width: 80px;"> -->
<!-- Params -->
<!-- <tip>Use var&#45;variableName=value to pass templating variables.</tip> -->
<!-- </li> -->
<!-- <li> -->
<!-- <input type="text" ng&#45;model="link.params" class="input&#45;xxlarge tight&#45;form&#45;input"> -->
<!-- </li> -->
<!-- </ul> -->
<!-- <div class="clearfix"></div> -->
<!-- </div> -->
<div class="editor-row">
<br>
<button class="btn btn-inverse" ng-click="addLink()"><i class="fa fa-plus"></i> Add link</button>
......
......@@ -19,9 +19,6 @@ function (angular, _) {
module.directive('dashLinksEditor', function() {
return {
scope: {
dashboard: "="
},
restrict: 'E',
controller: 'DashLinkEditorCtrl',
templateUrl: 'app/features/dashlinks/editor.html',
......@@ -76,6 +73,11 @@ function (angular, _) {
icon.attr('class', 'fa fa-fw ' + scope.link.icon);
anchor.attr('target', scope.link.target);
// fix for menus on the far right
if (link.asDropdown && scope.$last) {
elem.find('.dropdown-menu').addClass('pull-right');
}
update();
scope.$on('refresh', update);
}
......@@ -96,12 +98,14 @@ function (angular, _) {
return $q.when([{
title: linkDef.title,
tag: linkDef.tag,
keepTime: linkDef.keepTime,
includeVars: linkDef.includeVars,
icon: "fa fa-bars",
asDropdown: true
}]);
}
return $scope.searchDashboards(linkDef.tag);
return $scope.searchDashboards(linkDef);
}
if (linkDef.type === 'link') {
......@@ -111,6 +115,8 @@ function (angular, _) {
icon: iconMap[linkDef.icon],
tooltip: linkDef.tooltip,
target: linkDef.targetBlank ? "_blank" : "",
keepTime: linkDef.keepTime,
includeVars: linkDef.includeVars,
}]);
}
......@@ -125,12 +131,18 @@ function (angular, _) {
});
}
$scope.searchDashboards = function(tag) {
return backendSrv.search({tag: tag}).then(function(results) {
$scope.searchDashboards = function(link) {
return backendSrv.search({tag: link.tag}).then(function(results) {
return _.reduce(results.dashboards, function(memo, dash) {
// do not add current dashboard
if (dash.id !== currentDashId) {
memo.push({ title: dash.title, url: 'dashboard/db/'+ dash.slug, icon: 'fa fa-th-large', addTime: true });
memo.push({
title: dash.title,
url: 'dashboard/db/'+ dash.slug,
icon: 'fa fa-th-large',
keepTime: link.keepTime,
includeVars: link.includeVars
});
}
return memo;
}, []);
......@@ -138,7 +150,7 @@ function (angular, _) {
};
$scope.fillDropdown = function(link) {
$scope.searchDashboards(link.tag).then(function(results) {
$scope.searchDashboards(link).then(function(results) {
_.each(results, function(hit) {
hit.url = linkSrv.getLinkUrl(hit);
});
......@@ -154,8 +166,11 @@ function (angular, _) {
$scope.iconMap = iconMap;
$scope.dashboard.links = $scope.dashboard.links || [];
$scope.addLink = function() {
$scope.dashboard.links.push({ type: 'dashboards', icon: 'external link' });
$scope.updateSubmenuVisibility();
$scope.updated();
};
$scope.moveLink = function(index, dir) {
......@@ -167,8 +182,10 @@ function (angular, _) {
$rootScope.appEvent('dash-links-updated');
};
$scope.deleteLink = function(link) {
$scope.dashboard.links = _.without($scope.dashboard.links, link);
$scope.deleteLink = function(index) {
$scope.dashboard.links.splice(index, 1);
$scope.updateSubmenuVisibility();
$scope.updated();
};
});
......
define([
'angular',
'kbn',
'lodash',
],
function (angular, kbn) {
function (angular, kbn, _) {
'use strict';
angular
.module('grafana.services')
.service('linkSrv', function(templateSrv, timeSrv) {
// parseUri 1.2.2
// (c) Steven Levithan <stevenlevithan.com>
// MIT License
this.getLinkUrl = function(link) {
var url = templateSrv.replace(link.url || '');
var params = {};
function parseUri (str) {
var o = parseUri.options,
m = o.parser[o.strictMode ? "strict" : "loose"].exec(str),
uri = {},
i = 14;
if (link.keepTime) {
var range = timeSrv.timeRangeForUrl();
params['from'] = range.from;
params['to'] = range.to;
}
while (i--) {
uri[o.key[i]] = m[i] || "";
if (link.includeVars) {
templateSrv.fillVariableValuesForUrl(params);
}
uri[o.q.name] = {};
uri[o.key[12]].replace(o.q.parser, function ($0, $1, $2) {
if ($1) {
uri[o.q.name][$1] = $2;
return this.addParamsToUrl(url, params);
};
this.addParamsToUrl = function(url, params) {
var paramsArray = [];
_.each(params, function(value, key) {
if (value === null) { return; }
if (value === true) {
paramsArray.push(key);
}
else if (_.isArray(value)) {
_.each(value, function(instance) {
paramsArray.push(key + '=' + encodeURIComponent(instance));
});
}
else {
paramsArray.push(key + '=' + encodeURIComponent(value));
}
});
return uri;
}
parseUri.options = {
strictMode: false,
key: ["source","protocol","authority","userInfo","user","password","host",
"port","relative","path","directory","file","query","anchor"],
q: {
name: "queryKey",
parser: /(?:^|&)([^&=]*)=?([^&]*)/g
},
/* jshint ignore:start */
parser: {
strict: /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/,
loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*)(?::([^:@]*))?)?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/
if (paramsArray.length === 0) {
return url;
}
/* jshint ignore:end */
};
this.getLinkUrl = function(link) {
var href = templateSrv.replace(link.url || '');
if (link.addTime) {
var range = timeSrv.timeRangeForUrl();
href += (href.indexOf('?') !== -1 ? '&' : '?');
href += 'from=' + range.from;
href += '&to=' + range.to;
}
return href;
url += (url.indexOf('?') !== -1 ? '&' : '?');
return url + paramsArray.join('&');
};
this.getAnchorInfo = function(link) {
......
......@@ -76,7 +76,7 @@ function (angular, _) {
};
this.replace = function(target, scopedVars) {
if (!target) { return; }
if (!target) { return target; }
var value;
this._regex.lastIndex = 0;
......@@ -95,7 +95,7 @@ function (angular, _) {
};
this.replaceWithText = function(target, scopedVars) {
if (!target) { return; }
if (!target) { return target; }
var value;
var text;
......@@ -115,6 +115,12 @@ function (angular, _) {
});
};
this.fillVariableValuesForUrl = function(params) {
_.each(this.variables, function(variable) {
params['var-' + variable.name] = variable.current.value;
});
};
});
});
......@@ -94,4 +94,5 @@
}
.dash-nav-link {
color: @textColor;
}
......@@ -131,6 +131,7 @@ define([
return _.template(text, this.data, this.templateSettings);
};
this.init = function() {};
this.fillVariableValuesForUrl = function() {};
this.updateTemplateData = function() { };
this.variableExists = function() { return false; };
this.highlightVariablesAsHtml = function(str) { return str; };
......
define([
'helpers',
'features/dashboard/shareModalCtrl'
'features/dashboard/shareModalCtrl',
'features/panellinks/linkSrv',
], function(helpers) {
'use strict';
......@@ -14,8 +15,10 @@ define([
setTime({ from: 'now-1h', to: 'now' });
beforeEach(module('grafana.controllers'));
beforeEach(module('grafana.services'));
beforeEach(ctx.providePhase());
beforeEach(ctx.createControllerPhase('ShareModalCtrl'));
describe('shareUrl with current time range and panel', function() {
......@@ -63,8 +66,11 @@ define([
ctx.$location.path('/test');
ctx.scope.options.includeTemplateVars = true;
ctx.templateSrv.variables = [{ name: 'app', current: {text: 'mupp' }}, {name: 'server', current: {text: 'srv-01'}}];
setTime({ from: 'now-1h', to: 'now' });
ctx.templateSrv.fillVariableValuesForUrl = function(params) {
params['var-app'] = 'mupp';
params['var-server'] = 'srv-01';
};
ctx.scope.buildUrl();
expect(ctx.scope.shareUrl).to.be('http://server/#/test?from=now-1h&to=now&var-app=mupp&var-server=srv-01');
......
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