AMBARI-7446. Slider View: Destroy action should have more warnings. (onechiporenko)
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/4365e446 Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/4365e446 Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/4365e446 Branch: refs/heads/branch-alerts-dev Commit: 4365e44675b0432c58bc1510bd0a51825efcac92 Parents: 2be3212 Author: Oleg Nechiporenko <onechipore...@apache.org> Authored: Tue Sep 23 14:18:08 2014 +0300 Committer: Oleg Nechiporenko <onechipore...@apache.org> Committed: Tue Sep 23 14:18:08 2014 +0300 ---------------------------------------------------------------------- .../resources/ui/app/assets/data/apps/apps.json | 2 +- .../assets/data/resource/slider-properties.json | 1 + .../ui/app/controllers/slider_app_controller.js | 139 ++++++++++++------- .../ui/app/mappers/slider_apps_mapper.js | 4 +- .../resources/ui/app/styles/application.less | 32 +++++ .../resources/ui/app/templates/slider_app.hbs | 9 +- .../slider_app/destroy/destroy_popup.hbs | 20 +++ .../slider_app/destroy/destroy_popup_footer.hbs | 28 ++++ .../src/main/resources/ui/app/translations.js | 5 + .../slider_app/destroy_modal_footer_view.js | 41 ++++++ .../app/views/slider_app/destroy_popup_view.js | 37 +++++ 11 files changed, 265 insertions(+), 53 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/4365e446/contrib/views/slider/src/main/resources/ui/app/assets/data/apps/apps.json ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/assets/data/apps/apps.json b/contrib/views/slider/src/main/resources/ui/app/assets/data/apps/apps.json index 63aa0be..aff516b 100644 --- a/contrib/views/slider/src/main/resources/ui/app/assets/data/apps/apps.json +++ b/contrib/views/slider/src/main/resources/ui/app/assets/data/apps/apps.json @@ -12,7 +12,7 @@ "metrics" : null, "name" : "h4", "startTime" : 1409348496653, - "state" : "RUNNING", + "state" : "FROZEN", "type" : "hbase", "user" : "yarn", "version" : "1.0.0", http://git-wip-us.apache.org/repos/asf/ambari/blob/4365e446/contrib/views/slider/src/main/resources/ui/app/assets/data/resource/slider-properties.json ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/assets/data/resource/slider-properties.json b/contrib/views/slider/src/main/resources/ui/app/assets/data/resource/slider-properties.json index 3b69893..6901ab6 100644 --- a/contrib/views/slider/src/main/resources/ui/app/assets/data/resource/slider-properties.json +++ b/contrib/views/slider/src/main/resources/ui/app/assets/data/resource/slider-properties.json @@ -16,6 +16,7 @@ "hdfs.address" : "hdfs://slider-1.c.pramod-thangali.internal:8020", "yarn.resourcemanager.address" : "slider-2.c.pramod-thangali.internal:8050", "yarn.resourcemanager.scheduler.address" : "slider-2.c.pramod-thangali.internal:8030", + "yarn.resourcemanager.webapp.address" : "slider-2.c.pramod-thangali.internal:8088", "zookeeper.quorum" : "slider-1.c.pramod-thangali.internal:2181,slider-2.c.pramod-thangali.internal:2181,slider-3.c.pramod-thangali.internal:2181", "ganglia.server.hostname" : "bvc", "ganglia.custom.clusters" : "'HBaseCluster1','7000','AccumuloCluster1','7001','HBaseCluster2','7002'", http://git-wip-us.apache.org/repos/asf/ambari/blob/4365e446/contrib/views/slider/src/main/resources/ui/app/controllers/slider_app_controller.js ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/controllers/slider_app_controller.js b/contrib/views/slider/src/main/resources/ui/app/controllers/slider_app_controller.js index 94ae7e7..c193d4f 100644 --- a/contrib/views/slider/src/main/resources/ui/app/controllers/slider_app_controller.js +++ b/contrib/views/slider/src/main/resources/ui/app/controllers/slider_app_controller.js @@ -48,6 +48,7 @@ App.SliderAppController = Ember.ObjectController.extend(App.AjaxErrorHandler, { */ availableActions: function() { var actions = Em.A([]), + advanced = Em.A([]), status = this.get('model.status'); if ('RUNNING' === status) { actions.pushObject({ @@ -64,29 +65,78 @@ App.SliderAppController = Ember.ObjectController.extend(App.AjaxErrorHandler, { }); } if ('FROZEN' === status) { - actions.pushObjects([ - { - title: 'Start', - action: 'thaw', - confirm: false - }, - { - title: 'Destroy', - action: 'destroy', - confirm: true - } - ]); + actions.pushObject({ + title: 'Start', + action: 'thaw', + confirm: false + }); + advanced.pushObject({ + title: 'Destroy', + action: 'destroy', + customConfirm: 'confirmDestroy' + }); + } + if (advanced.length) { + actions.pushObject({ + title: 'Advanced', + submenu: advanced + }); } return actions; }.property('model.status'), /** + * Checkbox in the destroy-modal + * If true - enable "Destroy"-button + * @type {bool} + */ + confirmChecked: false, + + /** + * Inverted <code>confirmChecked</code>-value + * Used in <code>App.DestroyAppPopupFooterView</code> to enable "Destroy"-button + * @type {bool} + */ + destroyButtonEnabled: Ember.computed.not('confirmChecked'), + + /** * Method's name that should be called for model * @type {string} */ currentAction: null, /** + * Grouped components by name + * @type {{name: string, count: number}[]} + */ + groupedComponents: [], + + /** + * Does new instance counts are invalid + * @type {bool} + */ + groupedComponentsHaveErrors: false, + + /** + * Custom popup for "Destroy"-action + * @method destroyConfirm + */ + confirmDestroy: function() { + var modalComponent = this.container.lookup('component-lookup:main'). + lookupFactory('bs-modal', this.get('container')).create(); + modalComponent.setProperties({ + name: 'confirm-modal', + title: Ember.I18n.t('sliderApp.destroy.confirm.title'), + manual: true, + targetObject: this, + body: App.DestroyAppPopupView, + controller: this, + footerViews: [App.DestroyAppPopupFooterView] + }); + Bootstrap.ModalManager.register('confirm-modal', modalComponent); + }, + + /** * Try call controller's method with name stored in <code>currentAction</code> * @method tryDoAction */ @@ -149,21 +199,6 @@ App.SliderAppController = Ember.ObjectController.extend(App.AjaxErrorHandler, { }, /** - * Buttons for Flex modal popup - * @type {Em.Object[]} - */ - flexModalButtons: [ - Ember.Object.create({title: Em.I18n.t('common.cancel'), clicked:"closeFlex", dismiss: 'modal'}), - Ember.Object.create({title: Em.I18n.t('common.send'), clicked:"submitFlex", type:'success'}) - ], - - /** - * Grouped components by name - * @type {{name: string, count: number}[]} - */ - groupedComponents: [], - - /** * Group components by <code>componentName</code> and save them to <code>groupedComponents</code> * @method groupComponents */ @@ -186,12 +221,6 @@ App.SliderAppController = Ember.ObjectController.extend(App.AjaxErrorHandler, { }, /** - * Does new instance counts are invalid - * @type {bool} - */ - groupedComponentsHaveErrors: false, - - /** * Validate new instance counts for components (should be integer and >= 0) * @method validateGroupedComponents * @returns {boolean} @@ -222,7 +251,10 @@ App.SliderAppController = Ember.ObjectController.extend(App.AjaxErrorHandler, { 'flex-popup', 'Flex', 'slider_app/flex_popup', - this.get('flexModalButtons'), + Em.A([ + Ember.Object.create({title: Em.I18n.t('common.cancel'), clicked:"closeFlex", dismiss: 'modal'}), + Ember.Object.create({title: Em.I18n.t('common.send'), clicked:"submitFlex", type:'success'}) + ]), this ); }, @@ -271,7 +303,7 @@ App.SliderAppController = Ember.ObjectController.extend(App.AjaxErrorHandler, { }, /** - * Complate-callback for "destroy app"-request + * Complete-callback for "destroy app"-request * @method destroyCompleteCallback */ destroyCompleteCallback: function() { @@ -322,6 +354,7 @@ App.SliderAppController = Ember.ObjectController.extend(App.AjaxErrorHandler, { */ modalConfirmed: function() { this.tryDoAction(); + this.set('confirmChecked', false); return Bootstrap.ModalManager.close('confirm-modal'); }, @@ -331,6 +364,7 @@ App.SliderAppController = Ember.ObjectController.extend(App.AjaxErrorHandler, { * @method modalCanceled */ modalCanceled: function() { + this.set('confirmChecked', false); return Bootstrap.ModalManager.close('confirm-modal'); }, @@ -340,24 +374,31 @@ App.SliderAppController = Ember.ObjectController.extend(App.AjaxErrorHandler, { * @method openModal */ openModal: function(option) { + if (!option.action) return false; this.set('currentAction', option.action); - if (option.confirm) { - Bootstrap.ModalManager.open( - "confirm-modal", - Ember.I18n.t('common.confirmation'), - Ember.View.extend({ - template: Ember.Handlebars.compile('{{t question.sure}}') - }), - [ - Ember.Object.create({title: Em.I18n.t('common.cancel'), clicked:"modalCanceled", dismiss: 'modal'}), - Ember.Object.create({title: Em.I18n.t('ok'), clicked:"modalConfirmed", type:'success'}) - ], - this - ); + if (!Em.isNone(option.customConfirm) && Ember.typeOf(this.get(option.customConfirm)) === 'function') { + this[option.customConfirm](); } else { - this.tryDoAction(); + if (option.confirm) { + Bootstrap.ModalManager.open( + "confirm-modal", + Ember.I18n.t('common.confirmation'), + Ember.View.extend({ + template: Ember.Handlebars.compile('{{t question.sure}}') + }), + [ + Ember.Object.create({title: Em.I18n.t('common.cancel'), clicked:"modalCanceled", dismiss: 'modal'}), + Ember.Object.create({title: Em.I18n.t('ok'), clicked:"modalConfirmed", type:'success'}) + ], + this + ); + } + else { + this.tryDoAction(); + } } + return true; } } http://git-wip-us.apache.org/repos/asf/ambari/blob/4365e446/contrib/views/slider/src/main/resources/ui/app/mappers/slider_apps_mapper.js ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/mappers/slider_apps_mapper.js b/contrib/views/slider/src/main/resources/ui/app/mappers/slider_apps_mapper.js index 3cf80cc..70583f4 100644 --- a/contrib/views/slider/src/main/resources/ui/app/mappers/slider_apps_mapper.js +++ b/contrib/views/slider/src/main/resources/ui/app/mappers/slider_apps_mapper.js @@ -137,9 +137,9 @@ App.SliderAppsMapper = App.Mapper.createWithMixins(App.RunPeriodically, { } var yarnUI = "http://"+window.location.hostname+":8088"; var viewConfigs = App.SliderApp.store.all('sliderConfig'); - if (viewConfigs!=null) { + if (!Em.isNone(viewConfigs)) { var viewConfig = viewConfigs.findBy('viewConfigName', 'yarn.resourcemanager.webapp.address'); - if (viewConfig!=null) { + if (!Em.isNone(viewConfig)) { yarnUI = viewConfig.get('value'); } } http://git-wip-us.apache.org/repos/asf/ambari/blob/4365e446/contrib/views/slider/src/main/resources/ui/app/styles/application.less ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/styles/application.less b/contrib/views/slider/src/main/resources/ui/app/styles/application.less index 98f52d4..cc8ef7d 100644 --- a/contrib/views/slider/src/main/resources/ui/app/styles/application.less +++ b/contrib/views/slider/src/main/resources/ui/app/styles/application.less @@ -923,3 +923,35 @@ select { word-wrap: break-word; overflow: auto; } + +.dropdown-submenu { + position:relative; +} +.dropdown-submenu>.dropdown-menu { + top:0; + left:-100%; + margin-top:-6px; + margin-left:-1px; + -webkit-border-radius:6px 0 6px 6px; + -moz-border-radius:6px 0 6px 6px; + border-radius:6px 0 6px 6px; +} +.dropdown-submenu:hover>.dropdown-menu { + display:block; +} +.dropdown-submenu>a:before { + display:block; + content:" "; + float:left; + width:0; + height:0; + border-color:transparent; + border-style:solid; + border-width:5px 5px 5px 0px; + border-right-color:#cccccc; + margin-top:5px; + margin-left:-10px; +} +.dropdown-submenu:hover>a:after { + border-left-color:#ffffff; +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/4365e446/contrib/views/slider/src/main/resources/ui/app/templates/slider_app.hbs ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/templates/slider_app.hbs b/contrib/views/slider/src/main/resources/ui/app/templates/slider_app.hbs index 8e4b0df..46b6682 100644 --- a/contrib/views/slider/src/main/resources/ui/app/templates/slider_app.hbs +++ b/contrib/views/slider/src/main/resources/ui/app/templates/slider_app.hbs @@ -32,8 +32,15 @@ </a> <ul class="dropdown-menu"> {{#each option in controller.availableActions}} - <li> + <li {{bind-attr class="option.submenu.length:dropdown-submenu"}}> <a {{action 'openModal' option target='controller'}}>{{humanize option.title}}</a> + <ul class="dropdown-menu"> + {{#each subitem in option.submenu}} + <li> + <a {{action 'openModal' subitem target='controller'}}>{{humanize subitem.title}}</a> + </li> + {{/each}} + </ul> </li> {{/each}} </ul> http://git-wip-us.apache.org/repos/asf/ambari/blob/4365e446/contrib/views/slider/src/main/resources/ui/app/templates/slider_app/destroy/destroy_popup.hbs ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/templates/slider_app/destroy/destroy_popup.hbs b/contrib/views/slider/src/main/resources/ui/app/templates/slider_app/destroy/destroy_popup.hbs new file mode 100644 index 0000000..d696150 --- /dev/null +++ b/contrib/views/slider/src/main/resources/ui/app/templates/slider_app/destroy/destroy_popup.hbs @@ -0,0 +1,20 @@ +{{! +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +}} + +<p class="alert alert-danger"> <span class="icon-warning-sign"></span> {{t sliderApp.destroy.confirm.body}}</p> +{{input type="checkbox" checkedBinding="controller.confirmChecked"}} {{{view.confirmMessage}}} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/4365e446/contrib/views/slider/src/main/resources/ui/app/templates/slider_app/destroy/destroy_popup_footer.hbs ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/templates/slider_app/destroy/destroy_popup_footer.hbs b/contrib/views/slider/src/main/resources/ui/app/templates/slider_app/destroy/destroy_popup_footer.hbs new file mode 100644 index 0000000..e6c38a5 --- /dev/null +++ b/contrib/views/slider/src/main/resources/ui/app/templates/slider_app/destroy/destroy_popup_footer.hbs @@ -0,0 +1,28 @@ +{{! +* Licensed to the Apache Software Foundation (ASF) under one +* or more contributor license agreements. See the NOTICE file +* distributed with this work for additional information +* regarding copyright ownership. The ASF licenses this file +* to you under the Apache License, Version 2.0 (the +* "License"); you may not use this file except in compliance +* with the License. You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +}} + +{{bs-button + content=view.cancelButton + targetObjectBinding="view.targetObject" +}} + +{{bs-button + content=view.destroyButton + disabledBinding="controller.destroyButtonEnabled" + targetObjectBinding="view.targetObject" +}} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/4365e446/contrib/views/slider/src/main/resources/ui/app/translations.js ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/translations.js b/contrib/views/slider/src/main/resources/ui/app/translations.js index 83be669..cead07b 100644 --- a/contrib/views/slider/src/main/resources/ui/app/translations.js +++ b/contrib/views/slider/src/main/resources/ui/app/translations.js @@ -31,6 +31,7 @@ Em.I18n.translations = { 'name': "Name", 'back': "Back", 'delete': 'Delete', + 'destroy': 'Destroy', 'value': "Value", 'next': "Next", 'quickLinks': "Quick Links", @@ -97,6 +98,10 @@ Em.I18n.translations = { 'sliderApp.alerts.brLastCheck': "\nLast Checked {0}", 'sliderApp.alerts.occurredOn': 'Occurred on {0}, {1}', + 'sliderApp.destroy.confirm.title': 'Destroy Slider App', + 'sliderApp.destroy.confirm.body': 'Destroying a Slider App could result in data loss if not property performed. Make sure you have backed up data handled by the application.', + 'sliderApp.destroy.confirm.body2': 'Are you sure you want to destroy Slider App <em>{0}</em>?', + 'wizard.name': 'Create App', 'wizard.step1.name': 'Select Type', 'wizard.step1.header': 'Available Applications', http://git-wip-us.apache.org/repos/asf/ambari/blob/4365e446/contrib/views/slider/src/main/resources/ui/app/views/slider_app/destroy_modal_footer_view.js ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/views/slider_app/destroy_modal_footer_view.js b/contrib/views/slider/src/main/resources/ui/app/views/slider_app/destroy_modal_footer_view.js new file mode 100644 index 0000000..0bab4ae --- /dev/null +++ b/contrib/views/slider/src/main/resources/ui/app/views/slider_app/destroy_modal_footer_view.js @@ -0,0 +1,41 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +App.DestroyAppPopupFooterView = Ember.View.extend({ + + /** + * targetObject should be defined for buttons and other components that may set actions + * @type {Em.Controller} + */ + targetObjectBinding: 'controller', + + templateName: 'slider_app/destroy/destroy_popup_footer', + + /** + * Destroy-button + * @type {Em.Object} + */ + destroyButton: Em.Object.create({title: Em.I18n.t('common.destroy'), clicked: "modalConfirmed", type:'success'}), + + /** + * Cancel-button + * @type {Em.Object} + */ + cancelButton: Em.Object.create({title: Em.I18n.t('common.cancel'), clicked: "modalCanceled"}) + +}); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/4365e446/contrib/views/slider/src/main/resources/ui/app/views/slider_app/destroy_popup_view.js ---------------------------------------------------------------------- diff --git a/contrib/views/slider/src/main/resources/ui/app/views/slider_app/destroy_popup_view.js b/contrib/views/slider/src/main/resources/ui/app/views/slider_app/destroy_popup_view.js new file mode 100644 index 0000000..f1ce6ba --- /dev/null +++ b/contrib/views/slider/src/main/resources/ui/app/views/slider_app/destroy_popup_view.js @@ -0,0 +1,37 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +App.DestroyAppPopupView = Ember.View.extend({ + + templateName: 'slider_app/destroy/destroy_popup', + + /** + * targetObject should be defined for buttons and other components that may set actions + * @type {Em.Controller} + */ + targetObjectBinding: 'controller', + + /** + * Warning message for dummy user + * @type {string} + */ + confirmMessage: function() { + return Em.I18n.t('sliderApp.destroy.confirm.body2').format(this.get('controller.model.name')); + }.property() + +}); \ No newline at end of file