Commit 1c5f9027 by Torkel Ödegaard

Added dashboard import feature

parent a0036179
......@@ -15,6 +15,13 @@ function (angular) {
access: 'proxy'
};
$scope.types = [
{ name: 'Graphite', type: 'graphite' },
{ name: 'InfluxDB', type: 'influxdb' },
{ name: 'Elasticsearch', type: 'elasticsearch' },
{ name: 'OpenTSDB', type: 'opentsdb' },
];
$scope.init = function() {
$scope.reset();
$scope.editor = {index: 0};
......
define([
'angular',
'lodash',
],
function (angular, _) {
'use strict';
var module = angular.module('grafana.controllers');
module.controller('ImportCtrl', function($scope, $http, backendSrv, datasourceSrv) {
$scope.init = function() {
$scope.datasources = [];
$scope.sourceName = 'grafana';
$scope.destName = 'grafana';
$scope.imported = [];
$scope.dashboards = [];
$scope.infoText = '';
$scope.importing = false;
_.each(datasourceSrv.getAll(), function(ds) {
if (ds.type === 'influxdb' || ds.type === 'elasticsearch') {
$scope.sourceName = ds.name;
$scope.datasources.push(ds.name);
} else if (ds.type === 'grafana') {
$scope.datasources.push(ds.name);
}
});
};
$scope.startImport = function() {
$scope.sourceDs = datasourceSrv.get($scope.sourceName);
$scope.destDs = datasourceSrv.get($scope.destName);
$scope.sourceDs.searchDashboards('title:').then(function(results) {
$scope.dashboards = results.dashboards;
if ($scope.dashboards.length === 0) {
$scope.infoText = 'No dashboards found';
return;
}
$scope.importing = true;
$scope.imported = [];
$scope.next();
});
};
$scope.next = function() {
if ($scope.dashboards.length === 0) {
$scope.infoText = "Done! Imported " + $scope.imported.length + " dashboards";
}
var dash = $scope.dashboards.shift();
if (!dash.title) {
console.log(dash);
return;
}
var infoObj = {name: dash.title, info: 'Importing...'};
$scope.imported.push(infoObj);
$scope.infoText = "Importing " + $scope.imported.length + '/' + ($scope.imported.length + $scope.dashboards.length);
$scope.sourceDs.getDashboard(dash.id).then(function(loadedDash) {
$scope.destDs.saveDashboard(loadedDash).then(function() {
infoObj.info = "Done!";
$scope.next();
}, function(err) {
infoObj.info = "Error: " + err;
$scope.next();
});
});
};
$scope.init();
});
});
......@@ -17,20 +17,20 @@
<div class="tight-form">
<ul class="tight-form-list">
<li class="tight-form-item" style="width: 160px">
<strong>Username or Email</strong>
<strong>username or email</strong>
</li>
<li>
<input type="text" ng-model="collaborator.loginOrEmail" required class="input-xlarge tight-form-input" placeholder="collaborator@email.com">
<input type="text" ng-model="collaborator.loginoremail" required class="input-xlarge tight-form-input" placeholder="collaborator@email.com">
</li>
<li class="tight-form-item">
Role
role
</li>
<li>
<select type="text" ng-model="collaborator.role" class="input-small tight-form-input" ng-options="f for f in ['Viewer', 'Editor', 'Admin']">
<select type="text" ng-model="collaborator.role" class="input-small tight-form-input" ng-options="f for f in ['viewer', 'editor', 'admin']">
</select>
</li>
<li>
<button class="btn btn-success tight-form-btn" ng-click="addCollaborator()">Add</button>
<button class="btn btn-success tight-form-btn" ng-click="addcollaborator()">add</button>
</li>
</ul>
<div class="clearfix"></div>
......
......@@ -70,7 +70,7 @@
</div>
<div class="editor-option">
<label class="small">Type</label>
<select class="input-medium" ng-model="current.type" ng-options="f for f in ['graphite', 'influxdb', 'opentsdb']" ng-change="typeChanged()"></select>
<select class="input-medium" ng-model="current.type" ng-options="f.type as f.name for f in types" ng-change="typeChanged()"></select>
</div>
<editor-opt-bool text="Mark as default" model="current.isDefault" change="render()"></editor-opt-bool>
</div>
......@@ -103,6 +103,15 @@
</div>
</div>
</div>
<div class="editor-row" ng-if="current.type === 'elasticsearch'">
<div class="section">
<h5>Elastic search details</h5>
<div class="editor-option">
<label class="small">Index name</label>
<input type="text" class="input-large" required ng-model='current.database' placeholder=""></input>
</div>
</div>
</div>
</div>
<div class="dashboard-editor-footer" style="margin-top: 20px">
......
<div ng-include="'app/partials/navbar.html'" ng-init="pageTitle='Import'"></div>
<div class="dashboard-edit-view" style="min-height: 500px">
<div class="dashboard-editor-header">
<div class="dashboard-editor-title">
<i class="fa fa-th-large"></i>
Import Dashboards
</div>
</div>
<div class="dashboard-editor-body">
<div class="editor-row">
<div class="section">
<div class="tight-form">
<ul class="tight-form-list">
<li class="tight-form-item" style="width: 160px">
<strong>Dashboard source</strong>
</li>
<li>
<select type="text" ng-model="sourceName" class="input-small tight-form-input" ng-options="f for f in datasources">
</select>
</li>
<li class="tight-form-item" style="width: 160px">
<strong>Destination</strong>
</li>
<li>
<select type="text" ng-model="destName" class="input-small tight-form-input" ng-options="f for f in datasources">
</select>
</li>
<li>
<button class="btn btn-success tight-form-btn" ng-click="startImport()">Import</button>
</li>
</ul>
<div class="clearfix"></div>
</div>
</div>
</div>
<div class="editor-row" ng-if="importing">
<section class="section">
<h5>{{infoText}}</h5>
<div class="editor-row row">
<table class="grafana-options-table span5">
<tr ng-repeat="dash in imported">
<td>{{dash.name}}</td>
<td>
{{dash.info}}
</td>
</tr>
</table>
</div>
</section>
</div>
</div>
</div>
<div ng-include="'app/partials/navbar.html'" ng-init="pageTitle='Accounts'"></div>
<div ng-include="'app/partials/navbar.html'" ng-init="pageTitle='Admin > Accounts'"></div>
<div class="dashboard-edit-view" style="min-height: 500px">
<div class="row-fluid">
<div class="span8">
<div class="dashboard-editor-body">
<table class="grafana-options-table">
<tr>
<th style="text-align:left">Id</th>
<th>Login</th>
<th>Email</th>
<th>Name</th>
<th>Admin</th>
<th></th>
</tr>
<tr ng-repeat="account in accounts">
<td>{{account.id}}</td>
<td>{{account.login}}</td>
<td>{{account.email}}</td>
<td>{{account.name}}</td>
<td>{{account.isAdmin}}</td>
<td style="width: 1%">
<a ng-click="edit(variable)" class="btn btn-success">
<i class="fa fa-edit"></i>
Edit
</a>
&nbsp;&nbsp;
<a ng-click="edit(variable)" class="btn btn-danger">
<i class="fa fa-remove"></i>
</a>
</td>
</tr>
</table>
<div class="editor-row row">
<div class="section span6">
<table class="grafana-options-table">
<tr>
<th style="text-align:left">Id</th>
<th>Login</th>
<th>Email</th>
<th>Name</th>
<th>Admin</th>
<th></th>
</tr>
<tr ng-repeat="account in accounts">
<td>{{account.id}}</td>
<td>{{account.login}}</td>
<td>{{account.email}}</td>
<td>{{account.name}}</td>
<td>{{account.isAdmin}}</td>
<td style="width: 1%">
<a ng-click="edit(variable)" class="btn btn-success btn-small">
<i class="fa fa-edit"></i>
Edit
</a>
&nbsp;&nbsp;
<a ng-click="edit(variable)" class="btn btn-danger btn-small">
<i class="fa fa-remove"></i>
</a>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
......@@ -11,6 +11,7 @@ define([
'./account/collaboratorsCtrl',
'./account/datasourcesCtrl',
'./account/apiKeysCtrl',
'./account/importCtrl',
'./admin/accountsCtrl',
'./grafanaDatasource/datasource',
], function () {});
......@@ -26,7 +26,7 @@
{{annotation.name}}
</td>
<td style="width: 1%">
<a ng-click="edit(annotation)" class="btn btn-success btn-mini">
<a ng-click="edit(annotation)" class="btn btn-success btn-small">
<i class="fa fa-edit"></i>
Edit
</a>
......@@ -34,7 +34,7 @@
<td style="width: 1%"><i ng-click="_.move(annotations,$index,$index-1)" ng-hide="$first" class="pointer fa fa-arrow-up"></i></td>
<td style="width: 1%"><i ng-click="_.move(annotations,$index,$index+1)" ng-hide="$last" class="pointer fa fa-arrow-down"></i></td>
<td style="width: 1%">
<a ng-click="removeAnnotation(annotation)" class="btn btn-danger btn-mini">
<a ng-click="removeAnnotation(annotation)" class="btn btn-danger btn-small">
<i class="fa fa-remove"></i>
</a>
</td>
......
......@@ -13,7 +13,7 @@ function (angular, _, config, kbn, moment) {
module.factory('ElasticDatasource', function($q, $http, templateSrv) {
function ElasticDatasource(datasource) {
this.type = 'elastic';
this.type = 'elasticsearch';
this.basicAuth = datasource.basicAuth;
this.url = datasource.url;
this.name = datasource.name;
......
......@@ -15,7 +15,7 @@ function (angular, _, kbn, InfluxSeries, InfluxQueryBuilder) {
module.factory('InfluxDatasource', function($q, $http, templateSrv) {
function InfluxDatasource(datasource) {
this.type = 'influxDB';
this.type = 'influxdb';
this.urls = datasource.urls;
this.username = datasource.username;
this.password = datasource.password;
......
......@@ -26,6 +26,10 @@
<a class="pro-sidemenu-link" href="account/apikeys">
<i class="fa fa-key"></i>API Keys
</a>
<a class="pro-sidemenu-link" href="account/import">
<i class="fa fa-download"></i>
Import
</a>
<a class="pro-sidemenu-link" href="admin/accounts" ng-if="grafana.user.isGrafanaAdmin">
<i class="fa fa-institution"></i>Admin
</a>
......
......@@ -42,6 +42,10 @@ define([
templateUrl: 'app/features/account/partials/apikeys.html',
controller : 'ApiKeysCtrl',
})
.when('/account/import', {
templateUrl: 'app/features/account/partials/import.html',
controller : 'ImportCtrl',
})
.when('/account', {
templateUrl: 'app/features/account/partials/account.html',
controller : 'AccountCtrl',
......
......@@ -82,6 +82,10 @@ function (angular, _, config) {
return this.default;
};
this.getAll = function() {
return datasources;
};
this.getAnnotationSources = function() {
return annotationSources;
};
......
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