Просмотр исходного кода

Added dashboard import feature

Torkel Ödegaard 11 лет назад
Родитель
Сommit
1c5f902770

+ 7 - 0
src/app/features/account/datasourcesCtrl.js

@@ -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};

+ 78 - 0
src/app/features/account/importCtrl.js

@@ -0,0 +1,78 @@
+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();
+
+  });
+});

+ 5 - 5
src/app/features/account/partials/collaborators.html

@@ -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>

+ 10 - 1
src/app/features/account/partials/datasources.html

@@ -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">

+ 59 - 0
src/app/features/account/partials/import.html

@@ -0,0 +1,59 @@
+<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>
+

+ 32 - 30
src/app/features/admin/partials/accounts.html

@@ -1,37 +1,39 @@
-<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>

+ 1 - 0
src/app/features/all.js

@@ -11,6 +11,7 @@ define([
   './account/collaboratorsCtrl',
   './account/datasourcesCtrl',
   './account/apiKeysCtrl',
+  './account/importCtrl',
   './admin/accountsCtrl',
   './grafanaDatasource/datasource',
 ], function () {});

+ 2 - 2
src/app/features/annotations/partials/editor.html

@@ -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>

+ 1 - 1
src/app/features/elasticsearch/datasource.js

@@ -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;

+ 1 - 1
src/app/features/influxdb/datasource.js

@@ -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;

+ 4 - 0
src/app/partials/sidemenu.html

@@ -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>

+ 4 - 0
src/app/routes/backend/all.js

@@ -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',

+ 4 - 0
src/app/services/datasourceSrv.js

@@ -82,6 +82,10 @@ function (angular, _, config) {
       return this.default;
     };
 
+    this.getAll = function() {
+      return datasources;
+    };
+
     this.getAnnotationSources = function() {
       return annotationSources;
     };