module.js 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /*jshint globalstrict:true */
  2. /*global angular:true */
  3. /*
  4. ## Trends
  5. ### Parameters
  6. * style :: A hash of css styles
  7. * arrangement :: How should I arrange the query results? 'horizontal' or 'vertical'
  8. * ago :: Date math formatted time to look back
  9. */
  10. 'use strict';
  11. angular.module('kibana.trends', [])
  12. .controller('trends', function($scope, kbnIndex, querySrv, dashboard, filterSrv) {
  13. $scope.panelMeta = {
  14. editorTabs : [
  15. {title:'Queries', src:'partials/querySelect.html'}
  16. ],
  17. status : "Beta",
  18. description : "A stock-ticker style representation of how queries are moving over time. "+
  19. "For example, if the time is 1:10pm, your time picker was set to \"Last 10m\", and the \"Time "+
  20. "Ago\" parameter was set to '1h', the panel would show how much the query results have changed"+
  21. " since 12:00-12:10pm"
  22. };
  23. // Set and populate defaults
  24. var _d = {
  25. queries : {
  26. mode : 'all',
  27. ids : []
  28. },
  29. style : { "font-size": '14pt'},
  30. ago : '1d',
  31. arrangement : 'vertical',
  32. };
  33. _.defaults($scope.panel,_d);
  34. $scope.init = function () {
  35. $scope.hits = 0;
  36. $scope.$on('refresh',function(){$scope.get_data();});
  37. $scope.get_data();
  38. };
  39. $scope.get_data = function(segment,query_id) {
  40. delete $scope.panel.error;
  41. $scope.panelMeta.loading = true;
  42. // Make sure we have everything for the request to complete
  43. if(dashboard.indices.length === 0) {
  44. return;
  45. } else {
  46. $scope.index = segment > 0 ? $scope.index : dashboard.indices;
  47. }
  48. $scope.panel.queries.ids = querySrv.idsByMode($scope.panel.queries);
  49. // Determine a time field
  50. var timeField = _.uniq(_.pluck(filterSrv.getByType('time'),'field'));
  51. if(timeField.length > 1) {
  52. $scope.panel.error = "Time field must be consistent amongst time filters";
  53. return;
  54. } else if(timeField.length === 0) {
  55. $scope.panel.error = "A time filter must exist for this panel to function";
  56. return;
  57. } else {
  58. timeField = timeField[0];
  59. }
  60. $scope.time = filterSrv.timeRange('min');
  61. $scope.old_time = {
  62. from : new Date($scope.time.from.getTime() - kbn.interval_to_seconds($scope.panel.ago)*1000),
  63. to : new Date($scope.time.to.getTime() - kbn.interval_to_seconds($scope.panel.ago)*1000)
  64. };
  65. var _segment = _.isUndefined(segment) ? 0 : segment;
  66. var request = $scope.ejs.Request();
  67. var _ids_without_time = _.difference(filterSrv.ids,filterSrv.idsByType('time'));
  68. // Build the question part of the query
  69. _.each($scope.panel.queries.ids, function(id) {
  70. var q = $scope.ejs.FilteredQuery(
  71. querySrv.getEjsObj(id),
  72. filterSrv.getBoolFilter(_ids_without_time).must(
  73. $scope.ejs.RangeFilter(timeField)
  74. .from($scope.time.from)
  75. .to($scope.time.to)
  76. ));
  77. request = request
  78. .facet($scope.ejs.QueryFacet(id)
  79. .query(q)
  80. ).size(0);
  81. });
  82. // And again for the old time period
  83. _.each($scope.panel.queries.ids, function(id) {
  84. var q = $scope.ejs.FilteredQuery(
  85. querySrv.getEjsObj(id),
  86. filterSrv.getBoolFilter(_ids_without_time).must(
  87. $scope.ejs.RangeFilter(timeField)
  88. .from($scope.old_time.from)
  89. .to($scope.old_time.to)
  90. ));
  91. request = request
  92. .facet($scope.ejs.QueryFacet("old_"+id)
  93. .query(q)
  94. ).size(0);
  95. });
  96. // TODO: Spy for trend panel
  97. //$scope.populate_modal(request);
  98. // If we're on the first segment we need to get our indices
  99. if (_segment === 0) {
  100. kbnIndex.indices(
  101. $scope.old_time.from,
  102. $scope.old_time.to,
  103. dashboard.current.index.pattern,
  104. dashboard.current.index.interval
  105. ).then(function (p) {
  106. $scope.index = _.union(p,$scope.index);
  107. request = request.indices($scope.index[_segment]);
  108. process_results(request.doSearch(),_segment,query_id);
  109. });
  110. } else {
  111. process_results(request.indices($scope.index[_segment]).doSearch(),_segment,query_id);
  112. }
  113. };
  114. // Populate scope when we have results
  115. var process_results = function(results,_segment,query_id) {
  116. results.then(function(results) {
  117. $scope.panelMeta.loading = false;
  118. if(_segment === 0) {
  119. $scope.hits = {};
  120. $scope.data = [];
  121. query_id = $scope.query_id = new Date().getTime();
  122. }
  123. // Check for error and abort if found
  124. if(!(_.isUndefined(results.error))) {
  125. $scope.panel.error = $scope.parse_error(results.error);
  126. return;
  127. }
  128. // Convert facet ids to numbers
  129. var facetIds = _.map(_.keys(results.facets),function(k){if(!isNaN(k)){return parseInt(k, 10);}});
  130. // Make sure we're still on the same query/queries
  131. if($scope.query_id === query_id &&
  132. _.intersection(facetIds,$scope.panel.queries.ids).length === $scope.panel.queries.ids.length
  133. ) {
  134. var i = 0;
  135. _.each($scope.panel.queries.ids, function(id) {
  136. var v = results.facets[id];
  137. var n = results.facets[id].count;
  138. var o = results.facets['old_'+id].count;
  139. var hits = {
  140. new : _.isUndefined($scope.data[i]) || _segment === 0 ? n : $scope.data[i].hits.new+n,
  141. old : _.isUndefined($scope.data[i]) || _segment === 0 ? o : $scope.data[i].hits.old+o
  142. };
  143. $scope.hits.new += n;
  144. $scope.hits.old += o;
  145. var percent = percentage(hits.old,hits.new) == null ?
  146. '?' : Math.round(percentage(hits.old,hits.new)*100)/100;
  147. // Create series
  148. $scope.data[i] = {
  149. info: querySrv.list[id],
  150. hits: {
  151. new : hits.new,
  152. old : hits.old
  153. },
  154. percent: percent
  155. };
  156. i++;
  157. });
  158. $scope.$emit('render');
  159. if(_segment < $scope.index.length-1) {
  160. $scope.get_data(_segment+1,query_id);
  161. } else {
  162. $scope.trends = $scope.data;
  163. }
  164. }
  165. });
  166. };
  167. function percentage(x,y) {
  168. return x === 0 ? null : 100*(y-x)/x;
  169. }
  170. $scope.set_refresh = function (state) {
  171. $scope.refresh = state;
  172. };
  173. $scope.close_edit = function() {
  174. if($scope.refresh) {
  175. $scope.get_data();
  176. }
  177. $scope.refresh = false;
  178. $scope.$emit('render');
  179. };
  180. });