module.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. angular.module('kibana.dashcontrol', [])
  2. .controller('dashcontrol', function($scope, $routeParams, $http, eventBus, timer) {
  3. $scope.panel = $scope.panel || {};
  4. // Set and populate defaults
  5. var _d = {
  6. group : "default",
  7. save : {
  8. gist: false,
  9. elasticsearch: true,
  10. local: true,
  11. 'default': true
  12. },
  13. load : {
  14. gist: true,
  15. elasticsearch: true,
  16. local: true,
  17. },
  18. hide_control: false,
  19. elasticsearch_size: 20,
  20. elasticsearch_saveto: $scope.config.kibana_index,
  21. temp: true,
  22. temp_ttl: '30d',
  23. }
  24. _.defaults($scope.panel,_d);
  25. // A hash of defaults for the dashboard object
  26. var _dash = {
  27. title: "",
  28. editable: true,
  29. rows: [],
  30. }
  31. $scope.init = function() {
  32. // Long ugly if statement for figuring out which dashboard to load on init
  33. // If there is no dashboard defined, find one
  34. if(_.isUndefined($scope.dashboards)) {
  35. // First check the URL for a path to a dashboard
  36. if(!(_.isUndefined($routeParams.type)) && !(_.isUndefined($routeParams.id))) {
  37. var _type = $routeParams.type;
  38. var _id = $routeParams.id;
  39. if(_type === 'elasticsearch')
  40. $scope.elasticsearch_load('dashboard',_id)
  41. if(_type === 'temp')
  42. $scope.elasticsearch_load('temp',_id)
  43. if(_type === 'file')
  44. $scope.file_load(_id)
  45. // No dashboard in the URL
  46. } else {
  47. // Check if browser supports localstorage, and if there's a dashboard
  48. if (Modernizr.localstorage &&
  49. !(_.isUndefined(localStorage['dashboard'])) &&
  50. localStorage['dashboard'] !== ''
  51. ) {
  52. var dashboard = JSON.parse(localStorage['dashboard']);
  53. _.defaults(dashboard,_dash);
  54. $scope.dash_load(JSON.stringify(dashboard))
  55. // No? Ok, grab default.json, its all we have now
  56. } else {
  57. $scope.file_load('default')
  58. }
  59. }
  60. }
  61. $scope.gist_pattern = /(^\d{5,}$)|(^[a-z0-9]{10,}$)|(gist.github.com(\/*.*)\/[a-z0-9]{5,}\/*$)/;
  62. $scope.gist = {};
  63. $scope.elasticsearch = {};
  64. }
  65. $scope.export = function() {
  66. var blob = new Blob([angular.toJson($scope.dashboards,true)], {type: "application/json;charset=utf-8"});
  67. saveAs(blob, $scope.dashboards.title+"-"+new Date().getTime());
  68. }
  69. $scope.default = function() {
  70. if (Modernizr.localstorage) {
  71. localStorage['dashboard'] = angular.toJson($scope.dashboards);
  72. $scope.alert('Success',
  73. $scope.dashboards.title + " has been set as your default dashboard",
  74. 'success',5000)
  75. } else {
  76. $scope.alert('Bummer!',
  77. "Your browser is too old for this functionality",
  78. 'error',5000);
  79. }
  80. }
  81. $scope.share_link = function(title,type,id) {
  82. $scope.share = {
  83. location : location.href.replace(location.hash,""),
  84. type : type,
  85. id : id,
  86. link : location.href.replace(location.hash,"")+"#dashboard/"+type+"/"+id,
  87. title : title,
  88. };
  89. }
  90. $scope.purge = function() {
  91. if (Modernizr.localstorage) {
  92. localStorage['dashboard'] = '';
  93. $scope.alert('Success',
  94. 'Default dashboard cleared',
  95. 'success',5000)
  96. } else {
  97. $scope.alert('Doh!',
  98. "Your browser is too old for this functionality",
  99. 'error',5000);
  100. }
  101. }
  102. $scope.file_load = function(file) {
  103. $http({
  104. url: "dashboards/default",
  105. method: "GET",
  106. }).success(function(data, status, headers, config) {
  107. var dashboard = data
  108. _.defaults(dashboard,_dash);
  109. $scope.dash_load(JSON.stringify(dashboard))
  110. }).error(function(data, status, headers, config) {
  111. $scope.alert('Default dashboard missing!','Could not locate dashboards/'+file,'error')
  112. });
  113. }
  114. $scope.elasticsearch_save = function(type) {
  115. // Clone object so we can modify it without influencing the existing obejct
  116. if($scope.panel.hide_control) {
  117. $scope.panel.hide = true;
  118. var save = _.clone($scope.dashboards)
  119. } else {
  120. var save = _.clone($scope.dashboards)
  121. }
  122. // Change title on object clone
  123. if(type === 'dashboard')
  124. var id = save.title = $scope.elasticsearch.title;
  125. // Create request with id as title. Rethink this.
  126. var request = $scope.ejs.Document($scope.panel.elasticsearch_saveto,type,id).source({
  127. user: 'guest',
  128. group: 'guest',
  129. title: save.title,
  130. dashboard: angular.toJson(save)
  131. })
  132. if(type === 'temp')
  133. request = request.ttl($scope.panel.temp_ttl)
  134. var result = request.doIndex();
  135. var id = result.then(function(result) {
  136. $scope.alert('Dashboard Saved','This dashboard has been saved to Elasticsearch','success',5000)
  137. $scope.elasticsearch_dblist($scope.elasticsearch.query);
  138. $scope.elasticsearch.title = '';
  139. if(type === 'temp')
  140. $scope.share_link($scope.dashboards.title,'temp',result._id)
  141. })
  142. $scope.panel.hide = false;
  143. }
  144. $scope.elasticsearch_delete = function(dashboard) {
  145. var result = $scope.ejs.Document($scope.panel.elasticsearch_saveto,'dashboard',dashboard._id).doDelete();
  146. result.then(function(result) {
  147. $scope.alert('Dashboard Deleted','','success',5000)
  148. $scope.elasticsearch.dashboards = _.without($scope.elasticsearch.dashboards,dashboard)
  149. })
  150. }
  151. $scope.elasticsearch_load = function(type,id) {
  152. var request = $scope.ejs.Request().indices($scope.panel.elasticsearch_saveto).types(type);
  153. var results = request.query(
  154. $scope.ejs.IdsQuery(id)
  155. ).size($scope.panel.elasticsearch_size).doSearch();
  156. results.then(function(results) {
  157. if(_.isUndefined(results)) {
  158. $scope.panel.error = 'Your query was unsuccessful';
  159. return;
  160. }
  161. $scope.panel.error = false;
  162. $scope.dash_load(results.hits.hits[0]['_source']['dashboard'])
  163. });
  164. }
  165. $scope.elasticsearch_dblist = function(query) {
  166. if($scope.panel.load.elasticsearch) {
  167. var request = $scope.ejs.Request().indices($scope.panel.elasticsearch_saveto).types('dashboard');
  168. var results = request.query(
  169. $scope.ejs.QueryStringQuery(query || '*')
  170. ).size($scope.panel.elasticsearch_size).doSearch();
  171. results.then(function(results) {
  172. if(_.isUndefined(results)) {
  173. $scope.panel.error = 'Your query was unsuccessful';
  174. return;
  175. }
  176. $scope.panel.error = false;
  177. $scope.hits = results.hits.total;
  178. $scope.elasticsearch.dashboards = results.hits.hits
  179. });
  180. }
  181. }
  182. $scope.save_gist = function() {
  183. var save = _.clone($scope.dashboards)
  184. save.title = $scope.gist.title;
  185. $http({
  186. url: "https://api.github.com/gists",
  187. method: "POST",
  188. data: {
  189. "description": save.title,
  190. "public": false,
  191. "files": {
  192. "kibana-dashboard.json": {
  193. "content": angular.toJson(save,true)
  194. }
  195. }
  196. }
  197. }).success(function(data, status, headers, config) {
  198. $scope.gist.last = data.html_url;
  199. $scope.alert('Gist saved','You will be able to access your exported dashboard file at <a href="'+data.html_url+'">'+data.html_url+'</a> in a moment','success')
  200. }).error(function(data, status, headers, config) {
  201. $scope.alert('Unable to save','Save to gist failed for some reason','error',5000)
  202. });
  203. }
  204. $scope.gist_dblist = function(id) {
  205. $http.jsonp("https://api.github.com/gists/"+id+"?callback=JSON_CALLBACK"
  206. ).success(function(response) {
  207. $scope.gist.files = []
  208. _.each(response.data.files,function(v,k) {
  209. try {
  210. var file = JSON.parse(v.content)
  211. $scope.gist.files.push(file)
  212. } catch(e) {
  213. $scope.alert('Gist failure','The dashboard file is invalid','warning',5000)
  214. }
  215. });
  216. }).error(function(data, status, headers, config) {
  217. $scope.alert('Gist Failed','Could not retrieve dashboard list from gist','error',5000)
  218. });
  219. }
  220. $scope.dash_load = function(dashboard) {
  221. if(!_.isObject(dashboard))
  222. dashboard = JSON.parse(dashboard)
  223. eventBus.broadcast($scope.$id,'ALL','dashboard',dashboard)
  224. timer.cancel_all();
  225. }
  226. $scope.gist_id = function(string) {
  227. if($scope.is_gist(string))
  228. return string.match($scope.gist_pattern)[0].replace(/.*\//, '');
  229. }
  230. $scope.is_gist = function(string) {
  231. if(!_.isUndefined(string) && string != '' && !_.isNull(string.match($scope.gist_pattern)))
  232. return string.match($scope.gist_pattern).length > 0 ? true : false;
  233. else
  234. return false
  235. }
  236. })
  237. .directive('dashUpload', function(timer, eventBus){
  238. return {
  239. restrict: 'A',
  240. link: function(scope, elem, attrs) {
  241. function file_selected(evt) {
  242. var files = evt.target.files; // FileList object
  243. // files is a FileList of File objects. List some properties.
  244. var output = [];
  245. for (var i = 0, f; f = files[i]; i++) {
  246. var reader = new FileReader();
  247. reader.onload = (function(theFile) {
  248. return function(e) {
  249. scope.dash_load(JSON.parse(e.target.result))
  250. scope.$apply();
  251. };
  252. })(f);
  253. reader.readAsText(f);
  254. }
  255. }
  256. // Check for the various File API support.
  257. if (window.File && window.FileReader && window.FileList && window.Blob) {
  258. // Something
  259. document.getElementById('dashupload').addEventListener('change', file_selected, false);
  260. } else {
  261. alert('Sorry, the HTML5 File APIs are not fully supported in this browser.');
  262. }
  263. }
  264. }
  265. }).filter('gistid', function() {
  266. var gist_pattern = /(\d{5,})|([a-z0-9]{10,})|(gist.github.com(\/*.*)\/[a-z0-9]{5,}\/*$)/;
  267. return function(input, scope) {
  268. //return input+"boners"
  269. if(!(_.isUndefined(input))) {
  270. var output = input.match(gist_pattern);
  271. if(!_.isNull(output) && !_.isUndefined(output))
  272. return output[0].replace(/.*\//, '');
  273. }
  274. }
  275. });;