grafana 267 B

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411
  1. commit 1c5f902770c260f9bc63a0f07f1e9d22f60ce796
  2. Author: Torkel Ödegaard <torkel.odegaard@gmail.com>
  3. Date: Sat Jan 17 10:39:01 2015 +0100
  4. Added dashboard import feature
  5. diff --git a/src/app/features/account/datasourcesCtrl.js b/src/app/features/account/datasourcesCtrl.js
  6. index 983c74b4b..b8f9f9fda 100644
  7. --- a/src/app/features/account/datasourcesCtrl.js
  8. +++ b/src/app/features/account/datasourcesCtrl.js
  9. @@ -15,6 +15,13 @@ function (angular) {
  10. access: 'proxy'
  11. };
  12. + $scope.types = [
  13. + { name: 'Graphite', type: 'graphite' },
  14. + { name: 'InfluxDB', type: 'influxdb' },
  15. + { name: 'Elasticsearch', type: 'elasticsearch' },
  16. + { name: 'OpenTSDB', type: 'opentsdb' },
  17. + ];
  18. +
  19. $scope.init = function() {
  20. $scope.reset();
  21. $scope.editor = {index: 0};
  22. diff --git a/src/app/features/account/importCtrl.js b/src/app/features/account/importCtrl.js
  23. new file mode 100644
  24. index 000000000..a8548491c
  25. --- /dev/null
  26. +++ b/src/app/features/account/importCtrl.js
  27. @@ -0,0 +1,78 @@
  28. +define([
  29. + 'angular',
  30. + 'lodash',
  31. +],
  32. +function (angular, _) {
  33. + 'use strict';
  34. +
  35. + var module = angular.module('grafana.controllers');
  36. +
  37. + module.controller('ImportCtrl', function($scope, $http, backendSrv, datasourceSrv) {
  38. +
  39. + $scope.init = function() {
  40. + $scope.datasources = [];
  41. + $scope.sourceName = 'grafana';
  42. + $scope.destName = 'grafana';
  43. + $scope.imported = [];
  44. + $scope.dashboards = [];
  45. + $scope.infoText = '';
  46. + $scope.importing = false;
  47. +
  48. + _.each(datasourceSrv.getAll(), function(ds) {
  49. + if (ds.type === 'influxdb' || ds.type === 'elasticsearch') {
  50. + $scope.sourceName = ds.name;
  51. + $scope.datasources.push(ds.name);
  52. + } else if (ds.type === 'grafana') {
  53. + $scope.datasources.push(ds.name);
  54. + }
  55. + });
  56. + };
  57. +
  58. + $scope.startImport = function() {
  59. + $scope.sourceDs = datasourceSrv.get($scope.sourceName);
  60. + $scope.destDs = datasourceSrv.get($scope.destName);
  61. +
  62. + $scope.sourceDs.searchDashboards('title:').then(function(results) {
  63. + $scope.dashboards = results.dashboards;
  64. +
  65. + if ($scope.dashboards.length === 0) {
  66. + $scope.infoText = 'No dashboards found';
  67. + return;
  68. + }
  69. +
  70. + $scope.importing = true;
  71. + $scope.imported = [];
  72. + $scope.next();
  73. + });
  74. + };
  75. +
  76. + $scope.next = function() {
  77. + if ($scope.dashboards.length === 0) {
  78. + $scope.infoText = "Done! Imported " + $scope.imported.length + " dashboards";
  79. + }
  80. +
  81. + var dash = $scope.dashboards.shift();
  82. + if (!dash.title) {
  83. + console.log(dash);
  84. + return;
  85. + }
  86. +
  87. + var infoObj = {name: dash.title, info: 'Importing...'};
  88. + $scope.imported.push(infoObj);
  89. + $scope.infoText = "Importing " + $scope.imported.length + '/' + ($scope.imported.length + $scope.dashboards.length);
  90. +
  91. + $scope.sourceDs.getDashboard(dash.id).then(function(loadedDash) {
  92. + $scope.destDs.saveDashboard(loadedDash).then(function() {
  93. + infoObj.info = "Done!";
  94. + $scope.next();
  95. + }, function(err) {
  96. + infoObj.info = "Error: " + err;
  97. + $scope.next();
  98. + });
  99. + });
  100. + };
  101. +
  102. + $scope.init();
  103. +
  104. + });
  105. +});
  106. diff --git a/src/app/features/account/partials/collaborators.html b/src/app/features/account/partials/collaborators.html
  107. index e66a55d07..4d3f581c0 100644
  108. --- a/src/app/features/account/partials/collaborators.html
  109. +++ b/src/app/features/account/partials/collaborators.html
  110. @@ -17,20 +17,20 @@
  111. <div class="tight-form">
  112. <ul class="tight-form-list">
  113. <li class="tight-form-item" style="width: 160px">
  114. - <strong>Username or Email</strong>
  115. + <strong>username or email</strong>
  116. </li>
  117. <li>
  118. - <input type="text" ng-model="collaborator.loginOrEmail" required class="input-xlarge tight-form-input" placeholder="collaborator@email.com">
  119. + <input type="text" ng-model="collaborator.loginoremail" required class="input-xlarge tight-form-input" placeholder="collaborator@email.com">
  120. </li>
  121. <li class="tight-form-item">
  122. - Role
  123. + role
  124. </li>
  125. <li>
  126. - <select type="text" ng-model="collaborator.role" class="input-small tight-form-input" ng-options="f for f in ['Viewer', 'Editor', 'Admin']">
  127. + <select type="text" ng-model="collaborator.role" class="input-small tight-form-input" ng-options="f for f in ['viewer', 'editor', 'admin']">
  128. </select>
  129. </li>
  130. <li>
  131. - <button class="btn btn-success tight-form-btn" ng-click="addCollaborator()">Add</button>
  132. + <button class="btn btn-success tight-form-btn" ng-click="addcollaborator()">add</button>
  133. </li>
  134. </ul>
  135. <div class="clearfix"></div>
  136. diff --git a/src/app/features/account/partials/datasources.html b/src/app/features/account/partials/datasources.html
  137. index 86264721c..4f5f2399d 100644
  138. --- a/src/app/features/account/partials/datasources.html
  139. +++ b/src/app/features/account/partials/datasources.html
  140. @@ -70,7 +70,7 @@
  141. </div>
  142. <div class="editor-option">
  143. <label class="small">Type</label>
  144. - <select class="input-medium" ng-model="current.type" ng-options="f for f in ['graphite', 'influxdb', 'opentsdb']" ng-change="typeChanged()"></select>
  145. + <select class="input-medium" ng-model="current.type" ng-options="f.type as f.name for f in types" ng-change="typeChanged()"></select>
  146. </div>
  147. <editor-opt-bool text="Mark as default" model="current.isDefault" change="render()"></editor-opt-bool>
  148. </div>
  149. @@ -103,6 +103,15 @@
  150. </div>
  151. </div>
  152. </div>
  153. + <div class="editor-row" ng-if="current.type === 'elasticsearch'">
  154. + <div class="section">
  155. + <h5>Elastic search details</h5>
  156. + <div class="editor-option">
  157. + <label class="small">Index name</label>
  158. + <input type="text" class="input-large" required ng-model='current.database' placeholder=""></input>
  159. + </div>
  160. + </div>
  161. + </div>
  162. </div>
  163. <div class="dashboard-editor-footer" style="margin-top: 20px">
  164. diff --git a/src/app/features/account/partials/import.html b/src/app/features/account/partials/import.html
  165. new file mode 100644
  166. index 000000000..3ce6e101b
  167. --- /dev/null
  168. +++ b/src/app/features/account/partials/import.html
  169. @@ -0,0 +1,59 @@
  170. +<div ng-include="'app/partials/navbar.html'" ng-init="pageTitle='Import'"></div>
  171. +
  172. +<div class="dashboard-edit-view" style="min-height: 500px">
  173. +
  174. + <div class="dashboard-editor-header">
  175. + <div class="dashboard-editor-title">
  176. + <i class="fa fa-th-large"></i>
  177. + Import Dashboards
  178. + </div>
  179. + </div>
  180. +
  181. + <div class="dashboard-editor-body">
  182. +
  183. + <div class="editor-row">
  184. + <div class="section">
  185. + <div class="tight-form">
  186. + <ul class="tight-form-list">
  187. + <li class="tight-form-item" style="width: 160px">
  188. + <strong>Dashboard source</strong>
  189. + </li>
  190. + <li>
  191. + <select type="text" ng-model="sourceName" class="input-small tight-form-input" ng-options="f for f in datasources">
  192. + </select>
  193. + </li>
  194. + <li class="tight-form-item" style="width: 160px">
  195. + <strong>Destination</strong>
  196. + </li>
  197. + <li>
  198. + <select type="text" ng-model="destName" class="input-small tight-form-input" ng-options="f for f in datasources">
  199. + </select>
  200. + </li>
  201. + <li>
  202. + <button class="btn btn-success tight-form-btn" ng-click="startImport()">Import</button>
  203. + </li>
  204. + </ul>
  205. + <div class="clearfix"></div>
  206. + </div>
  207. + </div>
  208. + </div>
  209. +
  210. + <div class="editor-row" ng-if="importing">
  211. + <section class="section">
  212. + <h5>{{infoText}}</h5>
  213. +
  214. + <div class="editor-row row">
  215. + <table class="grafana-options-table span5">
  216. + <tr ng-repeat="dash in imported">
  217. + <td>{{dash.name}}</td>
  218. + <td>
  219. + {{dash.info}}
  220. + </td>
  221. + </tr>
  222. + </table>
  223. + </div>
  224. + </section>
  225. + </div>
  226. + </div>
  227. +</div>
  228. +
  229. diff --git a/src/app/features/admin/partials/accounts.html b/src/app/features/admin/partials/accounts.html
  230. index ffd6c7015..d8dffe750 100644
  231. --- a/src/app/features/admin/partials/accounts.html
  232. +++ b/src/app/features/admin/partials/accounts.html
  233. @@ -1,37 +1,39 @@
  234. -<div ng-include="'app/partials/navbar.html'" ng-init="pageTitle='Accounts'"></div>
  235. +<div ng-include="'app/partials/navbar.html'" ng-init="pageTitle='Admin > Accounts'"></div>
  236. <div class="dashboard-edit-view" style="min-height: 500px">
  237. - <div class="row-fluid">
  238. - <div class="span8">
  239. + <div class="dashboard-editor-body">
  240. - <table class="grafana-options-table">
  241. - <tr>
  242. - <th style="text-align:left">Id</th>
  243. - <th>Login</th>
  244. - <th>Email</th>
  245. - <th>Name</th>
  246. - <th>Admin</th>
  247. - <th></th>
  248. - </tr>
  249. - <tr ng-repeat="account in accounts">
  250. - <td>{{account.id}}</td>
  251. - <td>{{account.login}}</td>
  252. - <td>{{account.email}}</td>
  253. - <td>{{account.name}}</td>
  254. - <td>{{account.isAdmin}}</td>
  255. - <td style="width: 1%">
  256. - <a ng-click="edit(variable)" class="btn btn-success">
  257. - <i class="fa fa-edit"></i>
  258. - Edit
  259. - </a>
  260. - &nbsp;&nbsp;
  261. - <a ng-click="edit(variable)" class="btn btn-danger">
  262. - <i class="fa fa-remove"></i>
  263. - </a>
  264. - </td>
  265. - </tr>
  266. - </table>
  267. + <div class="editor-row row">
  268. + <div class="section span6">
  269. + <table class="grafana-options-table">
  270. + <tr>
  271. + <th style="text-align:left">Id</th>
  272. + <th>Login</th>
  273. + <th>Email</th>
  274. + <th>Name</th>
  275. + <th>Admin</th>
  276. + <th></th>
  277. + </tr>
  278. + <tr ng-repeat="account in accounts">
  279. + <td>{{account.id}}</td>
  280. + <td>{{account.login}}</td>
  281. + <td>{{account.email}}</td>
  282. + <td>{{account.name}}</td>
  283. + <td>{{account.isAdmin}}</td>
  284. + <td style="width: 1%">
  285. + <a ng-click="edit(variable)" class="btn btn-success btn-small">
  286. + <i class="fa fa-edit"></i>
  287. + Edit
  288. + </a>
  289. + &nbsp;&nbsp;
  290. + <a ng-click="edit(variable)" class="btn btn-danger btn-small">
  291. + <i class="fa fa-remove"></i>
  292. + </a>
  293. + </td>
  294. + </tr>
  295. + </table>
  296. + </div>
  297. </div>
  298. </div>
  299. </div>
  300. diff --git a/src/app/features/all.js b/src/app/features/all.js
  301. index 6b22c50e9..f3833c659 100644
  302. --- a/src/app/features/all.js
  303. +++ b/src/app/features/all.js
  304. @@ -11,6 +11,7 @@ define([
  305. './account/collaboratorsCtrl',
  306. './account/datasourcesCtrl',
  307. './account/apiKeysCtrl',
  308. + './account/importCtrl',
  309. './admin/accountsCtrl',
  310. './grafanaDatasource/datasource',
  311. ], function () {});
  312. diff --git a/src/app/features/annotations/partials/editor.html b/src/app/features/annotations/partials/editor.html
  313. index 14208dc2a..ae2d624ed 100644
  314. --- a/src/app/features/annotations/partials/editor.html
  315. +++ b/src/app/features/annotations/partials/editor.html
  316. @@ -26,7 +26,7 @@
  317. {{annotation.name}}
  318. </td>
  319. <td style="width: 1%">
  320. - <a ng-click="edit(annotation)" class="btn btn-success btn-mini">
  321. + <a ng-click="edit(annotation)" class="btn btn-success btn-small">
  322. <i class="fa fa-edit"></i>
  323. Edit
  324. </a>
  325. @@ -34,7 +34,7 @@
  326. <td style="width: 1%"><i ng-click="_.move(annotations,$index,$index-1)" ng-hide="$first" class="pointer fa fa-arrow-up"></i></td>
  327. <td style="width: 1%"><i ng-click="_.move(annotations,$index,$index+1)" ng-hide="$last" class="pointer fa fa-arrow-down"></i></td>
  328. <td style="width: 1%">
  329. - <a ng-click="removeAnnotation(annotation)" class="btn btn-danger btn-mini">
  330. + <a ng-click="removeAnnotation(annotation)" class="btn btn-danger btn-small">
  331. <i class="fa fa-remove"></i>
  332. </a>
  333. </td>
  334. diff --git a/src/app/features/elasticsearch/datasource.js b/src/app/features/elasticsearch/datasource.js
  335. index 3c82d98f8..0ca8ec853 100644
  336. --- a/src/app/features/elasticsearch/datasource.js
  337. +++ b/src/app/features/elasticsearch/datasource.js
  338. @@ -13,7 +13,7 @@ function (angular, _, config, kbn, moment) {
  339. module.factory('ElasticDatasource', function($q, $http, templateSrv) {
  340. function ElasticDatasource(datasource) {
  341. - this.type = 'elastic';
  342. + this.type = 'elasticsearch';
  343. this.basicAuth = datasource.basicAuth;
  344. this.url = datasource.url;
  345. this.name = datasource.name;
  346. diff --git a/src/app/features/influxdb/datasource.js b/src/app/features/influxdb/datasource.js
  347. index cef933d8d..692fdbdbb 100644
  348. --- a/src/app/features/influxdb/datasource.js
  349. +++ b/src/app/features/influxdb/datasource.js
  350. @@ -15,7 +15,7 @@ function (angular, _, kbn, InfluxSeries, InfluxQueryBuilder) {
  351. module.factory('InfluxDatasource', function($q, $http, templateSrv) {
  352. function InfluxDatasource(datasource) {
  353. - this.type = 'influxDB';
  354. + this.type = 'influxdb';
  355. this.urls = datasource.urls;
  356. this.username = datasource.username;
  357. this.password = datasource.password;
  358. diff --git a/src/app/partials/sidemenu.html b/src/app/partials/sidemenu.html
  359. index 25aeca4c9..207688965 100644
  360. --- a/src/app/partials/sidemenu.html
  361. +++ b/src/app/partials/sidemenu.html
  362. @@ -26,6 +26,10 @@
  363. <a class="pro-sidemenu-link" href="account/apikeys">
  364. <i class="fa fa-key"></i>API Keys
  365. </a>
  366. + <a class="pro-sidemenu-link" href="account/import">
  367. + <i class="fa fa-download"></i>
  368. + Import
  369. + </a>
  370. <a class="pro-sidemenu-link" href="admin/accounts" ng-if="grafana.user.isGrafanaAdmin">
  371. <i class="fa fa-institution"></i>Admin
  372. </a>
  373. diff --git a/src/app/routes/backend/all.js b/src/app/routes/backend/all.js
  374. index ec2635603..740baf48c 100644
  375. --- a/src/app/routes/backend/all.js
  376. +++ b/src/app/routes/backend/all.js
  377. @@ -42,6 +42,10 @@ define([
  378. templateUrl: 'app/features/account/partials/apikeys.html',
  379. controller : 'ApiKeysCtrl',
  380. })
  381. + .when('/account/import', {
  382. + templateUrl: 'app/features/account/partials/import.html',
  383. + controller : 'ImportCtrl',
  384. + })
  385. .when('/account', {
  386. templateUrl: 'app/features/account/partials/account.html',
  387. controller : 'AccountCtrl',
  388. diff --git a/src/app/services/datasourceSrv.js b/src/app/services/datasourceSrv.js
  389. index e77ca7077..1a2c4db5f 100644
  390. --- a/src/app/services/datasourceSrv.js
  391. +++ b/src/app/services/datasourceSrv.js
  392. @@ -82,6 +82,10 @@ function (angular, _, config) {
  393. return this.default;
  394. };
  395. + this.getAll = function() {
  396. + return datasources;
  397. + };
  398. +
  399. this.getAnnotationSources = function() {
  400. return annotationSources;
  401. };