kbn.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463
  1. define(['jquery', 'underscore','moment'],
  2. function($, _, moment) {
  3. 'use strict';
  4. var kbn = {};
  5. kbn.get_object_fields = function(obj) {
  6. var field_array = [];
  7. obj = kbn.flatten_json(obj._source);
  8. for (var field in obj) {
  9. field_array.push(field);
  10. }
  11. return field_array.sort();
  12. };
  13. kbn.get_all_fields = function(data) {
  14. var _d = data;
  15. var fields = [];
  16. _.each(_d,function(hit) {
  17. fields = _.uniq(fields.concat(_.keys(kbn.flatten_json(hit._source))));
  18. });
  19. // Remove stupid angular key
  20. fields = _.without(fields,'$$hashKey');
  21. return fields;
  22. };
  23. kbn.has_field = function(obj,field) {
  24. var obj_fields = kbn.get_object_fields(obj);
  25. if (_.inArray(obj_fields,field) < 0) {
  26. return false;
  27. } else {
  28. return true;
  29. }
  30. };
  31. kbn.get_related_fields = function(docs,field) {
  32. var field_array = [];
  33. _.each(docs, function(doc) {
  34. var keys = _.keys(doc);
  35. if(_.contains(keys,field)) {
  36. field_array = field_array.concat(keys);
  37. }
  38. });
  39. var counts = _.countBy(_.without(field_array,field),function(field){return field;});
  40. return _.map(counts, function(num, key){return {name:key,count:num};});
  41. };
  42. kbn.recurse_field_dots = function(object,field) {
  43. var value = null;
  44. var nested;
  45. if (typeof object[field] !== 'undefined') {
  46. value = object[field];
  47. }
  48. else if (nested = field.match(/(.*?)\.(.*)/)) {
  49. if(typeof object[nested[1]] !== 'undefined') {
  50. value = (typeof object[nested[1]][nested[2]] !== 'undefined') ?
  51. object[nested[1]][nested[2]] : kbn.recurse_field_dots(
  52. object[nested[1]],nested[2]);
  53. }
  54. }
  55. return value;
  56. };
  57. kbn.top_field_values = function(docs,field,count,grouped) {
  58. var all_values = _.pluck(docs,field),
  59. groups = {},
  60. counts,
  61. hasArrays;
  62. // manually grouping into pairs allows us to keep the original value,
  63. _.each(all_values, function (value) {
  64. var k;
  65. if(_.isArray(value)) {
  66. hasArrays = true;
  67. }
  68. if(_.isArray(value) && !grouped) {
  69. k = value;
  70. } else {
  71. k = _.isUndefined(value) ? '' : [value.toString()];
  72. }
  73. _.each(k, function(key) {
  74. if (_.has(groups, key)) {
  75. groups[key][1] ++;
  76. } else {
  77. groups[key] = [(grouped ? value : key), 1];
  78. }
  79. });
  80. });
  81. counts = _.values(groups).sort(function(a, b) {
  82. return a[1] - b[1];
  83. }).reverse().slice(0,count);
  84. return {
  85. counts: counts,
  86. hasArrays : hasArrays
  87. };
  88. };
  89. /**
  90. * Calculate a graph interval
  91. *
  92. * from:: Date object containing the start time
  93. * to:: Date object containing the finish time
  94. * size:: Calculate to approximately this many bars
  95. * user_interval:: User specified histogram interval
  96. *
  97. */
  98. kbn.calculate_interval = function(from,to,size,user_interval) {
  99. if(_.isObject(from)) {
  100. from = from.valueOf();
  101. }
  102. if(_.isObject(to)) {
  103. to = to.valueOf();
  104. }
  105. return user_interval === 0 ? kbn.round_interval((to - from)/size) : user_interval;
  106. };
  107. kbn.round_interval = function(interval) {
  108. switch (true) {
  109. // 0.5s
  110. case (interval <= 500):
  111. return 100; // 0.1s
  112. // 5s
  113. case (interval <= 5000):
  114. return 1000; // 1s
  115. // 7.5s
  116. case (interval <= 7500):
  117. return 5000; // 5s
  118. // 15s
  119. case (interval <= 15000):
  120. return 10000; // 10s
  121. // 45s
  122. case (interval <= 45000):
  123. return 30000; // 30s
  124. // 3m
  125. case (interval <= 180000):
  126. return 60000; // 1m
  127. // 9m
  128. case (interval <= 450000):
  129. return 300000; // 5m
  130. // 20m
  131. case (interval <= 1200000):
  132. return 600000; // 10m
  133. // 45m
  134. case (interval <= 2700000):
  135. return 1800000; // 30m
  136. // 2h
  137. case (interval <= 7200000):
  138. return 3600000; // 1h
  139. // 6h
  140. case (interval <= 21600000):
  141. return 10800000; // 3h
  142. // 24h
  143. case (interval <= 86400000):
  144. return 43200000; // 12h
  145. // 48h
  146. case (interval <= 172800000):
  147. return 86400000; // 24h
  148. // 1w
  149. case (interval <= 604800000):
  150. return 86400000; // 24h
  151. // 3w
  152. case (interval <= 1814400000):
  153. return 604800000; // 1w
  154. // 2y
  155. case (interval < 3628800000):
  156. return 2592000000; // 30d
  157. default:
  158. return 31536000000; // 1y
  159. }
  160. };
  161. kbn.secondsToHms = function(seconds){
  162. var numyears = Math.floor(seconds / 31536000);
  163. if(numyears){
  164. return numyears + 'y';
  165. }
  166. var numdays = Math.floor((seconds % 31536000) / 86400);
  167. if(numdays){
  168. return numdays + 'd';
  169. }
  170. var numhours = Math.floor(((seconds % 31536000) % 86400) / 3600);
  171. if(numhours){
  172. return numhours + 'h';
  173. }
  174. var numminutes = Math.floor((((seconds % 31536000) % 86400) % 3600) / 60);
  175. if(numminutes){
  176. return numminutes + 'm';
  177. }
  178. var numseconds = (((seconds % 31536000) % 86400) % 3600) % 60;
  179. if(numseconds){
  180. return numseconds + 's';
  181. }
  182. return 'less then a second'; //'just now' //or other string you like;
  183. };
  184. kbn.to_percent = function(number,outof) {
  185. return Math.floor((number/outof)*10000)/100 + "%";
  186. };
  187. kbn.addslashes = function(str) {
  188. str = str.replace(/\\/g, '\\\\');
  189. str = str.replace(/\'/g, '\\\'');
  190. str = str.replace(/\"/g, '\\"');
  191. str = str.replace(/\0/g, '\\0');
  192. return str;
  193. };
  194. kbn.interval_regex = /(\d+(?:\.\d+)?)([Mwdhmsy])/;
  195. // histogram & trends
  196. kbn.intervals_in_seconds = {
  197. y: 31536000,
  198. M: 2592000,
  199. w: 604800,
  200. d: 86400,
  201. h: 3600,
  202. m: 60,
  203. s: 1
  204. };
  205. kbn.describe_interval = function (string) {
  206. var matches = string.match(kbn.interval_regex);
  207. if (!matches || !_.has(kbn.intervals_in_seconds, matches[2])) {
  208. throw new Error('Invalid interval string, expexcting a number followed by one of "Mwdhmsy"');
  209. } else {
  210. return {
  211. sec: kbn.intervals_in_seconds[matches[2]],
  212. type: matches[2],
  213. count: parseInt(matches[1], 10)
  214. };
  215. }
  216. };
  217. kbn.interval_to_ms = function(string) {
  218. var info = kbn.describe_interval(string);
  219. return info.sec * 1000 * info.count;
  220. };
  221. kbn.interval_to_seconds = function (string) {
  222. var info = kbn.describe_interval(string);
  223. return info.sec * info.count;
  224. };
  225. // This should go away, moment.js can do this
  226. kbn.time_ago = function(string) {
  227. return new Date(new Date().getTime() - (kbn.interval_to_ms(string)));
  228. };
  229. /* This is a simplified version of elasticsearch's date parser */
  230. kbn.parseDate = function(text) {
  231. if(_.isDate(text)) {
  232. return text;
  233. }
  234. var time,
  235. mathString = "",
  236. index,
  237. parseString;
  238. if (text.substring(0,3) === "now") {
  239. time = new Date();
  240. mathString = text.substring("now".length);
  241. } else {
  242. index = text.indexOf("||");
  243. parseString;
  244. if (index === -1) {
  245. parseString = text;
  246. mathString = ""; // nothing else
  247. } else {
  248. parseString = text.substring(0, index);
  249. mathString = text.substring(index + 2);
  250. }
  251. // We're going to just require ISO8601 timestamps, k?
  252. time = new Date(parseString);
  253. }
  254. if (!mathString.length) {
  255. return time;
  256. }
  257. //return [time,parseString,mathString];
  258. return kbn.parseDateMath(mathString, time);
  259. };
  260. kbn.parseDateMath = function(mathString, time, roundUp) {
  261. var dateTime = moment(time);
  262. for (var i = 0; i < mathString.length; ) {
  263. var c = mathString.charAt(i++),
  264. type,
  265. num,
  266. unit;
  267. if (c === '/') {
  268. type = 0;
  269. } else if (c === '+') {
  270. type = 1;
  271. } else if (c === '-') {
  272. type = 2;
  273. } else {
  274. return false;
  275. }
  276. if (isNaN(mathString.charAt(i))) {
  277. num = 1;
  278. } else {
  279. var numFrom = i;
  280. while (!isNaN(mathString.charAt(i))) {
  281. i++;
  282. }
  283. num = parseInt(mathString.substring(numFrom, i),10);
  284. }
  285. if (type === 0) {
  286. // rounding is only allowed on whole numbers
  287. if (num !== 1) {
  288. return false;
  289. }
  290. }
  291. unit = mathString.charAt(i++);
  292. switch (unit) {
  293. case 'M':
  294. if (type === 0) {
  295. roundUp ? dateTime.endOf('month') : dateTime.startOf('month');
  296. } else if (type === 1) {
  297. dateTime.add('months',num);
  298. } else if (type === 2) {
  299. dateTime.subtract('months',num);
  300. }
  301. break;
  302. case 'w':
  303. if (type === 0) {
  304. roundUp ? dateTime.endOf('week') : dateTime.startOf('week');
  305. } else if (type === 1) {
  306. dateTime.add('weeks',num);
  307. } else if (type === 2) {
  308. dateTime.subtract('weeks',num);
  309. }
  310. break;
  311. case 'd':
  312. if (type === 0) {
  313. roundUp ? dateTime.endOf('day') : dateTime.startOf('day');
  314. } else if (type === 1) {
  315. dateTime.add('days',num);
  316. } else if (type === 2) {
  317. dateTime.subtract('days',num);
  318. }
  319. break;
  320. case 'h':
  321. case 'H':
  322. if (type === 0) {
  323. roundUp ? dateTime.endOf('hour') : dateTime.startOf('hour');
  324. } else if (type === 1) {
  325. dateTime.add('hours',num);
  326. } else if (type === 2) {
  327. dateTime.subtract('hours',num);
  328. }
  329. break;
  330. case 'm':
  331. if (type === 0) {
  332. roundUp ? dateTime.endOf('minute') : dateTime.startOf('minute');
  333. } else if (type === 1) {
  334. dateTime.add('minutes',num);
  335. } else if (type === 2) {
  336. dateTime.subtract('minutes',num);
  337. }
  338. break;
  339. case 's':
  340. if (type === 0) {
  341. roundUp ? dateTime.endOf('second') : dateTime.startOf('second');
  342. } else if (type === 1) {
  343. dateTime.add('seconds',num);
  344. } else if (type === 2) {
  345. dateTime.subtract('seconds',num);
  346. }
  347. break;
  348. default:
  349. return false;
  350. }
  351. }
  352. return dateTime.toDate();
  353. };
  354. // LOL. hahahahaha. DIE.
  355. kbn.flatten_json = function(object,root,array) {
  356. if (typeof array === 'undefined') {
  357. array = {};
  358. }
  359. if (typeof root === 'undefined') {
  360. root = '';
  361. }
  362. for(var index in object) {
  363. var obj = object[index];
  364. var rootname = root.length === 0 ? index : root + '.' + index;
  365. if(typeof obj === 'object' ) {
  366. if(_.isArray(obj)) {
  367. if(obj.length > 0 && typeof obj[0] === 'object') {
  368. var strval = '';
  369. for (var objidx = 0, objlen = obj.length; objidx < objlen; objidx++) {
  370. if (objidx > 0) {
  371. strval = strval + ', ';
  372. }
  373. strval = strval + JSON.stringify(obj[objidx]);
  374. }
  375. array[rootname] = strval;
  376. } else if(obj.length === 1 && _.isNumber(obj[0])) {
  377. array[rootname] = parseFloat(obj[0]);
  378. } else {
  379. array[rootname] = typeof obj === 'undefined' ? null : obj;
  380. }
  381. } else {
  382. kbn.flatten_json(obj,rootname,array);
  383. }
  384. } else {
  385. array[rootname] = typeof obj === 'undefined' ? null : obj;
  386. }
  387. }
  388. return kbn.sortObj(array);
  389. };
  390. kbn.xmlEnt = function(value) {
  391. if(_.isString(value)) {
  392. var stg1 = value.replace(/</g, '&lt;')
  393. .replace(/>/g, '&gt;')
  394. .replace(/\r\n/g, '<br/>')
  395. .replace(/\r/g, '<br/>')
  396. .replace(/\n/g, '<br/>')
  397. .replace(/\t/g, '&nbsp;&nbsp;&nbsp;&nbsp;')
  398. .replace(/ /g, '&nbsp;&nbsp;')
  399. .replace(/&lt;del&gt;/g, '<del>')
  400. .replace(/&lt;\/del&gt;/g, '</del>');
  401. return stg1;
  402. } else {
  403. return value;
  404. }
  405. };
  406. kbn.sortObj = function(arr) {
  407. // Setup Arrays
  408. var sortedKeys = [];
  409. var sortedObj = {};
  410. var i;
  411. // Separate keys and sort them
  412. for (i in arr) {
  413. sortedKeys.push(i);
  414. }
  415. sortedKeys.sort();
  416. // Reconstruct sorted obj based on keys
  417. for (i in sortedKeys) {
  418. sortedObj[sortedKeys[i]] = arr[sortedKeys[i]];
  419. }
  420. return sortedObj;
  421. };
  422. kbn.query_color_dot = function (color, diameter) {
  423. return '<div class="icon-circle" style="' + [
  424. 'display:inline-block',
  425. 'color:' + color,
  426. 'font-size:' + diameter + 'px',
  427. ].join(';') + '"></div>';
  428. };
  429. return kbn;
  430. });