config_history_flow.js 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  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 App = require('app');
  19. App.ConfigHistoryFlowView = Em.View.extend({
  20. templateName: require('templates/common/configs/config_history_flow'),
  21. /**
  22. * index of the first element(service version box) in viewport
  23. */
  24. startIndex: 0,
  25. showLeftArrow: false,
  26. showRightArrow: false,
  27. leftArrowTooltip: Em.computed.ifThenElse('showLeftArrow', Em.I18n.t('services.service.config.configHistory.leftArrow.tooltip'), null),
  28. rightArrowTooltip: Em.computed.ifThenElse('showRightArrow', Em.I18n.t('services.service.config.configHistory.rightArrow.tooltip'), null),
  29. VERSIONS_IN_FLOW: 6,
  30. VERSIONS_IN_DROPDOWN: 6,
  31. /**
  32. * flag identify whether to show all versions or short list of them
  33. */
  34. showFullList: false,
  35. compareServiceVersion: null,
  36. /**
  37. * types of actions that can't be done to service config versions
  38. */
  39. actionTypes: {
  40. SWITCH: 'switchVersion',
  41. COMPARE: 'compare',
  42. REVERT: 'revert'
  43. },
  44. /**
  45. * In reason of absence of properties dynamic values support which passed to an action,
  46. * used property map to get latest values of properties for action
  47. */
  48. serviceVersionsReferences: {
  49. displayed: Em.Object.create({
  50. isReference: true,
  51. property: 'displayedServiceVersion'
  52. }),
  53. compare: Em.Object.create({
  54. isReference: true,
  55. property: 'compareServiceVersion'
  56. })
  57. },
  58. allServiceVersions: function() {
  59. return App.ServiceConfigVersion.find().filterProperty('serviceName', this.get('serviceName'));
  60. }.property('serviceName'),
  61. showCompareVersionBar: Em.computed.bool('compareServiceVersion'),
  62. isSaveDisabled: Em.computed.or('controller.isSubmitDisabled', '!controller.versionLoaded', '!controller.isPropertiesChanged'),
  63. serviceName: Em.computed.alias('controller.selectedService.serviceName'),
  64. displayedServiceVersion: Em.computed.findBy('serviceVersions', 'isDisplayed', true),
  65. /**
  66. * identify whether to show link that open whole content of notes
  67. */
  68. showMoreLink: Em.computed.gt('displayedServiceVersion.notes.length', 100),
  69. /**
  70. * formatted notes ready to display
  71. */
  72. shortNotes: Em.computed.truncate('displayedServiceVersion.notes', 100, 100),
  73. serviceVersions: function () {
  74. var groupName = this.get('controller.selectedConfigGroup.isDefault') ? 'default'
  75. : this.get('controller.selectedConfigGroup.name');
  76. var groupId = this.get('controller.selectedConfigGroup.configGroupId');
  77. var self = this;
  78. this.get('allServiceVersions').forEach(function (version) {
  79. version.set('isDisabled', !(version.get('groupName') === groupName));
  80. }, this);
  81. var serviceVersions = this.get('allServiceVersions').filter(function(s) {
  82. return (s.get('groupId') === groupId) || s.get('groupName') == 'default';
  83. });
  84. if (!serviceVersions.findProperty('isDisplayed')) {
  85. //recompute serviceVersions if displayed version absent
  86. Em.run.next(function() {
  87. self.propertyDidChange('controller.selectedConfigGroup.name');
  88. });
  89. }
  90. return serviceVersions.sort(function (a, b) {
  91. return Em.get(b, 'createTime') - Em.get(a, 'createTime');
  92. });
  93. }.property('serviceName', 'controller.selectedConfigGroup.name'),
  94. /**
  95. * disable versions visible to the user to prevent actions on them
  96. */
  97. disableVersions: function () {
  98. this.get('allServiceVersions').setEach('isDisabled', true);
  99. },
  100. /**
  101. * service versions which in viewport and visible to user
  102. */
  103. visibleServiceVersion: function () {
  104. return this.get('serviceVersions').slice(this.get('startIndex'), (this.get('startIndex') + this.VERSIONS_IN_FLOW));
  105. }.property('startIndex', 'serviceVersions'),
  106. /**
  107. * enable actions to manipulate version only after it's loaded
  108. */
  109. versionActionsDisabled: Em.computed.or('!controller.versionLoaded', '!dropDownList.length'),
  110. /**
  111. * enable discard to manipulate version only after it's loaded and any property is changed
  112. */
  113. isDiscardDisabled: Em.computed.or('!controller.versionLoaded', '!controller.isPropertiesChanged'),
  114. /**
  115. * list of service versions
  116. * by default 6 is number of items in short list
  117. */
  118. dropDownList: function () {
  119. var serviceVersions = this.get('serviceVersions').slice(0);
  120. if (this.get('showFullList')) {
  121. return serviceVersions;
  122. }
  123. return serviceVersions.slice(0, this.VERSIONS_IN_DROPDOWN);
  124. }.property('serviceVersions', 'showFullList', 'displayedServiceVersion'),
  125. openFullList: function (event) {
  126. event.stopPropagation();
  127. this.set('showFullList', true);
  128. },
  129. hideFullList: function (event) {
  130. this.set('showFullList', !(this.get('serviceVersions.length') > this.VERSIONS_IN_DROPDOWN));
  131. },
  132. computePosition: function(event) {
  133. var $el = this.$('.dropdown-menu', event.currentTarget);
  134. // remove existing style - in case user scrolls the page
  135. $el.removeAttr('style');
  136. var elHeight = $el.outerHeight(),
  137. parentHeight = $el.parent().outerHeight(),
  138. pagePosition = window.innerHeight + window.pageYOffset,
  139. elBottomPosition = $el.offset().top + elHeight,
  140. shouldShowUp = elBottomPosition > pagePosition ;
  141. if (shouldShowUp) {
  142. $el.css('margin-top', -(elHeight - parentHeight));
  143. }
  144. $el = null;
  145. },
  146. didInsertElement: function () {
  147. App.tooltip(this.$('[data-toggle=tooltip]'),{
  148. placement: 'bottom',
  149. html: false
  150. });
  151. App.tooltip(this.$('[data-toggle=arrow-tooltip]'),{
  152. placement: 'top'
  153. });
  154. this.$(".version-info-bar-wrapper").stick_in_parent({parent: '#serviceConfig', offset_top: 10});
  155. },
  156. willDestroyElement: function() {
  157. Em.keys(this.get('serviceVersionsReferences')).forEach(function(key) {
  158. Em.get(this.get('serviceVersionsReferences'), key).destroy();
  159. }, this);
  160. this.$('.version-info-bar-wrapper').trigger('sticky_kit:detach').off();
  161. this.$('[data-toggle=tooltip], [data-toggle=arrow-tooltip]').remove();
  162. },
  163. willInsertElement: function () {
  164. this.setDisplayVersion();
  165. },
  166. setDisplayVersion: function () {
  167. var serviceVersions = this.get('serviceVersions');
  168. var startIndex = 0;
  169. var currentIndex = 0;
  170. var selectedVersion = this.get('controller.selectedVersion');
  171. serviceVersions.setEach('isDisplayed', false);
  172. serviceVersions.forEach(function (serviceVersion, index) {
  173. if (selectedVersion === serviceVersion.get('version')) {
  174. serviceVersion.set('isDisplayed', true);
  175. currentIndex = index;
  176. }
  177. }, this);
  178. // show current version as the last one
  179. if (currentIndex + 1 > this.VERSIONS_IN_FLOW) {
  180. startIndex = currentIndex + 1 - this.VERSIONS_IN_FLOW;
  181. }
  182. this.set('startIndex', startIndex);
  183. this.adjustFlowView();
  184. }.observes('allVersionsLoaded'),
  185. onChangeConfigGroup: function () {
  186. var serviceVersions = this.get('serviceVersions');
  187. var selectedGroupName = this.get('controller.selectedConfigGroup.name');
  188. var startIndex = 0;
  189. var currentIndex = 0;
  190. serviceVersions.setEach('isDisplayed', false);
  191. //display the version belongs to current group
  192. if (this.get('controller.selectedConfigGroup.isDefault')) {
  193. // display current in default group
  194. serviceVersions.forEach(function (serviceVersion, index) {
  195. // find current in default group
  196. if (serviceVersion.get('isCurrent') && serviceVersion.get('groupName') == Em.I18n.t('dashboard.configHistory.table.configGroup.default')) {
  197. serviceVersion.set('isDisplayed', true);
  198. currentIndex = index + 1;
  199. }
  200. });
  201. } else {
  202. // display current in selected group
  203. serviceVersions.forEach(function (serviceVersion, index) {
  204. // find current in selected group
  205. if (serviceVersion.get('isCurrent') && serviceVersion.get('groupName') == selectedGroupName) {
  206. serviceVersion.set('isDisplayed', true);
  207. currentIndex = index + 1;
  208. }
  209. });
  210. // no current version for selected group, show default group current version
  211. if (currentIndex == 0) {
  212. serviceVersions.forEach(function (serviceVersion, index) {
  213. // find current in default group
  214. if (serviceVersion.get('isCurrent') && serviceVersion.get('groupName') == Em.I18n.t('dashboard.configHistory.table.configGroup.default')) {
  215. currentIndex = index + 1;
  216. serviceVersion.set('isDisplayed', true);
  217. }
  218. });
  219. }
  220. }
  221. // show current version as the last one
  222. if (currentIndex > this.VERSIONS_IN_FLOW) {
  223. startIndex = currentIndex - this.VERSIONS_IN_FLOW;
  224. }
  225. this.set('startIndex', startIndex);
  226. this.adjustFlowView();
  227. }.observes('controller.selectedConfigGroup.name'),
  228. /**
  229. * define the first element in viewport
  230. * change visibility of arrows
  231. */
  232. adjustFlowView: function () {
  233. var startIndex = this.get('startIndex');
  234. this.get('serviceVersions').forEach(function (serviceVersion, index) {
  235. serviceVersion.set('first', (index === startIndex));
  236. });
  237. this.set('showLeftArrow', (startIndex !== 0));
  238. this.set('showRightArrow', (this.get('serviceVersions.length') > this.VERSIONS_IN_FLOW) && ((startIndex + this.VERSIONS_IN_FLOW) < this.get('serviceVersions.length')));
  239. },
  240. /**
  241. * check action constraints prior to invoke it
  242. * @param event
  243. */
  244. doAction: function (event) {
  245. var type = event.contexts[1],
  246. controller = this.get('controller'),
  247. self = this;
  248. if (type === 'switchVersion') {
  249. if (event.context.get("isDisplayed")) return;
  250. } else {
  251. var isDisabled = event.context ? event.context.get('isDisabled') : false;
  252. if (isDisabled) return;
  253. }
  254. function callback() {
  255. self[type].call(self, event);
  256. }
  257. Em.run.next(function() {
  258. if (controller.hasUnsavedChanges()) {
  259. controller.showSavePopup(null, callback);
  260. return;
  261. }
  262. self.disableVersions();
  263. callback();
  264. });
  265. },
  266. /**
  267. * switch configs view version to chosen
  268. */
  269. switchVersion: function (event) {
  270. var version = event.context.get('version');
  271. var versionIndex = 0;
  272. this.set('compareServiceVersion', null);
  273. this.get('serviceVersions').forEach(function (serviceVersion, index) {
  274. if (serviceVersion.get('version') === version) {
  275. serviceVersion.set('isDisplayed', true);
  276. versionIndex = index;
  277. } else {
  278. serviceVersion.set('isDisplayed', false);
  279. }
  280. });
  281. this.shiftFlowOnSwitch(versionIndex);
  282. this.get('controller').loadSelectedVersion(version);
  283. },
  284. /**
  285. * add config values of chosen version to view for comparison
  286. * add a second version-info-bar for the chosen version
  287. */
  288. compare: function (event) {
  289. this.set('controller.compareServiceVersion', event.context);
  290. this.set('compareServiceVersion', event.context);
  291. var controller = this.get('controller');
  292. controller.get('stepConfigs').clear();
  293. controller.loadCompareVersionConfigs(controller.get('allConfigs')).done(function() {
  294. controller.onLoadOverrides(controller.get('allConfigs'));
  295. });
  296. },
  297. removeCompareVersionBar: function () {
  298. var displayedVersion = this.get('displayedServiceVersion.version');
  299. var versionIndex = 0;
  300. this.set('compareServiceVersion', null);
  301. this.get('serviceVersions').forEach(function (serviceVersion, index) {
  302. if (serviceVersion.get('version') === displayedVersion) {
  303. serviceVersion.set('isDisplayed', true);
  304. versionIndex = index;
  305. } else {
  306. serviceVersion.set('isDisplayed', false);
  307. }
  308. });
  309. this.set('isCompareMode', false);
  310. this.shiftFlowOnSwitch(versionIndex);
  311. this.get('controller').loadSelectedVersion(displayedVersion);
  312. },
  313. clearCompareVersionBar: function () {
  314. if (this.get('controller.isCompareMode') === false) {
  315. this.set('compareServiceVersion', null);
  316. }
  317. }.observes('controller.isCompareMode'),
  318. /**
  319. * revert config values to chosen version and apply reverted configs to server
  320. */
  321. revert: function (event) {
  322. var self = this;
  323. var serviceConfigVersion = event.context || Em.Object.create({
  324. version: this.get('displayedServiceVersion.version'),
  325. serviceName: this.get('displayedServiceVersion.serviceName'),
  326. notes:''
  327. });
  328. if (serviceConfigVersion.get('isReference')) {
  329. serviceConfigVersion = this.get(serviceConfigVersion.get('property'));
  330. }
  331. var versionText = serviceConfigVersion.get('versionText');
  332. return App.ModalPopup.show({
  333. header: Em.I18n.t('dashboard.configHistory.info-bar.makeCurrent.popup.title'),
  334. serviceConfigNote: Em.I18n.t('services.service.config.configHistory.makeCurrent.message').format(versionText),
  335. bodyClass: Em.View.extend({
  336. templateName: require('templates/common/configs/save_configuration'),
  337. notesArea: Em.TextArea.extend({
  338. classNames: ['full-width'],
  339. value: Em.I18n.t('services.service.config.configHistory.makeCurrent.message').format(versionText),
  340. onChangeValue: function() {
  341. this.get('parentView.parentView').set('serviceConfigNote', this.get('value'));
  342. }.observes('value')
  343. })
  344. }),
  345. primary: Em.I18n.t('dashboard.configHistory.info-bar.revert.button'),
  346. secondary: Em.I18n.t('common.discard'),
  347. third: Em.I18n.t('common.cancel'),
  348. onPrimary: function () {
  349. serviceConfigVersion.set('serviceConfigNote', this.get('serviceConfigNote'));
  350. self.sendRevertCall(serviceConfigVersion);
  351. this.hide();
  352. },
  353. onSecondary: function () {
  354. // force <code>serviceVersions</code> recalculating
  355. self.propertyDidChange('controller.selectedConfigGroup.name');
  356. this._super();
  357. },
  358. onThird: function () {
  359. this.onSecondary();
  360. }
  361. });
  362. },
  363. /**
  364. * send PUT call to revert config to selected version
  365. * @param serviceConfigVersion
  366. */
  367. sendRevertCall: function (serviceConfigVersion) {
  368. App.ajax.send({
  369. name: 'service.serviceConfigVersion.revert',
  370. sender: this,
  371. data: {
  372. data: {
  373. "Clusters": {
  374. "desired_service_config_versions": {
  375. "service_config_version": serviceConfigVersion.get('version'),
  376. "service_name": serviceConfigVersion.get('serviceName'),
  377. "service_config_version_note": serviceConfigVersion.get('serviceConfigNote')
  378. }
  379. }
  380. }
  381. },
  382. success: 'sendRevertCallSuccess'
  383. });
  384. },
  385. sendRevertCallSuccess: function (data, opt, params) {
  386. // revert to an old version would generate a new version with latest version number,
  387. // so, need to loadStep to update
  388. App.router.get('updateController').updateComponentConfig(Em.K);
  389. this.get('controller').loadStep();
  390. },
  391. /**
  392. * save configuration
  393. * @return {object}
  394. */
  395. save: function () {
  396. var self = this;
  397. var passwordWasChanged = this.get('controller.passwordConfigsAreChanged');
  398. return App.ModalPopup.show({
  399. header: Em.I18n.t('dashboard.configHistory.info-bar.save.popup.title'),
  400. serviceConfigNote: '',
  401. bodyClass: Em.View.extend({
  402. templateName: require('templates/common/configs/save_configuration'),
  403. showPasswordChangeWarning: passwordWasChanged,
  404. notesArea: Em.TextArea.extend({
  405. classNames: ['full-width'],
  406. value: passwordWasChanged ? Em.I18n.t('dashboard.configHistory.info-bar.save.popup.notesForPasswordChange') : '',
  407. placeholder: Em.I18n.t('dashboard.configHistory.info-bar.save.popup.placeholder'),
  408. didInsertElement: function () {
  409. if (this.get('value')) {
  410. this.onChangeValue();
  411. }
  412. },
  413. onChangeValue: function() {
  414. this.get('parentView.parentView').set('serviceConfigNote', this.get('value'));
  415. }.observes('value')
  416. })
  417. }),
  418. footerClass: Em.View.extend({
  419. templateName: require('templates/main/service/info/save_popup_footer')
  420. }),
  421. primary: Em.I18n.t('common.save'),
  422. secondary: Em.I18n.t('common.cancel'),
  423. onSave: function () {
  424. var newVersionToBeCreated = App.ServiceConfigVersion.find().filterProperty('serviceName', self.get('serviceName')).get('length') + 1;
  425. self.get('controller').setProperties({
  426. saveConfigsFlag: true,
  427. serviceConfigVersionNote: this.get('serviceConfigNote'),
  428. preSelectedConfigVersion: Em.Object.create({
  429. version: newVersionToBeCreated,
  430. serviceName: self.get('displayedServiceVersion.serviceName'),
  431. groupName: self.get('controller.selectedConfigGroup.name')
  432. })
  433. });
  434. self.get('controller').saveStepConfigs();
  435. this.hide();
  436. },
  437. onDiscard: function () {
  438. this.hide();
  439. self.set('controller.preSelectedConfigVersion', null);
  440. self.get('controller').loadStep();
  441. },
  442. onCancel: function () {
  443. this.hide();
  444. }
  445. });
  446. },
  447. /**
  448. * move back to the later service version
  449. */
  450. shiftBack: function () {
  451. if (!this.get('showLeftArrow')) return;
  452. this.decrementProperty('startIndex');
  453. this.adjustFlowView();
  454. },
  455. /**
  456. * move forward to the previous service version
  457. */
  458. shiftForward: function () {
  459. if (!this.get('showRightArrow')) return;
  460. this.incrementProperty('startIndex');
  461. this.adjustFlowView();
  462. },
  463. /**
  464. * shift flow view to position where selected version is visible
  465. * @param versionIndex
  466. */
  467. shiftFlowOnSwitch: function (versionIndex) {
  468. var serviceVersions = this.get('serviceVersions');
  469. if ((this.get('startIndex') + this.VERSIONS_IN_FLOW) < versionIndex || versionIndex < this.get('startIndex')) {
  470. versionIndex = (serviceVersions.length < (versionIndex + this.VERSIONS_IN_FLOW)) ? serviceVersions.length - this.VERSIONS_IN_FLOW : versionIndex;
  471. this.set('startIndex', versionIndex);
  472. this.adjustFlowView();
  473. }
  474. }
  475. });
  476. App.ConfigsServiceVersionBoxView = Em.View.extend({
  477. actionTypesBinding: 'parentView.actionTypes',
  478. disabledActionAttr: Em.computed.alias('serviceVersion.disabledActionAttr'),
  479. disabledActionMessages: Em.computed.alias('serviceVersion.disabledActionMessages'),
  480. templateName: require('templates/common/configs/service_version_box'),
  481. didInsertElement: function () {
  482. this._super();
  483. this.$('.version-box').hoverIntent(function() {
  484. if ($(this).is(':hover')) {
  485. $(this).find('.version-popover').delay(700).fadeIn(200).end();
  486. }
  487. }, function() {
  488. $(this).find('.version-popover').stop().fadeOut(200).end();
  489. });
  490. App.tooltip(this.$('[data-toggle=tooltip]'), {
  491. placement: 'bottom'
  492. });
  493. App.tooltip(this.$('[data-toggle=arrow-tooltip]'), {
  494. placement: 'top'
  495. });
  496. },
  497. willDestroyElement: function() {
  498. this.$('.version-box').off();
  499. this.$('[data-toggle=tooltip], [data-toggle=arrow-tooltip]').remove();
  500. }
  501. });