ambari-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From atk...@apache.org
Subject ambari git commit: AMBARI-14682 Service uninstall: add UI elements. (atkach)
Date Fri, 15 Jan 2016 11:07:10 GMT
Repository: ambari
Updated Branches:
  refs/heads/trunk 10a07da8f -> fad7367ef


AMBARI-14682 Service uninstall: add UI elements. (atkach)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/fad7367e
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/fad7367e
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/fad7367e

Branch: refs/heads/trunk
Commit: fad7367ef5fb42064a7a10a90b091b66ec4f27fd
Parents: 10a07da
Author: Andrii Tkach <atkach@hortonworks.com>
Authored: Fri Jan 15 12:15:02 2016 +0200
Committer: Andrii Tkach <atkach@hortonworks.com>
Committed: Fri Jan 15 13:05:26 2016 +0200

----------------------------------------------------------------------
 ambari-web/app/controllers/main/service/item.js | 92 +++++++++++++++++++-
 ambari-web/app/messages.js                      | 11 +++
 ambari-web/app/models/host_component.js         |  6 ++
 ambari-web/app/views/main/service/item.js       | 19 ++--
 .../test/controllers/main/service/item_test.js  | 92 ++++++++++++++++++++
 5 files changed, 211 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/fad7367e/ambari-web/app/controllers/main/service/item.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/controllers/main/service/item.js b/ambari-web/app/controllers/main/service/item.js
index aa4ca5d..85e7910 100644
--- a/ambari-web/app/controllers/main/service/item.js
+++ b/ambari-web/app/controllers/main/service/item.js
@@ -44,6 +44,16 @@ App.MainServiceItemController = Em.Controller.extend(App.SupportClientConfigsDow
     }
   },
 
+  /**
+   * @type {boolean}
+   * @default true
+   */
+  isPending: true,
+
+  /**
+   * @type {boolean}
+   * @default false
+   */
   isServicesInfoLoaded: false,
 
   initHosts: function() {
@@ -938,5 +948,85 @@ App.MainServiceItemController = Em.Controller.extend(App.SupportClientConfigsDow
     App.showAlertPopup(Em.I18n.t('services.service.actions.run.executeCustomCommand.error'),
error);
   },
 
-  isPending:true
+  /**
+   * delete service action
+   * @param {string} serviceName
+   */
+  deleteService: function(serviceName) {
+    var dependentServices = App.StackService.find(serviceName).get('requiredServices').filter(function(_serviceName)
{
+      return App.Service.find(_serviceName).get('isLoaded');
+    });
+    var self = this;
+    var displayName = App.format.role(serviceName);
+
+    if (dependentServices.length > 0) {
+      this.dependentServicesWarning(serviceName, dependentServices);
+    } else if (App.Service.find(serviceName).get('workStatus') === 'INSTALLED') {
+      App.showConfirmationPopup(
+        function() {self.confirmDeleteService(serviceName)},
+        Em.I18n.t('services.service.delete.popup.warning').format(displayName),
+        null,
+        Em.I18n.t('services.service.delete.popup.header'),
+        Em.I18n.t('common.delete'),
+        true
+      );
+    } else {
+      App.ModalPopup.show({
+        secondary: null,
+        header: Em.I18n.t('services.service.delete.popup.header'),
+        encodeBody: false,
+        body: Em.I18n.t('services.service.delete.popup.mustBeStopped').format(displayName)
+      });
+    }
+  },
+
+  /**
+   * warning that show dependent services which must be deleted prior to chosen service deletion
+   * @param {string} origin
+   * @param {string} dependent
+   * @returns {App.ModalPopup}
+   */
+  dependentServicesWarning: function(origin, dependent) {
+    var body = Em.I18n.t('services.service.delete.popup.dependentServices').format(App.format.role(origin));
+
+    body += '<ul>';
+    dependent.forEach(function(serviceName) {
+      body += '<li>' + App.format.role(serviceName) + '</li>';
+    });
+    body += '</ul>';
+
+    return App.ModalPopup.show({
+      secondary: null,
+      header: Em.I18n.t('services.service.delete.popup.header'),
+      bodyClass: Em.View.extend({
+        template: Em.Handlebars.compile(body)
+      })
+    });
+  },
+
+  /**
+   * Confirmation popup of service deletion
+   * @param {string} serviceName
+   */
+  confirmDeleteService: function (serviceName) {
+    var message = Em.I18n.t('services.service.confirmDelete.popup.body').format(App.format.role(serviceName));
+    var confirmKey = 'yes';
+
+    App.ModalPopup.show({
+      primary: Em.I18n.t('common.delete'),
+      primaryClass: 'btn-danger',
+      header: Em.I18n.t('services.service.confirmDelete.popup.header'),
+      confirmInput: '',
+      disablePrimary: Em.computed.notEqual('confirmInput', confirmKey),
+      bodyClass: Em.View.extend({
+        confirmKey: confirmKey,
+        template: Em.Handlebars.compile(message +
+        '<form class="form-inline align-center"></br>' +
+        '<label><b>{{t common.enter}}&nbsp;{{view.confirmKey}}</b></label>&nbsp;'
+
+        '{{view Ember.TextField valueBinding="view.parentView.confirmInput" class="input-small"}}</br>'
+
+        '</form>')
+      })
+    });
+  }
+
 });

http://git-wip-us.apache.org/repos/asf/ambari/blob/fad7367e/ambari-web/app/messages.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js
index e93aeff..2af22d1 100644
--- a/ambari-web/app/messages.js
+++ b/ambari-web/app/messages.js
@@ -293,6 +293,7 @@ Em.I18n.translations = {
   'common.optional': 'Optional',
   'common.running': 'Running',
   'common.stopped': 'Stopped',
+  'common.enter': 'Enter',
   'common.timeout.warning.popup.header': 'Automatic Logout',
   'common.timeout.warning.popup.body.before': 'You will be automatically logged out in ',
   'common.timeout.warning.popup.body.after': ' seconds due to inactivity',
@@ -1675,6 +1676,16 @@ Em.I18n.translations = {
   'services.service.actions.run.immediateStopHawqCluster.error': 'Error during remote command:
',
   'services.service.actions.manage_configuration_groups.short':'Manage Config Groups',
   'services.service.actions.serviceActions':'Service Actions',
+
+  'services.service.delete.popup.header': 'Delete Service',
+  'services.service.delete.popup.dependentServices': 'Prior to deleting <b>{0}</b>,
you must delete the following dependent services:',
+  'services.service.delete.popup.mustBeStopped': 'Prior to deleting <b>{0}</b>,
you must stop the service.',
+  'services.service.delete.popup.warning': 'The <b>{0} service will be removed from
Ambari and all configurations' +
+  ' and configuration history will be lost</b>',
+  'services.service.confirmDelete.popup.header': 'Confirm Delete',
+  'services.service.confirmDelete.popup.body': 'You must confirm delete of <b>{0}</b>
by typing "yes"' +
+  ' in the confirmation box. <b>This operation is not reversible and all configuration
history will be lost.</b>',
+
   'services.service.summary.unknown':'unknown',
   'services.service.summary.notRunning':'Not Running',
   'services.service.summary.notAvailable':'n/a',

http://git-wip-us.apache.org/repos/asf/ambari/blob/fad7367e/ambari-web/app/models/host_component.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/models/host_component.js b/ambari-web/app/models/host_component.js
index e63f634..0c013b1 100644
--- a/ambari-web/app/models/host_component.js
+++ b/ambari-web/app/models/host_component.js
@@ -384,6 +384,12 @@ App.HostComponentActionMap = {
         cssClass: 'icon-play-circle',
         isHidden: false,
         disabled: false
+      },
+      DELETE_SERVICE: {
+        action: 'deleteService',
+        context: ctx.get('serviceName'),
+        label: Em.I18n.t('common.delete'),
+        cssClass: 'icon-remove'
       }
     };
   }

http://git-wip-us.apache.org/repos/asf/ambari/blob/fad7367e/ambari-web/app/views/main/service/item.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/views/main/service/item.js b/ambari-web/app/views/main/service/item.js
index 1dfa937..cb9782c 100644
--- a/ambari-web/app/views/main/service/item.js
+++ b/ambari-web/app/views/main/service/item.js
@@ -192,15 +192,16 @@ App.MainServiceItemView = Em.View.extend({
         var hawqMasterCustomCommands = hawqMasterComponent.get('customCommands');
         customCommandToStopCluster = 'IMMEDIATE_STOP_CLUSTER';
         if (hawqMasterCustomCommands && hawqMasterCustomCommands.contains(customCommandToStopCluster))
{
-        options.push(self.createOption(actionMap.IMMEDIATE_STOP_CLUSTER, {
-          label: Em.I18n.t('services.service.actions.run.immediateStopHawqCluster.context'),
-          context: {
+          options.push(self.createOption(actionMap.IMMEDIATE_STOP_CLUSTER, {
             label: Em.I18n.t('services.service.actions.run.immediateStopHawqCluster.context'),
-            service: hawqMasterComponent.get('serviceName'),
-            component: hawqMasterComponent.get('componentName'),
-            command: customCommandToStopCluster
-          }
-        })) };
+            context: {
+              label: Em.I18n.t('services.service.actions.run.immediateStopHawqCluster.context'),
+              service: hawqMasterComponent.get('serviceName'),
+              component: hawqMasterComponent.get('componentName'),
+              command: customCommandToStopCluster
+            }
+          }))
+        }
       }
 
       self.addActionMap().filterProperty('service', serviceName).forEach(function(item) {
@@ -242,6 +243,8 @@ App.MainServiceItemView = Em.View.extend({
       options.push(actionMap.DOWNLOAD_CLIENT_CONFIGS);
     }
 
+    options.push(actionMap.DELETE_SERVICE);
+
     if (this.get('maintenance.length')) {
       this.get('maintenance').forEach(function(option, index) {
         if (JSON.stringify(option) != JSON.stringify(options[index])) {

http://git-wip-us.apache.org/repos/asf/ambari/blob/fad7367e/ambari-web/test/controllers/main/service/item_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/controllers/main/service/item_test.js b/ambari-web/test/controllers/main/service/item_test.js
index 7b75dbb..4fe46dc 100644
--- a/ambari-web/test/controllers/main/service/item_test.js
+++ b/ambari-web/test/controllers/main/service/item_test.js
@@ -1175,4 +1175,96 @@ describe('App.MainServiceItemController', function () {
       expect(App.showConfirmationPopup.calledOnce).to.equal(true);
     });
   });
+
+  describe("#deleteService()", function() {
+    var mainServiceItemController;
+
+    beforeEach(function() {
+      mainServiceItemController = App.MainServiceItemController.create({});
+      this.mockStackService = sinon.stub(App.StackService, 'find');
+      sinon.stub(mainServiceItemController, 'dependentServicesWarning');
+      this.mockService = sinon.stub(App.Service, 'find');
+      sinon.stub(App, 'showConfirmationPopup');
+      sinon.stub(App.ModalPopup, 'show');
+      sinon.stub(App.format, 'role', function(name) {return name});
+    });
+    afterEach(function() {
+      this.mockStackService.restore();
+      this.mockService.restore();
+      mainServiceItemController.dependentServicesWarning.restore();
+      App.showConfirmationPopup.restore();
+      App.ModalPopup.show.restore();
+      App.format.role.restore();
+    });
+
+    it("service has installed dependent services", function() {
+      this.mockStackService.returns(Em.Object.create({requiredServices: ['S2']}));
+      this.mockService.returns(Em.Object.create({workStatus: 'INSTALLED', isLoaded: true}));
+      mainServiceItemController.deleteService('S1');
+      expect(mainServiceItemController.dependentServicesWarning.calledWith('S1', ['S2'])).to.be.true;
+    });
+
+    it("service has not-installed dependent services, and stopped", function() {
+      this.mockStackService.returns(Em.Object.create({requiredServices: ['S2']}));
+      this.mockService.returns(Em.Object.create({workStatus: 'INSTALLED', isLoaded: false}));
+      mainServiceItemController.deleteService('S1');
+      expect(App.showConfirmationPopup.calledOnce).to.be.true;
+    });
+
+    it("service has not dependent services, and stopped", function() {
+      this.mockStackService.returns(Em.Object.create({requiredServices: []}));
+      this.mockService.returns(Em.Object.create({workStatus: 'INSTALLED', isLoaded: true}));
+      mainServiceItemController.deleteService('S1');
+      expect(App.showConfirmationPopup.calledOnce).to.be.true;
+    });
+
+    it("service has not dependent services, and not stopped", function() {
+      this.mockStackService.returns(Em.Object.create({requiredServices: []}));
+      this.mockService.returns(Em.Object.create({workStatus: 'STARTED', isLoaded: true}));
+      mainServiceItemController.deleteService('S1');
+      expect(App.ModalPopup.show.calledWith({
+        secondary: null,
+        header: Em.I18n.t('services.service.delete.popup.header'),
+        encodeBody: false,
+        body: Em.I18n.t('services.service.delete.popup.mustBeStopped').format('S1')
+      })).to.be.true;
+    });
+  });
+
+  describe("#dependentServicesWarning()", function() {
+    var mainServiceItemController;
+
+    beforeEach(function() {
+      mainServiceItemController = App.MainServiceItemController.create({});
+      sinon.stub(App.ModalPopup, 'show');
+      sinon.stub(App.format, 'role', function(name) {return name});
+    });
+    afterEach(function() {
+      App.ModalPopup.show.restore();
+      App.format.role.restore();
+    });
+
+    it("App.ModalPopup.show should be called", function() {
+      mainServiceItemController.dependentServicesWarning('S1', ['S2']);
+      expect(App.ModalPopup.show.calledOnce).to.be.true;
+    });
+  });
+
+  describe("#confirmDeleteService()", function() {
+    var mainServiceItemController;
+
+    beforeEach(function() {
+      mainServiceItemController = App.MainServiceItemController.create({});
+      sinon.stub(App.ModalPopup, 'show');
+    });
+    afterEach(function() {
+      App.ModalPopup.show.restore();
+    });
+
+    it("App.ModalPopup.show should be called", function() {
+      mainServiceItemController.confirmDeleteService();
+      expect(App.ModalPopup.show.calledOnce).to.be.true;
+    });
+  });
+
 });


Mime
View raw message