helper.js 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134
  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. var stringUtils = require('utils/string_utils');
  19. var timezoneUtils = require('utils/date/timezone');
  20. /**
  21. * Remove spaces at beginning and ending of line.
  22. * @example
  23. * var str = " I'm a string "
  24. * str.trim() // return "I'm a string"
  25. * @method trim
  26. * @return {string}
  27. */
  28. String.prototype.trim = function () {
  29. return this.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
  30. };
  31. /**
  32. * Determines whether string end within another string.
  33. *
  34. * @method endsWith
  35. * @param suffix {string} substring for search
  36. * @return {boolean}
  37. */
  38. String.prototype.endsWith = function(suffix) {
  39. return this.indexOf(suffix, this.length - suffix.length) !== -1;
  40. };
  41. /**
  42. * Determines whether string start within another string.
  43. *
  44. * @method startsWith
  45. * @param prefix {string} substring for search
  46. * @return {boolean}
  47. */
  48. String.prototype.startsWith = function (prefix){
  49. return this.indexOf(prefix) == 0;
  50. };
  51. /**
  52. * Determines whether string founded within another string.
  53. *
  54. * @method contains
  55. * @param substring {string} substring for search
  56. * @return {boolean}
  57. */
  58. String.prototype.contains = function(substring) {
  59. return this.indexOf(substring) != -1;
  60. };
  61. /**
  62. * Capitalize the first letter of string.
  63. * @method capitalize
  64. * @return {string}
  65. */
  66. String.prototype.capitalize = function () {
  67. return this.charAt(0).toUpperCase() + this.slice(1);
  68. };
  69. /**
  70. * Capitalize the first letter of string.
  71. * And set to lowercase other part of string
  72. * @method toCapital
  73. * @return {string}
  74. */
  75. String.prototype.toCapital = function () {
  76. return this.charAt(0).toUpperCase() + this.slice(1).toLowerCase();
  77. };
  78. /**
  79. * Finds the value in an object where this string is a key.
  80. * Optionally, the index of the key can be provided where the
  81. * value of the nth key in the hierarchy is returned.
  82. *
  83. * Example:
  84. * var tofind = 'smart';
  85. * var person = {'name': 'Bob Bob', 'smart': 'no', 'age': '28', 'personality': {'smart': 'yes', 'funny': 'yes', 'emotion': 'happy'} };
  86. * tofind.findIn(person); // 'no'
  87. * tofind.findIn(person, 0); // 'no'
  88. * tofind.findIn(person, 1); // 'yes'
  89. * tofind.findIn(person, 2); // null
  90. *
  91. * @method findIn
  92. * @param multi {object}
  93. * @param index {number} Occurrence count of this key
  94. * @return {*} Value of key at given index
  95. */
  96. String.prototype.findIn = function(multi, index, _foundValues) {
  97. if (!index) {
  98. index = 0;
  99. }
  100. if (!_foundValues) {
  101. _foundValues = [];
  102. }
  103. multi = multi || '';
  104. var value = null;
  105. var str = this.valueOf();
  106. if (typeof multi == 'object') {
  107. for ( var key in multi) {
  108. if (value != null) {
  109. break;
  110. }
  111. if (key == str) {
  112. _foundValues.push(multi[key]);
  113. }
  114. if (_foundValues.length - 1 == index) {
  115. // Found the value
  116. return _foundValues[index];
  117. }
  118. if (typeof multi[key] == 'object') {
  119. value = value || this.findIn(multi[key], index, _foundValues);
  120. }
  121. }
  122. }
  123. return value;
  124. };
  125. /**
  126. * Replace {i} with argument. where i is number of argument to replace with.
  127. * @example
  128. * var str = "{0} world{1}";
  129. * str.format("Hello", "!") // return "Hello world!"
  130. *
  131. * @method format
  132. * @return {string}
  133. */
  134. String.prototype.format = function () {
  135. var args = arguments;
  136. return this.replace(/{(\d+)}/g, function (match, number) {
  137. return typeof args[number] != 'undefined' ? args[number] : match;
  138. });
  139. };
  140. /**
  141. * Wrap words in string within template.
  142. *
  143. * @method highlight
  144. * @param {string[]} words - words to wrap
  145. * @param {string} [highlightTemplate="<b>{0}</b>"] - template for wrapping
  146. * @return {string}
  147. */
  148. String.prototype.highlight = function (words, highlightTemplate) {
  149. var self = this;
  150. highlightTemplate = highlightTemplate ? highlightTemplate : "<b>{0}</b>";
  151. words.forEach(function (word) {
  152. var searchRegExp = new RegExp("\\b" + word + "\\b", "gi");
  153. self = self.replace(searchRegExp, function (found) {
  154. return highlightTemplate.format(found);
  155. });
  156. });
  157. return self;
  158. };
  159. /**
  160. * Convert time in milliseconds to object contained days, hours and minutes.
  161. * @typedef ConvertedTime
  162. * @type {Object}
  163. * @property {number} d - days
  164. * @property {number} h - hours
  165. * @property {string} m - minutes
  166. * @example
  167. * var time = 1000000000;
  168. * time.toDaysHoursMinutes() // {d: 11, h: 13, m: "46.67"}
  169. *
  170. * @method toDaysHoursMinutes
  171. * @return {object}
  172. */
  173. Number.prototype.toDaysHoursMinutes = function () {
  174. var formatted = {},
  175. dateDiff = this,
  176. secK = 1000, //ms
  177. minK = 60 * secK, // sec
  178. hourK = 60 * minK, // sec
  179. dayK = 24 * hourK;
  180. dateDiff = parseInt(dateDiff);
  181. formatted.d = Math.floor(dateDiff / dayK);
  182. dateDiff -= formatted.d * dayK;
  183. formatted.h = Math.floor(dateDiff / hourK);
  184. dateDiff -= formatted.h * hourK;
  185. formatted.m = (dateDiff / minK).toFixed(2);
  186. return formatted;
  187. };
  188. /**
  189. *
  190. * @param bound1 {Number}
  191. * @param bound2 {Number}
  192. * @return {boolean}
  193. */
  194. Number.prototype.isInRange = function (bound1, bound2) {
  195. var upperBound, lowerBound;
  196. upperBound = bound1 > bound2 ? bound1: bound2;
  197. lowerBound = bound1 < bound2 ? bound1: bound2;
  198. return this > lowerBound && this < upperBound;
  199. };
  200. /**
  201. Sort an array by the key specified in the argument.
  202. Handle only native js objects as element of array, not the Ember's object.
  203. Can be used as alternative to sortProperty method of Ember library
  204. in order to speed up executing on large data volumes
  205. @method sortBy
  206. @param {String} path name(s) to sort on
  207. @return {Array} The sorted array.
  208. */
  209. Array.prototype.sortPropertyLight = function (path) {
  210. var realPath = (typeof path === "string") ? path.split('.') : [];
  211. this.sort(function (a, b) {
  212. var aProperty = a;
  213. var bProperty = b;
  214. realPath.forEach(function (key) {
  215. aProperty = aProperty[key];
  216. bProperty = bProperty[key];
  217. });
  218. if (aProperty > bProperty) return 1;
  219. if (aProperty < bProperty) return -1;
  220. return 0;
  221. });
  222. return this;
  223. };
  224. /**
  225. * Create map from array with executing provided callback for each array's item
  226. * Example:
  227. * <pre>
  228. * var array = [{a: 1, b: 3}, {a: 2, b: 2}, {a: 3, b: 1}];
  229. * var map = array.toMapByCallback('a', function (item) {
  230. * return Em.get(item, 'b');
  231. * });
  232. * console.log(map); // {1: 3, 2: 2, 3: 1}
  233. * </pre>
  234. * <code>map[1]</code> is much more faster than <code>array.findProperty('a', 1).get('b')</code>
  235. *
  236. * @param {string} property
  237. * @param {Function} callback
  238. * @returns {object}
  239. * @method toMapByCallback
  240. */
  241. Array.prototype.toMapByCallback = function (property, callback) {
  242. var ret = {};
  243. Em.assert('`property` can\'t be empty string', property.length);
  244. Em.assert('`callback` should be a function', 'function' === Em.typeOf(callback));
  245. this.forEach(function (item) {
  246. var key = Em.get(item, property);
  247. ret[key] = callback(item, property);
  248. });
  249. return ret;
  250. };
  251. /**
  252. * Create map from array
  253. * Example:
  254. * <pre>
  255. * var array = [{a: 1}, {a: 2}, {a: 3}];
  256. * var map = array.toMapByProperty('a'); // {1: {a: 1}, 2: {a: 2}, 3: {a: 3}}
  257. * </pre>
  258. * <code>map[1]</code> is much more faster than <code>array.findProperty('a', 1)</code>
  259. *
  260. * @param {string} property
  261. * @return {object}
  262. * @method toMapByProperty
  263. * @see toMapByCallback
  264. */
  265. Array.prototype.toMapByProperty = function (property) {
  266. return this.toMapByCallback(property, function (item) {
  267. return item;
  268. });
  269. };
  270. /**
  271. * Create wick map from array
  272. * Example:
  273. * <pre>
  274. * var array = [{a: 1}, {a: 2}, {a: 3}];
  275. * var map = array.toWickMapByProperty('a'); // {1: true, 2: true, 3: true}
  276. * </pre>
  277. * <code>map[1]</code> works faster than <code>array.someProperty('a', 1)</code>
  278. *
  279. * @param {string} property
  280. * @return {object}
  281. * @method toWickMapByProperty
  282. * @see toMapByCallback
  283. */
  284. Array.prototype.toWickMapByProperty = function (property) {
  285. return this.toMapByCallback(property, function () {
  286. return true;
  287. });
  288. };
  289. /**
  290. * Create wick map from array of primitives
  291. * Example:
  292. * <pre>
  293. * var array = [1, 2, 3];
  294. * var map = array.toWickMap(); // {1: true, 2: true, 3: true}
  295. * </pre>
  296. * <code>map[1]</code> works faster than <code>array.contains(1)</code>
  297. *
  298. * @returns {object}
  299. * @method toWickMap
  300. */
  301. Array.prototype.toWickMap = function () {
  302. var ret = {};
  303. this.forEach(function (item) {
  304. ret[item] = true;
  305. });
  306. return ret;
  307. };
  308. /** @namespace Em **/
  309. Em.CoreObject.reopen({
  310. t:function (key, attrs) {
  311. return Em.I18n.t(key, attrs)
  312. }
  313. });
  314. Em.TextArea.reopen(Em.I18n.TranslateableAttributes);
  315. /** @namespace Em.Handlebars **/
  316. Em.Handlebars.registerHelper('log', function (variable) {
  317. console.log(variable);
  318. });
  319. Em.Handlebars.registerHelper('warn', function (variable) {
  320. console.warn(variable);
  321. });
  322. Em.Handlebars.registerHelper('highlight', function (property, words, fn) {
  323. var context = (fn.contexts && fn.contexts[0]) || this;
  324. property = Em.Handlebars.getPath(context, property, fn);
  325. words = words.split(";");
  326. // if (highlightTemplate == undefined) {
  327. var highlightTemplate = "<b>{0}</b>";
  328. // }
  329. words.forEach(function (word) {
  330. var searchRegExp = new RegExp("\\b" + word + "\\b", "gi");
  331. property = property.replace(searchRegExp, function (found) {
  332. return highlightTemplate.format(found);
  333. });
  334. });
  335. return new Em.Handlebars.SafeString(property);
  336. });
  337. Em.Handlebars.registerHelper('isAuthorized', function (property, options) {
  338. var permission = Ember.Object.create({
  339. isAuthorized: function() {
  340. return App.isAuthorized(property);
  341. }.property('App.router.wizardWatcherController.isWizardRunning')
  342. });
  343. // wipe out contexts so boundIf uses `this` (the permission) as the context
  344. options.contexts = null;
  345. return Ember.Handlebars.helpers.boundIf.call(permission, "isAuthorized", options);
  346. });
  347. Em.Handlebars.registerHelper('isNotAuthorized', function (property, options) {
  348. var permission = Ember.Object.create({
  349. isNotAuthorized: function() {
  350. return !App.isAuthorized(property);
  351. }.property('App.router.wizardWatcherController.isWizardRunning')
  352. });
  353. // wipe out contexts so boundIf uses `this` (the permission) as the context
  354. options.contexts = null;
  355. return Ember.Handlebars.helpers.boundIf.call(permission, "isNotAuthorized", options);
  356. });
  357. /**
  358. * @namespace App
  359. */
  360. App = require('app');
  361. /**
  362. * Certain variables can have JSON in string
  363. * format, or in JSON format itself.
  364. *
  365. * @memberof App
  366. * @function parseJson
  367. * @param {string|object}
  368. * @return {object}
  369. */
  370. App.parseJSON = function (value) {
  371. if (typeof value == "string") {
  372. return jQuery.parseJSON(value);
  373. }
  374. return value;
  375. };
  376. /**
  377. * Check for empty <code>Object</code>, built in Em.isEmpty()
  378. * doesn't support <code>Object</code> type
  379. *
  380. * @memberof App
  381. * @method isEmptyObject
  382. * @param obj {Object}
  383. * @return {Boolean}
  384. */
  385. App.isEmptyObject = function(obj) {
  386. var empty = true;
  387. for (var prop in obj) { if (obj.hasOwnProperty(prop)) {empty = false; break;} }
  388. return empty;
  389. };
  390. /**
  391. * Convert object under_score keys to camelCase
  392. *
  393. * @param {Object} object
  394. * @return {Object}
  395. **/
  396. App.keysUnderscoreToCamelCase = function(object) {
  397. var tmp = {};
  398. for (var key in object) {
  399. tmp[stringUtils.underScoreToCamelCase(key)] = object[key];
  400. }
  401. return tmp;
  402. };
  403. /**
  404. * Convert dotted keys to camelcase
  405. *
  406. * @param {Object} object
  407. * @return {Object}
  408. **/
  409. App.keysDottedToCamelCase = function(object) {
  410. var tmp = {};
  411. for (var key in object) {
  412. tmp[key.split('.').reduce(function(p, c) { return p + c.capitalize()})] = object[key];
  413. }
  414. return tmp;
  415. };
  416. /**
  417. * Returns object with defined keys only.
  418. *
  419. * @memberof App
  420. * @method permit
  421. * @param {Object} obj - input object
  422. * @param {String|Array} keys - allowed keys
  423. * @return {Object}
  424. */
  425. App.permit = function(obj, keys) {
  426. var result = {};
  427. if (typeof obj !== 'object' || App.isEmptyObject(obj)) return result;
  428. if (typeof keys == 'string') keys = Array(keys);
  429. keys.forEach(function(key) {
  430. if (obj.hasOwnProperty(key))
  431. result[key] = obj[key];
  432. });
  433. return result;
  434. };
  435. /**
  436. *
  437. * @namespace App
  438. * @namespace App.format
  439. */
  440. App.format = {
  441. /**
  442. * @memberof App.format
  443. * @type {object}
  444. * @property components
  445. */
  446. components: {
  447. 'API': 'API',
  448. 'DECOMMISSION_DATANODE': 'Update Exclude File',
  449. 'DRPC': 'DRPC',
  450. 'FLUME_HANDLER': 'Flume',
  451. 'GLUSTERFS': 'GLUSTERFS',
  452. 'HBASE': 'HBase',
  453. 'HBASE_REGIONSERVER': 'RegionServer',
  454. 'HCAT': 'HCat Client',
  455. 'HDFS': 'HDFS',
  456. 'HISTORYSERVER': 'History Server',
  457. 'HIVE_SERVER': 'HiveServer2',
  458. 'JCE': 'JCE',
  459. 'MAPREDUCE2': 'MapReduce2',
  460. 'MYSQL': 'MySQL',
  461. 'REST': 'REST',
  462. 'SECONDARY_NAMENODE': 'SNameNode',
  463. 'STORM_REST_API': 'Storm REST API Server',
  464. 'WEBHCAT': 'WebHCat',
  465. 'YARN': 'YARN',
  466. 'UI': 'UI',
  467. 'ZKFC': 'ZKFailoverController',
  468. 'ZOOKEEPER': 'ZooKeeper',
  469. 'ZOOKEEPER_QUORUM_SERVICE_CHECK': 'ZK Quorum Service Check'
  470. },
  471. /**
  472. * @memberof App.format
  473. * @property command
  474. * @type {object}
  475. */
  476. command: {
  477. 'INSTALL': 'Install',
  478. 'UNINSTALL': 'Uninstall',
  479. 'START': 'Start',
  480. 'STOP': 'Stop',
  481. 'EXECUTE': 'Execute',
  482. 'ABORT': 'Abort',
  483. 'UPGRADE': 'Upgrade',
  484. 'RESTART': 'Restart',
  485. 'SERVICE_CHECK': 'Check',
  486. 'Excluded:': 'Decommission:',
  487. 'Included:': 'Recommission:'
  488. },
  489. /**
  490. * cached map of service and component names
  491. * @type {object}
  492. */
  493. stackRolesMap: {},
  494. /**
  495. * convert role to readable string
  496. *
  497. * @memberof App.format
  498. * @method role
  499. * @param {string} role
  500. * return {string}
  501. */
  502. role: function (role) {
  503. var models = [App.StackService, App.StackServiceComponent];
  504. if (App.isEmptyObject(this.stackRolesMap)) {
  505. models.forEach(function (model) {
  506. model.find().forEach(function (item) {
  507. this.stackRolesMap[item.get('id')] = item.get('displayName');
  508. }, this);
  509. }, this);
  510. }
  511. if (this.stackRolesMap[role]) {
  512. return this.stackRolesMap[role];
  513. }
  514. return this.normalizeName(role);
  515. },
  516. /**
  517. * Try to format non predefined names to readable format.
  518. *
  519. * @method normalizeNameBySeparator
  520. * @param name {String} - name to format
  521. * @param separators {String} - token use to split the string
  522. * @return {String}
  523. */
  524. normalizeNameBySeparators: function(name, separators) {
  525. if (!name || typeof name != 'string') return '';
  526. name = name.toLowerCase();
  527. if (!separators || separators.length == 0) {
  528. console.debug("No separators specified. Use default separator '_' instead");
  529. separators = ["_"];
  530. }
  531. for (var i = 0; i < separators.length; i++){
  532. var separator = separators[i];
  533. if (new RegExp(separator, 'g').test(name)) {
  534. name = name.split(separator).map(function(singleName) {
  535. return this.normalizeName(singleName.toUpperCase());
  536. }, this).join(' ');
  537. }
  538. }
  539. return name.capitalize();
  540. },
  541. /**
  542. * Try to format non predefined names to readable format.
  543. *
  544. * @method normalizeName
  545. * @param name {String} - name to format
  546. * @return {String}
  547. */
  548. normalizeName: function(name) {
  549. if (!name || typeof name != 'string') return '';
  550. if (this.components[name]) return this.components[name];
  551. name = name.toLowerCase();
  552. var suffixNoSpaces = ['node','tracker','manager'];
  553. var suffixRegExp = new RegExp('(\\w+)(' + suffixNoSpaces.join('|') + ')', 'gi');
  554. if (/_/g.test(name)) {
  555. name = name.split('_').map(function(singleName) {
  556. return this.normalizeName(singleName.toUpperCase());
  557. }, this).join(' ');
  558. } else if(suffixRegExp.test(name)) {
  559. suffixRegExp.lastIndex = 0;
  560. var matches = suffixRegExp.exec(name);
  561. name = matches[1].capitalize() + matches[2].capitalize();
  562. }
  563. return name.capitalize();
  564. },
  565. /**
  566. * convert command_detail to readable string, show the string for all tasks name
  567. *
  568. * @memberof App.format
  569. * @method commandDetail
  570. * @param {string} command_detail
  571. * @param {string} request_inputs
  572. * @return {string}
  573. */
  574. commandDetail: function (command_detail, request_inputs) {
  575. var detailArr = command_detail.split(' ');
  576. var self = this;
  577. var result = '';
  578. detailArr.forEach( function(item) {
  579. // if the item has the pattern SERVICE/COMPONENT, drop the SERVICE part
  580. if (item.contains('/')) {
  581. item = item.split('/')[1];
  582. }
  583. if (item == 'DECOMMISSION,') {
  584. // ignore text 'DECOMMISSION,'( command came from 'excluded/included'), here get the component name from request_inputs
  585. item = (jQuery.parseJSON(request_inputs)) ? jQuery.parseJSON(request_inputs).slave_type : '';
  586. }
  587. if (self.components[item]) {
  588. result = result + ' ' + self.components[item];
  589. } else if (self.command[item]) {
  590. result = result + ' ' + self.command[item];
  591. } else {
  592. result = result + ' ' + self.role(item);
  593. }
  594. });
  595. if (result.indexOf('Decommission:') > -1 || result.indexOf('Recommission:') > -1) {
  596. // for Decommission command, make sure the hostname is in lower case
  597. result = result.split(':')[0] + ': ' + result.split(':')[1].toLowerCase();
  598. }
  599. //TODO check if UI use this
  600. if (result === ' Nagios Update Ignore Actionexecute') {
  601. result = Em.I18n.t('common.maintenance.task');
  602. }
  603. if (result.indexOf('Install Packages Actionexecute') != -1) {
  604. result = Em.I18n.t('common.installRepo.task');
  605. }
  606. if (result === ' Rebalancehdfs NameNode') {
  607. result = Em.I18n.t('services.service.actions.run.rebalanceHdfsNodes.title');
  608. }
  609. if (result === " Startdemoldap Knox Gateway") {
  610. result = Em.I18n.t('services.service.actions.run.startLdapKnox.title');
  611. }
  612. if (result === " Stopdemoldap Knox Gateway") {
  613. result = Em.I18n.t('services.service.actions.run.stopLdapKnox.title');
  614. }
  615. if (result === ' Refreshqueues ResourceManager') {
  616. result = Em.I18n.t('services.service.actions.run.yarnRefreshQueues.title');
  617. }
  618. // HAWQ custom commands on back Ops page.
  619. if (result === ' Resync Hawq Standby HAWQ Standby Master') {
  620. result = Em.I18n.t('services.service.actions.run.resyncHawqStandby.label');
  621. }
  622. if (result === ' Immediate Stop Hawq Service HAWQ Master') {
  623. result = Em.I18n.t('services.service.actions.run.immediateStopHawqService.label');
  624. }
  625. if (result === ' Immediate Stop Hawq Segment HAWQ Segment') {
  626. result = Em.I18n.t('services.service.actions.run.immediateStopHawqSegment.label');
  627. }
  628. if(result === ' Activate Hawq Standby HAWQ Standby Master') {
  629. result = Em.I18n.t('admin.activateHawqStandby.button.enable');
  630. }
  631. if(result === ' Hawq Clear Cache HAWQ Master') {
  632. result = Em.I18n.t('services.service.actions.run.clearHawqCache.label');
  633. }
  634. if(result === ' Run Hawq Check HAWQ Master') {
  635. result = Em.I18n.t('services.service.actions.run.runHawqCheck.label');
  636. }
  637. //<---End HAWQ custom commands--->
  638. return result;
  639. },
  640. /**
  641. * Convert uppercase status name to lowercase.
  642. * <br>
  643. * <br>PENDING - Not queued yet for a host
  644. * <br>QUEUED - Queued for a host
  645. * <br>IN_PROGRESS - Host reported it is working
  646. * <br>COMPLETED - Host reported success
  647. * <br>FAILED - Failed
  648. * <br>TIMEDOUT - Host did not respond in time
  649. * <br>ABORTED - Operation was abandoned
  650. *
  651. * @memberof App.format
  652. * @method taskStatus
  653. * @param {string} _taskStatus
  654. * @return {string}
  655. *
  656. */
  657. taskStatus:function (_taskStatus) {
  658. return _taskStatus.toLowerCase();
  659. },
  660. /**
  661. * simplify kdc error msg
  662. * @param {string} message
  663. * @param {boolean} strict if this flag is true ignore not defined msgs return null
  664. * else return input msg as is;
  665. * @returns {*}
  666. */
  667. kdcErrorMsg: function(message, strict) {
  668. /**
  669. * Error messages for KDC administrator credentials error
  670. * is used for checking if error message is caused by bad KDC credentials
  671. * @type {{missingKDC: string, invalidKDC: string}}
  672. */
  673. var specialMsg = {
  674. "missingKDC": "Missing KDC administrator credentials.",
  675. "invalidKDC": "Invalid KDC administrator credentials.",
  676. "missingRDCForRealm": "Failed to find a KDC for the specified realm - kadmin"
  677. };
  678. for (var m in specialMsg) {
  679. if (specialMsg.hasOwnProperty(m) && message.contains(specialMsg[m]))
  680. return specialMsg[m];
  681. }
  682. return strict ? null : message;
  683. }
  684. };
  685. /**
  686. * wrapper to bootstrap popover
  687. * fix issue when popover stuck on view routing
  688. *
  689. * @memberof App
  690. * @method popover
  691. * @param {DOMElement} self
  692. * @param {object} options
  693. */
  694. App.popover = function (self, options) {
  695. if (!self) return;
  696. self.popover(options);
  697. self.on("remove", function () {
  698. $(this).trigger('mouseleave').off().removeData('popover');
  699. });
  700. };
  701. /**
  702. * wrapper to bootstrap tooltip
  703. * fix issue when tooltip stuck on view routing
  704. * @memberof App
  705. * @method tooltip
  706. * @param {DOMElement} self
  707. * @param {object} options
  708. */
  709. App.tooltip = function (self, options) {
  710. if (!self || !self.tooltip) return;
  711. self.tooltip(options);
  712. /* istanbul ignore next */
  713. self.on("remove", function () {
  714. $(this).trigger('mouseleave').off().removeData('tooltip');
  715. });
  716. };
  717. /**
  718. * wrapper to Date().getTime()
  719. * fix issue when client clock and server clock not sync
  720. *
  721. * @memberof App
  722. * @method dateTime
  723. * @return {Number} timeStamp of current server clock
  724. */
  725. App.dateTime = function() {
  726. return new Date().getTime() + App.clockDistance;
  727. };
  728. /**
  729. *
  730. * @param {number} [x] timestamp
  731. * @returns {number}
  732. */
  733. App.dateTimeWithTimeZone = function (x) {
  734. var timezone = App.router.get('userSettingsController.userSettings.timezone');
  735. if (timezone) {
  736. var tz = Em.getWithDefault(timezone, 'zones.0.value', '');
  737. return moment(moment.tz(x ? new Date(x) : new Date(), tz).toArray()).toDate().getTime();
  738. }
  739. return x || new Date().getTime();
  740. };
  741. App.formatDateTimeWithTimeZone = function (timeStamp, format) {
  742. var timezone = App.router.get('userSettingsController.userSettings.timezone'),
  743. time;
  744. if (timezone) {
  745. var tz = Em.getWithDefault(timezone, 'zones.0.value', '');
  746. time = moment.tz(timeStamp, tz);
  747. } else {
  748. time = moment(timeStamp);
  749. }
  750. return moment(time).format(format);
  751. };
  752. App.getTimeStampFromLocalTime = function (time) {
  753. var timezone = App.router.get('userSettingsController.userSettings.timezone'),
  754. offsetString = '',
  755. date = moment(time).format('YYYY-MM-DD HH:mm:ss');
  756. if (timezone) {
  757. var offset = timezone.utcOffset;
  758. offsetString = moment().utcOffset(offset).format('Z');
  759. }
  760. return moment(date + offsetString).toDate().getTime();
  761. };
  762. /**
  763. * Helper function for bound property helper registration
  764. * @memberof App
  765. * @method registerBoundHelper
  766. * @param name {String} name of helper
  767. * @param view {Em.View} view
  768. */
  769. App.registerBoundHelper = function(name, view) {
  770. Em.Handlebars.registerHelper(name, function(property, options) {
  771. options.hash.contentBinding = property;
  772. return Em.Handlebars.helpers.view.call(this, view, options);
  773. });
  774. };
  775. /*
  776. * Return singular or plural word based on Em.I18n, view|controller context property key.
  777. *
  778. * Example: {{pluralize hostsCount singular="t:host" plural="t:hosts"}}
  779. * {{pluralize hostsCount singular="@view.hostName"}}
  780. */
  781. App.registerBoundHelper('pluralize', Em.View.extend({
  782. tagName: 'span',
  783. template: Em.Handlebars.compile('{{view.wordOut}}'),
  784. wordOut: function() {
  785. var count, singular, plural;
  786. count = this.get('content');
  787. singular = this.get('singular');
  788. plural = this.get('plural');
  789. return this.getWord(count, singular, plural);
  790. }.property('content'),
  791. /**
  792. * Get computed word.
  793. *
  794. * @param {Number} count
  795. * @param {String} singular
  796. * @param {String} [plural]
  797. * @return {String}
  798. * @method getWord
  799. */
  800. getWord: function(count, singular, plural) {
  801. singular = this.parseValue(singular);
  802. // if plural not passed
  803. if (!plural) plural = singular + 's';
  804. else plural = this.parseValue(plural);
  805. if (singular && plural) {
  806. if (count == 1) {
  807. return singular;
  808. } else {
  809. return plural;
  810. }
  811. }
  812. return '';
  813. },
  814. /**
  815. * Detect and return value from its instance.
  816. *
  817. * @param {String} value
  818. * @return {*}
  819. * @method parseValue
  820. **/
  821. parseValue: function(value) {
  822. switch (value[0]) {
  823. case '@':
  824. value = this.getViewPropertyValue(value);
  825. break;
  826. case 't':
  827. value = this.tDetect(value);
  828. break;
  829. default:
  830. break;
  831. }
  832. return value;
  833. },
  834. /*
  835. * Detect for Em.I18n.t reference call
  836. * @params word {String}
  837. * return {String}
  838. */
  839. tDetect: function(word) {
  840. var splitted = word.split(':');
  841. if (splitted.length > 1 && splitted[0] == 't') {
  842. return Em.I18n.t(splitted[1]);
  843. } else {
  844. return splitted[0];
  845. }
  846. },
  847. /**
  848. * Get property value from view|controller by its key path.
  849. *
  850. * @param {String} value - key path
  851. * @return {*}
  852. * @method getViewPropertyValue
  853. **/
  854. getViewPropertyValue: function(value) {
  855. value = value.substr(1);
  856. var keyword = value.split('.')[0]; // return 'controller' or 'view'
  857. switch (keyword) {
  858. case 'controller':
  859. return Em.get(this, value);
  860. case 'view':
  861. return Em.get(this, value.replace(/^view/, 'parentView'));
  862. default:
  863. break;
  864. }
  865. }
  866. })
  867. );
  868. /**
  869. * Return defined string instead of empty if value is null/undefined
  870. * by default is `n/a`.
  871. *
  872. * @param empty {String} - value instead of empty string (not required)
  873. * can be used with Em.I18n pass value started with't:'
  874. *
  875. * Examples:
  876. *
  877. * default value will be returned
  878. * {{formatNull service.someValue}}
  879. *
  880. * <code>empty<code> will be returned
  881. * {{formatNull service.someValue empty="I'm empty"}}
  882. *
  883. * Em.I18n translation will be returned
  884. * {{formatNull service.someValue empty="t:my.key.to.translate"
  885. */
  886. App.registerBoundHelper('formatNull', Em.View.extend({
  887. tagName: 'span',
  888. template: Em.Handlebars.compile('{{view.result}}'),
  889. result: function() {
  890. var emptyValue = this.get('empty') ? this.get('empty') : Em.I18n.t('services.service.summary.notAvailable');
  891. emptyValue = emptyValue.startsWith('t:') ? Em.I18n.t(emptyValue.substr(2, emptyValue.length)) : emptyValue;
  892. return (this.get('content') || this.get('content') == 0) ? this.get('content') : emptyValue;
  893. }.property('content')
  894. }));
  895. /**
  896. * Return formatted string with inserted <code>wbr</code>-tag after each dot
  897. *
  898. * @param {String} content
  899. *
  900. * Examples:
  901. *
  902. * returns 'apple'
  903. * {{formatWordBreak 'apple'}}
  904. *
  905. * returns 'apple.<wbr />banana'
  906. * {{formatWordBreak 'apple.banana'}}
  907. *
  908. * returns 'apple.<wbr />banana.<wbr />uranium'
  909. * {{formatWordBreak 'apple.banana.uranium'}}
  910. */
  911. App.registerBoundHelper('formatWordBreak', Em.View.extend({
  912. attributeBindings: ["data-original-title"],
  913. tagName: 'span',
  914. template: Em.Handlebars.compile('{{{view.result}}}'),
  915. /**
  916. * @type {string}
  917. */
  918. result: function() {
  919. return this.get('content') && this.get('content').replace(/\./g, '.<wbr />');
  920. }.property('content')
  921. }));
  922. /**
  923. * Return <i></i> with class that correspond to status
  924. *
  925. * @param {string} content - status
  926. *
  927. * Examples:
  928. *
  929. * {{statusIcon view.status}}
  930. * returns 'icon-cog'
  931. *
  932. */
  933. App.registerBoundHelper('statusIcon', Em.View.extend({
  934. tagName: 'i',
  935. /**
  936. * relation map between status and icon class
  937. * @type {object}
  938. */
  939. statusIconMap: {
  940. 'COMPLETED': 'icon-ok completed',
  941. 'WARNING': 'icon-warning-sign',
  942. 'FAILED': 'icon-exclamation-sign failed',
  943. 'HOLDING_FAILED': 'icon-exclamation-sign failed',
  944. 'SKIPPED_FAILED': 'icon-share-alt failed',
  945. 'PENDING': 'icon-cog pending',
  946. 'QUEUED': 'icon-cog queued',
  947. 'IN_PROGRESS': 'icon-cogs in_progress',
  948. 'HOLDING': 'icon-pause',
  949. 'SUSPENDED': 'icon-pause',
  950. 'ABORTED': 'icon-minus aborted',
  951. 'TIMEDOUT': 'icon-time timedout',
  952. 'HOLDING_TIMEDOUT': 'icon-time timedout',
  953. 'SUBITEM_FAILED': 'icon-remove failed'
  954. },
  955. classNameBindings: ['iconClass'],
  956. attributeBindings: ['data-original-title'],
  957. didInsertElement: function () {
  958. App.tooltip($(this.get('element')));
  959. },
  960. 'data-original-title': function() {
  961. return this.get('content').toCapital();
  962. }.property('content'),
  963. /**
  964. * @type {string}
  965. */
  966. iconClass: function () {
  967. return this.get('statusIconMap')[this.get('content')] || 'icon-question-sign';
  968. }.property('content')
  969. }));
  970. /**
  971. * Ambari overrides the default date transformer.
  972. * This is done because of the non-standard data
  973. * sent. For example Nagios sends date as "12345678".
  974. * The problem is that it is a String and is represented
  975. * only in seconds whereas Javascript's Date needs
  976. * milliseconds representation.
  977. */
  978. DS.attr.transforms.date = {
  979. from: function (serialized) {
  980. var type = typeof serialized;
  981. if (type === Em.I18n.t('common.type.string')) {
  982. serialized = parseInt(serialized);
  983. type = typeof serialized;
  984. }
  985. if (type === Em.I18n.t('common.type.number')) {
  986. if (!serialized ){ //serialized timestamp = 0;
  987. return 0;
  988. }
  989. // The number could be seconds or milliseconds.
  990. // If seconds, then the length is 10
  991. // If milliseconds, the length is 13
  992. if (serialized.toString().length < 13) {
  993. serialized = serialized * 1000;
  994. }
  995. return new Date(serialized);
  996. } else if (serialized === null || serialized === undefined) {
  997. // if the value is not present in the data,
  998. // return undefined, not null.
  999. return serialized;
  1000. } else {
  1001. return null;
  1002. }
  1003. },
  1004. to: function (deserialized) {
  1005. if (deserialized instanceof Date) {
  1006. return deserialized.getTime();
  1007. } else if (deserialized === undefined) {
  1008. return undefined;
  1009. } else {
  1010. return null;
  1011. }
  1012. }
  1013. };
  1014. DS.attr.transforms.object = {
  1015. from: function(serialized) {
  1016. return Ember.none(serialized) ? null : Object(serialized);
  1017. },
  1018. to: function(deserialized) {
  1019. return Ember.none(deserialized) ? null : Object(deserialized);
  1020. }
  1021. };
  1022. /**
  1023. * Allows EmberData models to have array properties.
  1024. *
  1025. * Declare the property as <code>
  1026. * operations: DS.attr('array'),
  1027. * </code> and
  1028. * during load provide a JSON array for value.
  1029. *
  1030. * This transform simply assigns the same array in both directions.
  1031. */
  1032. DS.attr.transforms.array = {
  1033. from : function(serialized) {
  1034. return serialized;
  1035. },
  1036. to : function(deserialized) {
  1037. return deserialized;
  1038. }
  1039. };
  1040. /**
  1041. * Utility method to delete all existing records of a DS.Model type from the model's associated map and
  1042. * store's persistence layer (recordCache)
  1043. * @param type DS.Model Class
  1044. */
  1045. App.resetDsStoreTypeMap = function(type) {
  1046. var allRecords = App.get('store.recordCache'); //This fetches all records in the ember-data persistence layer
  1047. var typeMaps = App.get('store.typeMaps');
  1048. var guidForType = Em.guidFor(type);
  1049. var typeMap = typeMaps[guidForType];
  1050. if (typeMap) {
  1051. var idToClientIdMap = typeMap.idToCid;
  1052. for (var id in idToClientIdMap) {
  1053. if (idToClientIdMap.hasOwnProperty(id) && idToClientIdMap[id]) {
  1054. delete allRecords[idToClientIdMap[id]]; // deletes the cached copy of the record from the store
  1055. }
  1056. }
  1057. typeMaps[guidForType] = {
  1058. idToCid: {},
  1059. clientIds: [],
  1060. cidToHash: {},
  1061. recordArrays: []
  1062. };
  1063. }
  1064. };