helper.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one
  3. * or more contributor license agreements. See the NOTICE file
  4. * distributed with this work for additional information
  5. * regarding copyright ownership. The ASF licenses this file
  6. * to you under the Apache License, Version 2.0 (the
  7. * "License"); you may not use this file except in compliance
  8. * with the License. You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. */
  18. String.prototype.trim = function () {
  19. return this.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
  20. };
  21. String.prototype.endsWith = function(suffix) {
  22. return this.indexOf(suffix, this.length - suffix.length) !== -1;
  23. };
  24. String.prototype.startsWith = function (prefix){
  25. return this.indexOf(prefix) == 0;
  26. };
  27. String.prototype.contains = function(substring) {
  28. return this.indexOf(substring) != -1;
  29. };
  30. String.prototype.capitalize = function () {
  31. return this.charAt(0).toUpperCase() + this.slice(1);
  32. };
  33. // Use: stringvalue.findIn(multi_dimensional_array_or_object)
  34. /***Example:
  35. var tofind = 'emotion';
  36. var person = {'name': 'Bob Loblaw', 'age': '28', 'personality': {'smart': 'yes', 'funny': 'yes', 'emotion': 'happy'} };
  37. tofind.findIn(person)
  38. ***/
  39. String.prototype.findIn = function (multi) {
  40. multi = multi || '';
  41. var val = this.valueOf();
  42. if(typeof multi == 'object' || typeof multi == 'array')
  43. {
  44. if(val in multi)
  45. {
  46. return multi[val];
  47. }
  48. else
  49. {
  50. for(var x in multi)
  51. {
  52. var found = this.findIn(multi[x]);
  53. if(found != false)
  54. {
  55. return found;
  56. }
  57. }
  58. }
  59. }
  60. return false;
  61. };
  62. /**
  63. * Replace {i} with argument. where i is number of argument to replace with
  64. * @return {String}
  65. */
  66. String.prototype.format = function () {
  67. var args = arguments;
  68. return this.replace(/{(\d+)}/g, function (match, number) {
  69. return typeof args[number] != 'undefined' ? args[number] : match;
  70. });
  71. };
  72. String.prototype.highlight = function (words, highlightTemplate) {
  73. var self = this;
  74. highlightTemplate = highlightTemplate ? highlightTemplate : "<b>{0}</b>";
  75. words.forEach(function (word) {
  76. var searchRegExp = new RegExp("\\b" + word + "\\b", "gi");
  77. self = self.replace(searchRegExp, function (found) {
  78. return highlightTemplate.format(found);
  79. });
  80. });
  81. return self;
  82. };
  83. Number.prototype.toDaysHoursMinutes = function () {
  84. var formatted = {},
  85. dateDiff = this,
  86. secK = 1000, //ms
  87. minK = 60 * secK, // sec
  88. hourK = 60 * minK, // sec
  89. dayK = 24 * hourK;
  90. dateDiff = parseInt(dateDiff);
  91. formatted.d = Math.floor(dateDiff / dayK);
  92. dateDiff -= formatted.d * dayK;
  93. formatted.h = Math.floor(dateDiff / hourK);
  94. dateDiff -= formatted.h * hourK;
  95. formatted.m = (dateDiff / minK).toFixed(2);
  96. return formatted;
  97. };
  98. /**
  99. Sort an array by the key specified in the argument.
  100. Handle only native js objects as element of array, not the Ember's object.
  101. Can be used as alternative to sortProperty method of Ember library
  102. in order to speed up executing on large data volumes
  103. @method sortBy
  104. @param {String} path name(s) to sort on
  105. @return {Array} The sorted array.
  106. */
  107. Array.prototype.sortPropertyLight = function (path) {
  108. var realPath = (typeof path === "string") ? path.split('.') : [];
  109. this.sort(function (a, b) {
  110. var aProperty = a;
  111. var bProperty = b;
  112. realPath.forEach(function (key) {
  113. aProperty = aProperty[key];
  114. bProperty = bProperty[key];
  115. });
  116. if (aProperty > bProperty) return 1;
  117. if (aProperty < bProperty) return -1;
  118. return 0;
  119. });
  120. return this;
  121. };
  122. Em.CoreObject.reopen({
  123. t:function (key, attrs) {
  124. return Em.I18n.t(key, attrs)
  125. }
  126. });
  127. Em.Handlebars.registerHelper('log', function (variable) {
  128. console.log(variable);
  129. });
  130. Em.Handlebars.registerHelper('warn', function (variable) {
  131. console.warn(variable);
  132. });
  133. Em.Handlebars.registerHelper('highlight', function (property, words, fn) {
  134. var context = (fn.contexts && fn.contexts[0]) || this;
  135. property = Em.Handlebars.getPath(context, property, fn);
  136. words = words.split(";");
  137. // if (highlightTemplate == undefined) {
  138. var highlightTemplate = "<b>{0}</b>";
  139. // }
  140. words.forEach(function (word) {
  141. var searchRegExp = new RegExp("\\b" + word + "\\b", "gi");
  142. property = property.replace(searchRegExp, function (found) {
  143. return highlightTemplate.format(found);
  144. });
  145. });
  146. return new Em.Handlebars.SafeString(property);
  147. });
  148. App = require('app');
  149. /**
  150. * Certain variables can have JSON in string
  151. * format, or in JSON format itself.
  152. */
  153. App.parseJSON = function (value) {
  154. if (typeof value == "string") {
  155. return jQuery.parseJSON(value);
  156. }
  157. return value;
  158. };
  159. /**
  160. * Check for empty <code>Object</code>, built in Em.isEmpty()
  161. * doesn't support <code>Object</code> type
  162. *
  163. * @params obj {Object}
  164. *
  165. * @return {Boolean}
  166. */
  167. App.isEmptyObject = function(obj) {
  168. var empty = true;
  169. for (var prop in obj) { if (obj.hasOwnProperty(prop)) {empty = false; break;} }
  170. return empty;
  171. }
  172. App.format = {
  173. /**
  174. * @type Object
  175. */
  176. components: {
  177. 'APP_TIMELINE_SERVER': 'App Timeline Server',
  178. 'DATANODE': 'DataNode',
  179. 'DECOMMISSION_DATANODE': 'Update Exclude File',
  180. 'DRPC_SERVER': 'DRPC Server',
  181. 'FALCON': 'Falcon',
  182. 'FALCON_CLIENT': 'Falcon Client',
  183. 'FALCON_SERVER': 'Falcon Server',
  184. 'FALCON_SERVICE_CHECK': 'Falcon Service Check',
  185. 'FLUME_SERVER': 'Flume Agent',
  186. 'GANGLIA_MONITOR': 'Ganglia Monitor',
  187. 'GANGLIA_SERVER': 'Ganglia Server',
  188. 'GLUSTERFS_CLIENT': 'GLUSTERFS Client',
  189. 'GLUSTERFS_SERVICE_CHECK': 'GLUSTERFS Service Check',
  190. 'GMETAD_SERVICE_CHECK': 'Gmetad Service Check',
  191. 'GMOND_SERVICE_CHECK': 'Gmond Service Check',
  192. 'HADOOP_CLIENT': 'Hadoop Client',
  193. 'HBASE_CLIENT': 'HBase Client',
  194. 'HBASE_MASTER': 'HBase Master',
  195. 'HBASE_REGIONSERVER': 'HBase RegionServer',
  196. 'HBASE_SERVICE_CHECK': 'HBase Service Check',
  197. 'HCAT': 'HCat',
  198. 'HCAT_SERVICE_CHECK': 'HCat Service Check',
  199. 'HDFS_CLIENT': 'HDFS Client',
  200. 'HDFS_SERVICE_CHECK': 'HDFS Service Check',
  201. 'HISTORYSERVER': 'History Server',
  202. 'HIVE_CLIENT': 'Hive Client',
  203. 'HIVE_METASTORE': 'Hive Metastore',
  204. 'HIVE_SERVER': 'HiveServer2',
  205. 'HIVE_SERVICE_CHECK': 'Hive Service Check',
  206. 'HUE_SERVER': 'Hue Server',
  207. 'JAVA_JCE': 'Java JCE',
  208. 'JOBTRACKER': 'JobTracker',
  209. 'JOBTRACKER_SERVICE_CHECK': 'JobTracker Service Check',
  210. 'JOURNALNODE': 'JournalNode',
  211. 'KERBEROS_ADMIN_CLIENT': 'Kerberos Admin Client',
  212. 'KERBEROS_CLIENT': 'Kerberos Client',
  213. 'KERBEROS_SERVER': 'Kerberos Server',
  214. 'MAPREDUCE2_CLIENT': 'MapReduce2 Client',
  215. 'MAPREDUCE2_SERVICE_CHECK': 'MapReduce2 Service Check',
  216. 'MAPREDUCE_CLIENT': 'MapReduce Client',
  217. 'MAPREDUCE_SERVICE_CHECK': 'MapReduce Service Check',
  218. 'MYSQL_SERVER': 'MySQL Server',
  219. 'NAGIOS_SERVER': 'Nagios Server',
  220. 'NAMENODE': 'NameNode',
  221. 'NAMENODE_SERVICE_CHECK': 'NameNode Service Check',
  222. 'NIMBUS': 'Nimbus',
  223. 'NODEMANAGER': 'NodeManager',
  224. 'OOZIE_CLIENT': 'Oozie Client',
  225. 'OOZIE_SERVER': 'Oozie Server',
  226. 'OOZIE_SERVICE_CHECK': 'Oozie Service Check',
  227. 'PIG': 'Pig',
  228. 'PIG_SERVICE_CHECK': 'Pig Service Check',
  229. 'RESOURCEMANAGER': 'ResourceManager',
  230. 'SECONDARY_NAMENODE': 'SNameNode',
  231. 'SQOOP': 'Sqoop',
  232. 'SQOOP_SERVICE_CHECK': 'Sqoop Service Check',
  233. 'STORM_REST_API': 'Storm REST API Server',
  234. 'STORM_SERVICE_CHECK': 'Storm Service Check',
  235. 'STORM_UI_SERVER': 'Storm UI Server',
  236. 'SUPERVISOR': 'Supervisor',
  237. 'TASKTRACKER': 'TaskTracker',
  238. 'TEZ_CLIENT': 'Tez Client',
  239. 'WEBHCAT_SERVER': 'WebHCat Server',
  240. 'WEBHCAT_SERVICE_CHECK': 'WebHCat Service Check',
  241. 'YARN_CLIENT': 'YARN Client',
  242. 'YARN_SERVICE_CHECK': 'YARN Service Check',
  243. 'ZKFC': 'ZKFailoverController',
  244. 'ZOOKEEPER_CLIENT': 'ZooKeeper Client',
  245. 'ZOOKEEPER_QUORUM_SERVICE_CHECK': 'ZK Quorum Service Check',
  246. 'ZOOKEEPER_SERVER': 'ZooKeeper Server',
  247. 'ZOOKEEPER_SERVICE_CHECK': 'ZooKeeper Service Check',
  248. 'CLIENT': 'client'
  249. },
  250. /**
  251. * @type Object
  252. */
  253. command: {
  254. 'INSTALL': 'Install',
  255. 'UNINSTALL': 'Uninstall',
  256. 'START': 'Start',
  257. 'STOP': 'Stop',
  258. 'EXECUTE': 'Execute',
  259. 'ABORT': 'Abort',
  260. 'UPGRADE': 'Upgrade',
  261. 'RESTART': 'Restart',
  262. 'SERVICE_CHECK': 'Check',
  263. 'Excluded:': 'Decommission:',
  264. 'Included:': 'Recommission:'
  265. },
  266. /**
  267. * convert role to readable string
  268. * @param role
  269. */
  270. role:function (role) {
  271. return this.components[role] ? this.components[role] : '';
  272. },
  273. /**
  274. * convert command_detail to readable string, show the string for all tasks name
  275. * @param command_detail
  276. */
  277. commandDetail: function (command_detail) {
  278. var detailArr = command_detail.split(' ');
  279. var self = this;
  280. var result = '';
  281. detailArr.forEach( function(item) {
  282. // if the item has the pattern SERVICE/COMPONENT, drop the SERVICE part
  283. if (item.contains('/')) {
  284. item = item.split('/')[1];
  285. }
  286. // ignore 'DECOMMISSION', command came from 'excluded/included'
  287. if (item == 'DECOMMISSION,') {
  288. item = '';
  289. }
  290. if (self.components[item]) {
  291. result = result + ' ' + self.components[item];
  292. } else if (self.command[item]) {
  293. result = result + ' ' + self.command[item];
  294. } else {
  295. result = result + ' ' + item;
  296. }
  297. });
  298. if (result === ' nagios_update_ignore ACTIONEXECUTE') {
  299. result = Em.I18n.t('common.maintenance.task');
  300. }
  301. return result;
  302. },
  303. /**
  304. * PENDING - Not queued yet for a host
  305. * QUEUED - Queued for a host
  306. * IN_PROGRESS - Host reported it is working
  307. * COMPLETED - Host reported success
  308. * FAILED - Failed
  309. * TIMEDOUT - Host did not respond in time
  310. * ABORTED - Operation was abandoned
  311. */
  312. taskStatus:function (_taskStatus) {
  313. return _taskStatus.toLowerCase();
  314. }
  315. };
  316. /**
  317. * wrapper to bootstrap popover
  318. * fix issue when popover stuck on view routing
  319. * @param self
  320. * @param options
  321. */
  322. App.popover = function(self, options) {
  323. self.popover(options);
  324. self.on("remove", function () {
  325. $(this).trigger('mouseleave');
  326. });
  327. };
  328. /**
  329. * wrapper to bootstrap tooltip
  330. * fix issue when tooltip stuck on view routing
  331. * @param self - DOM element
  332. * @param options
  333. */
  334. App.tooltip = function(self, options) {
  335. self.tooltip(options);
  336. self.on("remove", function () {
  337. $(this).trigger('mouseleave');
  338. });
  339. };
  340. /**
  341. * wrapper to Date().getTime()
  342. * fix issue when client clock and server clock not sync
  343. * @return timeStamp of current server clock
  344. */
  345. App.dateTime = function() {
  346. return new Date().getTime() + App.clockDistance;
  347. };
  348. /*
  349. * Helper function for bound property helper registration
  350. * @params name {String} - name of helper
  351. * @params view {Em.View} - view
  352. */
  353. App.registerBoundHelper = function(name, view) {
  354. Em.Handlebars.registerHelper(name, function(property, options) {
  355. options.hash.contentBinding = property;
  356. return Em.Handlebars.helpers.view.call(this, view, options);
  357. });
  358. };
  359. /*
  360. * Return singular or plural word based on Em.I18n property key.
  361. *
  362. * Example: {{pluralize hostsCount singular="t:host" plural="t:hosts"}}
  363. */
  364. App.registerBoundHelper('pluralize', Em.View.extend({
  365. tagName: 'span',
  366. template: Em.Handlebars.compile('{{view.wordOut}}'),
  367. wordOut: function() {
  368. var count, singular, plural;
  369. count = this.get('content');
  370. singular = this.get('singular');
  371. plural = this.get('plural');
  372. return this.getWord(count, singular, plural);
  373. }.property('content'),
  374. getWord: function(count, singular, plural) {
  375. singular = this.tDetect(singular);
  376. plural = this.tDetect(plural);
  377. if (singular && plural) {
  378. if (count > 1) {
  379. return plural;
  380. } else {
  381. return singular;
  382. }
  383. }
  384. return '';
  385. },
  386. /*
  387. * Detect for Em.I18n.t reference call
  388. * @params word {String}
  389. * return {String}
  390. */
  391. tDetect: function(word) {
  392. var splitted = word.split(':');
  393. if (splitted.length > 1 && splitted[0] == 't') {
  394. return Em.I18n.t(splitted[1]);
  395. } else {
  396. return splitted[0];
  397. }
  398. }
  399. })
  400. );
  401. /**
  402. * Return defined string instead of empty if value is null/undefined
  403. * by default is `n/a`.
  404. *
  405. * @param empty {String} - value instead of empty string (not required)
  406. * can be used with Em.I18n pass value started with't:'
  407. *
  408. * Examples:
  409. *
  410. * default value will be returned
  411. * {{formatNull service.someValue}}
  412. *
  413. * <code>empty<code> will be returned
  414. * {{formatNull service.someValue empty="I'm empty"}}
  415. *
  416. * Em.I18n translation will be returned
  417. * {{formatNull service.someValue empty="t:my.key.to.translate"
  418. */
  419. App.registerBoundHelper('formatNull', Em.View.extend({
  420. tagName: 'span',
  421. template: Em.Handlebars.compile('{{view.result}}'),
  422. result: function() {
  423. var emptyValue = this.get('empty') ? this.get('empty') : Em.I18n.t('services.service.summary.notAvailable');
  424. emptyValue = emptyValue.startsWith('t:') ? Em.I18n.t(emptyValue.substr(2, emptyValue.length)) : emptyValue;
  425. return (this.get('content') || this.get('content') == 0) ? this.get('content') : emptyValue;
  426. }.property('content')
  427. }));
  428. /**
  429. * Return formatted string with inserted <code>wbr</code>-tag after each dot
  430. *
  431. * @param {String} content
  432. *
  433. * Examples:
  434. *
  435. * returns 'apple'
  436. * {{formatWordBreak 'apple'}}
  437. *
  438. * returns 'apple.<wbr />banana'
  439. * {{formatWordBreak 'apple.banana'}}
  440. *
  441. * returns 'apple.<wbr />banana.<wbr />uranium'
  442. * {{formatWordBreak 'apple.banana.uranium'}}
  443. */
  444. App.registerBoundHelper('formatWordBreak', Em.View.extend({
  445. tagName: 'span',
  446. template: Em.Handlebars.compile('{{{view.result}}}'),
  447. /**
  448. * @type {string}
  449. */
  450. result: function() {
  451. return this.get('content').replace(/\./g, '.<wbr />');
  452. }.property('content')
  453. }));
  454. /**
  455. * Ambari overrides the default date transformer.
  456. * This is done because of the non-standard data
  457. * sent. For example Nagios sends date as "12345678".
  458. * The problem is that it is a String and is represented
  459. * only in seconds whereas Javascript's Date needs
  460. * milliseconds representation.
  461. */
  462. DS.attr.transforms.date = {
  463. from: function (serialized) {
  464. var type = typeof serialized;
  465. if (type === Em.I18n.t('common.type.string')) {
  466. serialized = parseInt(serialized);
  467. type = typeof serialized;
  468. }
  469. if (type === Em.I18n.t('common.type.number')) {
  470. if (!serialized ){ //serialized timestamp = 0;
  471. return 0;
  472. }
  473. // The number could be seconds or milliseconds.
  474. // If seconds, then the length is 10
  475. // If milliseconds, the length is 13
  476. if (serialized.toString().length < 13) {
  477. serialized = serialized * 1000;
  478. }
  479. return new Date(serialized);
  480. } else if (serialized === null || serialized === undefined) {
  481. // if the value is not present in the data,
  482. // return undefined, not null.
  483. return serialized;
  484. } else {
  485. return null;
  486. }
  487. },
  488. to: function (deserialized) {
  489. if (deserialized instanceof Date) {
  490. return deserialized.getTime();
  491. } else if (deserialized === undefined) {
  492. return undefined;
  493. } else {
  494. return null;
  495. }
  496. }
  497. };
  498. DS.attr.transforms.object = {
  499. from: function(serialized) {
  500. return Ember.none(serialized) ? null : Object(serialized);
  501. },
  502. to: function(deserialized) {
  503. return Ember.none(deserialized) ? null : Object(deserialized);
  504. }
  505. };
  506. /**
  507. * Allows EmberData models to have array properties.
  508. *
  509. * Declare the property as <code>
  510. * operations: DS.attr('array'),
  511. * </code> and
  512. * during load provide a JSON array for value.
  513. *
  514. * This transform simply assigns the same array in both directions.
  515. */
  516. DS.attr.transforms.array = {
  517. from : function(serialized) {
  518. return serialized;
  519. },
  520. to : function(deserialized) {
  521. return deserialized;
  522. }
  523. };