Repository: ambari Updated Branches: refs/heads/trunk a80dc9ac9 -> ca7b8fdb8
AMBARI-8463. Alerts UI: Manage Notifications dialog needs Edit/Create/Remove/Duplicate ability. (akovalenko) Project: http://git-wip-us.apache.org/repos/asf/ambari/repo Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/ca7b8fdb Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/ca7b8fdb Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/ca7b8fdb Branch: refs/heads/trunk Commit: ca7b8fdb89979ec587626649f1e8931808bc8887 Parents: a80dc9a Author: Aleksandr Kovalenko <[email protected]> Authored: Thu Nov 27 15:25:54 2014 +0200 Committer: Aleksandr Kovalenko <[email protected]> Committed: Thu Nov 27 15:25:54 2014 +0200 ---------------------------------------------------------------------- ambari-web/app/assets/test/tests.js | 2 + .../manage_alert_notifications_controller.js | 254 ++++++++++- .../app/mappers/alert_notification_mapper.js | 69 ++- ambari-web/app/messages.js | 3 + ambari-web/app/models/alert_notification.js | 21 +- ambari-web/app/styles/alerts.less | 18 + .../main/alerts/create_alert_notification.hbs | 74 ++++ .../alerts/manage_alert_notifications_popup.hbs | 4 +- .../templates/main/alerts/severity_filter.hbs | 30 ++ ambari-web/app/utils/ajax/ajax.js | 23 +- ambari-web/app/views.js | 1 + .../alerts/manage_alert_notifications_view.js | 10 +- .../views/main/alerts/severity_filter_view.js | 52 +++ .../manage_alert_groups_controller_test.js | 4 - ...anage_alert_notifications_controller_test.js | 437 +++++++++++++++++++ 15 files changed, 946 insertions(+), 56 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ambari/blob/ca7b8fdb/ambari-web/app/assets/test/tests.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/assets/test/tests.js b/ambari-web/app/assets/test/tests.js index d165276..77f2869 100644 --- a/ambari-web/app/assets/test/tests.js +++ b/ambari-web/app/assets/test/tests.js @@ -50,6 +50,7 @@ var files = ['test/init_model_test', 'test/controllers/main/alerts/definitions_details_controller_test', 'test/controllers/main/alerts/alert_instances_controller_test', 'test/controllers/main/alerts/add_alert_definition/step1_controller_test', + 'test/controllers/main/alerts/manage_alert_notifications_controller_test', 'test/controllers/main/admin/stack_and_upgrade_controller_test', 'test/controllers/main/admin/stack_version/stack_version_details_controller_test', 'test/controllers/main/admin/serviceAccounts_controller_test', @@ -239,6 +240,7 @@ var files = ['test/init_model_test', 'test/models/host_stack_version_test', //contains test with fake timers that affect Date 'test/utils/lazy_loading_test' + ]; App.initialize(); describe('Ambari Web Unit tests', function() { http://git-wip-us.apache.org/repos/asf/ambari/blob/ca7b8fdb/ambari-web/app/controllers/main/alerts/manage_alert_notifications_controller.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/controllers/main/alerts/manage_alert_notifications_controller.js b/ambari-web/app/controllers/main/alerts/manage_alert_notifications_controller.js index 160de40..a6d13b1 100644 --- a/ambari-web/app/controllers/main/alerts/manage_alert_notifications_controller.js +++ b/ambari-web/app/controllers/main/alerts/manage_alert_notifications_controller.js @@ -25,6 +25,57 @@ App.ManageAlertNotificationsController = Em.Controller.extend({ isLoaded: false, /** + * Create/Edit modal popup object + * used to hide popup + * @type {App.ModalPopup} + */ + createEditPopup: null, + + /** + * Map of edit inputs shown in Create/Edit Notification popup + * @type {Object} + */ + inputFields: Em.Object.create({ + name: { + label: Em.I18n.t('common.name'), + value: '', + defaultValue: '' + }, + groups: { + label: Em.I18n.t('common.groups'), + value: '', + defaultValue: '' + }, + method: { + label: Em.I18n.t('alerts.actions.manage_alert_notifications_popup.method'), + value: '', + defaultValue: '' + }, + email: { + label: Em.I18n.t('alerts.actions.manage_alert_notifications_popup.email'), + value: '', + defaultValue: '' + }, + severityFilter: { + label: Em.I18n.t('alerts.actions.manage_alert_notifications_popup.severityFilter'), + value: [true, true, true, true], + defaultValue: [true, true, true, true] + }, + description: { + label: Em.I18n.t('common.description'), + value: '', + defaultValue: '' + } + }), + + /** + * List of available Notification types + * used in Type combobox + * @type {Array} + */ + methods: ['EMAIL', 'SNMP'], + + /** * List of all Alert Notifications * @type {App.AlertNotification[]} */ @@ -47,13 +98,10 @@ App.ManageAlertNotificationsController = Em.Controller.extend({ * @returns {$.ajax|null} */ loadAlertNotifications: function () { - if (this.get('isLoaded')) { - return null; - } + this.set('isLoaded', false); return App.ajax.send({ name: 'alerts.notifications', sender: this, - data: {}, success: 'getAlertNotificationsSuccessCallback', error: 'getAlertNotificationsErrorCallback' }); @@ -77,8 +125,198 @@ App.ManageAlertNotificationsController = Em.Controller.extend({ this.set('isLoaded', true); }, - addAlertNotification: Em.K, - deleteAlertNotification: Em.K, - editAlertNotification: Em.K, - duplicateAlertNotification: Em.K + /** + * Add Notification button handler + */ + addAlertNotification: function () { + var inputFields = this.get('inputFields'); + Em.keys(inputFields).forEach(function (key) { + inputFields.set(key + '.value', inputFields.get(key + '.defaultValue')); + }); + this.showCreateEditPopup(false); + }, + + /** + * Edit Notification button handler + */ + editAlertNotification: function () { + this.fillEditCreateInputs(); + this.showCreateEditPopup(true); + }, + + /** + * Fill inputs of Create/Edit popup form + * @param addCopyToName define whether add 'Copy of ' to name + */ + fillEditCreateInputs: function (addCopyToName) { + var inputFields = this.get('inputFields'); + var selectedAlertNotification = this.get('selectedAlertNotification'); + inputFields.set('name.value', (addCopyToName ? 'Copy of ' : '') + selectedAlertNotification.get('name')); + inputFields.set('email.value', selectedAlertNotification.get('properties')['ambari.dispatch.recipients'] ? + selectedAlertNotification.get('properties')['ambari.dispatch.recipients'].join(', ') : ''); + inputFields.set('severityFilter.value', [ + selectedAlertNotification.get('alertStates').contains('OK'), + selectedAlertNotification.get('alertStates').contains('WARNING'), + selectedAlertNotification.get('alertStates').contains('CRITICAL'), + selectedAlertNotification.get('alertStates').contains('UNKNOWN') + ]); + inputFields.set('description.value', selectedAlertNotification.get('description')); + inputFields.set('method.value', selectedAlertNotification.get('type')); + }, + + /** + * Show Edit or Create Notification popup + * @param isEdit + * @returns {App.ModalPopup} + */ + showCreateEditPopup: function (isEdit) { + var self = this; + var createEditPopup = App.ModalPopup.show({ + header: isEdit ? Em.I18n.t('alerts.actions.manage_alert_notifications_popup.editHeader') : Em.I18n.t('alerts.actions.manage_alert_notifications_popup.addHeader'), + bodyClass: Em.View.extend({ + controller: this, + templateName: require('templates/main/alerts/create_alert_notification'), + isEmailMethodSelected: function () { + return this.get('controller.inputFields.method.value') === 'EMAIL'; + }.property('controller.inputFields.method.value') + }), + primary: Em.I18n.t('common.save'), + onPrimary: function () { + this.set('disablePrimary', true); + var apiObject = self.formatNotificationAPIObject(); + if (isEdit) { + self.updateAlertNotification(apiObject); + } else { + self.createAlertNotification(apiObject); + } + } + }); + this.set('createEditPopup', createEditPopup); + return createEditPopup; + }, + + /** + * Create API-formatted object from data populate by user + * @returns {Object} + */ + formatNotificationAPIObject: function () { + var inputFields = this.get('inputFields'); + var alertStates = []; + var properties = {}; + if (inputFields.severityFilter.value[0]) { + alertStates.push('OK'); + } + if (inputFields.severityFilter.value[1]) { + alertStates.push('WARNING'); + } + if (inputFields.severityFilter.value[2]) { + alertStates.push('CRITICAL'); + } + if (inputFields.severityFilter.value[3]) { + alertStates.push('UNKNOWN'); + } + if (inputFields.method.value === 'EMAIL') { + properties['ambari.dispatch.recipients'] = inputFields.email.value.replace(/\s/g, '').split(','); + } + return { + AlertTarget: { + name: inputFields.name.value, + description: inputFields.description.value, + notification_type: inputFields.method.value, + alert_states: alertStates, + properties: properties + } + }; + }, + + /** + * Send request to server to create Alert Notification + * @param apiObject + * @returns {$.ajax} + */ + createAlertNotification: function (apiObject) { + return App.ajax.send({ + name: 'alerts.create_alert_notification', + sender: this, + data: { + data: apiObject + }, + success: 'createAlertNotificationSuccessCallback' + }); + }, + + /** + * Success callback for <code>createAlertNotification</code> + */ + createAlertNotificationSuccessCallback: function () { + this.loadAlertNotifications(); + var createEditPopup = this.get('createEditPopup'); + if (createEditPopup) { + createEditPopup.hide(); + } + }, + + /** + * Send request to server to update Alert Notification + * @param apiObject + * @returns {$.ajax} + */ + updateAlertNotification: function (apiObject) { + return App.ajax.send({ + name: 'alerts.update_alert_notification', + sender: this, + data: { + data: apiObject, + id: this.get('selectedAlertNotification.id') + }, + success: 'updateAlertNotificationSuccessCallback' + }); + }, + + /** + * Success callback for <code>updateAlertNotification</code> + */ + updateAlertNotificationSuccessCallback: function () { + this.loadAlertNotifications(); + var createEditPopup = this.get('createEditPopup'); + if (createEditPopup) { + createEditPopup.hide(); + } + }, + + /** + * Delete Notification button handler + */ + deleteAlertNotification: function () { + var self = this; + return App.showConfirmationPopup(function () { + App.ajax.send({ + name: 'alerts.delete_alert_notification', + sender: self, + data: { + id: self.get('selectedAlertNotification.id') + }, + success: 'deleteAlertNotificationSuccessCallback' + }); + }); + }, + + /** + * Success callback for <code>deleteAlertNotification</code> + */ + deleteAlertNotificationSuccessCallback: function () { + this.loadAlertNotifications(); + var selectedAlertNotification = this.get('selectedAlertNotification'); + selectedAlertNotification.deleteRecord(); + this.set('selectedAlertNotification', null); + }, + + /** + * Duplicate Notification button handler + */ + duplicateAlertNotification: function () { + this.fillEditCreateInputs(true); + this.showCreateEditPopup(); + } + }); http://git-wip-us.apache.org/repos/asf/ambari/blob/ca7b8fdb/ambari-web/app/mappers/alert_notification_mapper.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/mappers/alert_notification_mapper.js b/ambari-web/app/mappers/alert_notification_mapper.js index 3fc0aaf..ba59477 100644 --- a/ambari-web/app/mappers/alert_notification_mapper.js +++ b/ambari-web/app/mappers/alert_notification_mapper.js @@ -1,29 +1,60 @@ /** - * 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. - */ + * 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. + */ var App = require('app'); App.alertNotificationMapper = App.QuickDataMapper.create({ - model : App.AlertNotification, - config : { + model: App.AlertNotification, + config: { id: 'AlertTarget.id', name: 'AlertTarget.name', type: 'AlertTarget.notification_type', - description: 'AlertTarget.description', - properties: 'AlertTarget.properties' + description: 'AlertTarget.description' + }, + + map: function (json) { + if (json.items) { + var result = []; + var notificationsProperties = {}; + var notificationsAlertStates = {}; + + json.items.forEach(function (item) { + result.push(this.parseIt(item, this.config)); + notificationsProperties[item.AlertTarget.id] = item.AlertTarget.properties; + notificationsAlertStates[item.AlertTarget.id] = item.AlertTarget.alert_states; + }, this); + + App.store.loadMany(this.get('model'), result); + this.setProperties('properties', notificationsProperties); + this.setProperties('alertStates', notificationsAlertStates); + } + }, + + /** + * Set values from <code>propertyMap</code> for <code>propertyName</code> for each record in model + * @param propertyName + * @param propertiesMap record_id to value map + */ + setProperties: function (propertyName, propertiesMap) { + var modelRecords = this.get('model').find(); + for (var recordId in propertiesMap) { + if (propertiesMap.hasOwnProperty(recordId)) { + modelRecords.findProperty('id', +recordId).set(propertyName, propertiesMap[recordId]); + } + } } }); \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/ca7b8fdb/ambari-web/app/messages.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/messages.js b/ambari-web/app/messages.js index a77d74d..302f2b5 100644 --- a/ambari-web/app/messages.js +++ b/ambari-web/app/messages.js @@ -1791,11 +1791,14 @@ Em.I18n.translations = { 'alerts.actions.manage_alert_notifications_popup.header':'Manage Alert Notifications', 'alerts.actions.manage_alert_notifications_popup.addButton':'Create new Alert Notification', + 'alerts.actions.manage_alert_notifications_popup.addHeader':'Create Alert Notification', 'alerts.actions.manage_alert_notifications_popup.removeButton':'Delete Alert Notification', 'alerts.actions.manage_alert_notifications_popup.editButton':'Edit Alert Notification', + 'alerts.actions.manage_alert_notifications_popup.editHeader':'Edit Notification', 'alerts.actions.manage_alert_notifications_popup.duplicateButton':'Duplicate Alert Notification', 'alerts.actions.manage_alert_notifications_popup.method':'Method', 'alerts.actions.manage_alert_notifications_popup.email':'Email', + 'alerts.actions.manage_alert_notifications_popup.severityFilter':'Severity Filter', 'hosts.host.add':'Add New Hosts', 'hosts.table.noHosts':'No hosts to display', http://git-wip-us.apache.org/repos/asf/ambari/blob/ca7b8fdb/ambari-web/app/models/alert_notification.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/models/alert_notification.js b/ambari-web/app/models/alert_notification.js index 6f5db0a..2ad89f3 100644 --- a/ambari-web/app/models/alert_notification.js +++ b/ambari-web/app/models/alert_notification.js @@ -23,22 +23,9 @@ App.AlertNotification = DS.Model.extend({ name: DS.attr('string'), type: DS.attr('string'), description: DS.attr('string'), - properties: DS.attr('string') + + properties: {}, + alertStates: [] }); -App.AlertNotification.FIXTURES = [ - { - "description" : "Admins", - "id" : 1, - "name" : "Administrators", - "type" : "EMAIL", - "properties" : "" - }, - { - "description" : "Operators", - "id" : 2, - "name" : "Operators", - "type" : "SNMP", - "properties" : "" - } -]; \ No newline at end of file +App.AlertNotification.FIXTURES = []; \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ambari/blob/ca7b8fdb/ambari-web/app/styles/alerts.less ---------------------------------------------------------------------- diff --git a/ambari-web/app/styles/alerts.less b/ambari-web/app/styles/alerts.less index e9783cb..2f9cc93 100644 --- a/ambari-web/app/styles/alerts.less +++ b/ambari-web/app/styles/alerts.less @@ -275,6 +275,24 @@ } } +#manage-alert-notifications-error { + margin-bottom: 20px +} + +#create-edit-alert-notification { + .form-horizontal { + .controls { + margin-left: 140px; + } + } + label { + width: 115px; + &.checkbox { + width: inherit; + } + } +} + /*****start styles for alerts popup*****/ .alerts-popup { .modal-body, .modal-footer, .modal-header { http://git-wip-us.apache.org/repos/asf/ambari/blob/ca7b8fdb/ambari-web/app/templates/main/alerts/create_alert_notification.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/main/alerts/create_alert_notification.hbs b/ambari-web/app/templates/main/alerts/create_alert_notification.hbs new file mode 100644 index 0000000..37ac7a9 --- /dev/null +++ b/ambari-web/app/templates/main/alerts/create_alert_notification.hbs @@ -0,0 +1,74 @@ +{{! +* 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. +}} + +<div id="create-edit-alert-notification"> + + <form class="form-horizontal"> + + <div class="control-group"> + <label class="control-label" for="inputName">{{controller.inputFields.name.label}}</label> + + <div class="controls"> + {{view Em.TextField valueBinding="controller.inputFields.name.value" id="inputName" class="input-xlarge"}} + </div> + </div> + + <div class="control-group"> + <label class="control-label" for="inputGroups">{{controller.inputFields.groups.label}}</label> + + <div class="controls"> + {{view Em.TextField valueBinding="controller.inputFields.groups.value" id="inputGroups" class="input-xlarge"}} + </div> + </div> + + <div class="control-group"> + <label class="control-label" for="inputMethod">{{controller.inputFields.method.label}}</label> + + <div class="controls"> + {{view Em.Select contentBinding="controller.methods" selectionBinding="controller.inputFields.method.value" id="inputMethod" class="input-xlarge"}} + </div> + </div> + + {{#if view.isEmailMethodSelected}} + <div class="control-group"> + <label class="control-label" for="inputEmail">{{controller.inputFields.email.label}}</label> + + <div class="controls"> + {{view Em.TextField valueBinding="controller.inputFields.email.value" id="inputEmail" class="input-xlarge"}} + </div> + </div> + {{/if}} + + <div class="control-group"> + <label class="control-label">{{controller.inputFields.severityFilter.label}}</label> + + <div class="controls"> + {{view App.AlertSeverityFilterView selectionBinding="controller.inputFields.severityFilter.value"}} + </div> + </div> + + <div class="control-group"> + <label class="control-label" for="inputDescription">{{controller.inputFields.description.label}}</label> + + <div class="controls"> + {{view Em.TextArea valueBinding="controller.inputFields.description.value" id="inputDescription" rows="4" class="input-xlarge"}} + </div> + </div> + + </form> +</div> http://git-wip-us.apache.org/repos/asf/ambari/blob/ca7b8fdb/ambari-web/app/templates/main/alerts/manage_alert_notifications_popup.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/main/alerts/manage_alert_notifications_popup.hbs b/ambari-web/app/templates/main/alerts/manage_alert_notifications_popup.hbs index 1956494..603e022 100644 --- a/ambari-web/app/templates/main/alerts/manage_alert_notifications_popup.hbs +++ b/ambari-web/app/templates/main/alerts/manage_alert_notifications_popup.hbs @@ -37,7 +37,7 @@ {{translateAttr data-original-title="alerts.actions.manage_alert_notifications_popup.removeButton"}} {{bindAttr disabled="view.isRemoveButtonDisabled"}} {{action deleteAlertNotification target="controller"}}><i class="icon-minus"></i></button> - <div class="btn-group dropup"> + <div class="btn-group"> <button class="btn dropdown-toggle" data-toggle="dropdown"> <i class="icon-cog"></i> <span class="caret"></span> </button> @@ -92,7 +92,7 @@ </div> <div class="clearfix"></div> <div class="row-fluid"> - <div class="span12 text-error" id="manage-config-group-error-div"> + <div class="span12 text-error" id="manage-alert-notifications-error"> {{#if controller.errorMessage}} {{controller.errorMessage}} {{else}} http://git-wip-us.apache.org/repos/asf/ambari/blob/ca7b8fdb/ambari-web/app/templates/main/alerts/severity_filter.hbs ---------------------------------------------------------------------- diff --git a/ambari-web/app/templates/main/alerts/severity_filter.hbs b/ambari-web/app/templates/main/alerts/severity_filter.hbs new file mode 100644 index 0000000..cfb7dae --- /dev/null +++ b/ambari-web/app/templates/main/alerts/severity_filter.hbs @@ -0,0 +1,30 @@ +{{! +* 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. +}} + +<label class="checkbox inline"> + {{view Em.Checkbox checkedBinding="view.okChecked"}} OK +</label> +<label class="checkbox inline"> + {{view Em.Checkbox checkedBinding="view.warningChecked"}} WARNING +</label> +<label class="checkbox inline"> + {{view Em.Checkbox checkedBinding="view.criticalChecked"}} CRITICAL +</label> +<label class="checkbox inline"> + {{view Em.Checkbox checkedBinding="view.unknownChecked"}} UNKNOWN +</label> http://git-wip-us.apache.org/repos/asf/ambari/blob/ca7b8fdb/ambari-web/app/utils/ajax/ajax.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/utils/ajax/ajax.js b/ambari-web/app/utils/ajax/ajax.js index 47fda77..9cc559f 100644 --- a/ambari-web/app/utils/ajax/ajax.js +++ b/ambari-web/app/utils/ajax/ajax.js @@ -386,12 +386,33 @@ var urls = { 'alerts.delete_alert_definition': { 'real': '/clusters/{clusterName}/alert_definitions/{id}', 'mock': '', + 'type': 'DELETE' + }, + 'alerts.create_alert_notification': { + 'real': '/alert_targets', + 'mock': '', 'format': function (data) { return { - type: 'DELETE' + type: 'POST', + data: JSON.stringify(data.data) } } }, + 'alerts.update_alert_notification': { + 'real': '/alert_targets/{id}', + 'mock': '', + 'format': function (data) { + return { + type: 'PUT', + data: JSON.stringify(data.data) + } + } + }, + 'alerts.delete_alert_notification': { + 'real': '/alert_targets/{id}', + 'mock': '', + 'type': 'DELETE' + }, 'background_operations.get_most_recent': { 'real': '/clusters/{clusterName}/requests?to=end&page_size={operationsCount}&fields=Requests', 'mock': '/data/background_operations/list_on_start.json', http://git-wip-us.apache.org/repos/asf/ambari/blob/ca7b8fdb/ambari-web/app/views.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views.js b/ambari-web/app/views.js index 9e21516..3b45d59 100644 --- a/ambari-web/app/views.js +++ b/ambari-web/app/views.js @@ -53,6 +53,7 @@ require('views/main/alerts/add_alert_definition/step3_view'); require('views/main/alerts'); require('views/main/alerts/manage_alert_groups_view'); require('views/main/alerts/manage_alert_notifications_view'); +require('views/main/alerts/severity_filter_view'); require('views/main/charts'); require('views/main/views/details'); require('views/main/host'); http://git-wip-us.apache.org/repos/asf/ambari/blob/ca7b8fdb/ambari-web/app/views/main/alerts/manage_alert_notifications_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/alerts/manage_alert_notifications_view.js b/ambari-web/app/views/main/alerts/manage_alert_notifications_view.js index 8ed67e9..f5fe600 100644 --- a/ambari-web/app/views/main/alerts/manage_alert_notifications_view.js +++ b/ambari-web/app/views/main/alerts/manage_alert_notifications_view.js @@ -71,12 +71,11 @@ App.ManageAlertNotificationsView = Em.View.extend({ */ onAlertNotificationSelect: function () { var selectedAlertNotification = this.get('selectedAlertNotification'); - var length = selectedAlertNotification.length; - if (selectedAlertNotification && length) { - this.set('controller.selectedAlertNotification', selectedAlertNotification[length - 1]); + if (selectedAlertNotification && selectedAlertNotification.length) { + this.set('controller.selectedAlertNotification', selectedAlertNotification[selectedAlertNotification.length - 1]); } - if (selectedAlertNotification && length > 1) { - this.set('selectedAlertNotification', selectedAlertNotification[length - 1]); + if (selectedAlertNotification && selectedAlertNotification.length > 1) { + this.set('selectedAlertNotification', selectedAlertNotification[selectedAlertNotification.length - 1]); } }.observes('selectedAlertNotification'), @@ -90,6 +89,7 @@ App.ManageAlertNotificationsView = Em.View.extend({ var notifications = this.get('controller.alertNotifications'); if (notifications && notifications.length) { this.set('selectedAlertNotification', notifications[0]); + this.buttonObserver(); } else { this.set('selectedAlertNotification', null); } http://git-wip-us.apache.org/repos/asf/ambari/blob/ca7b8fdb/ambari-web/app/views/main/alerts/severity_filter_view.js ---------------------------------------------------------------------- diff --git a/ambari-web/app/views/main/alerts/severity_filter_view.js b/ambari-web/app/views/main/alerts/severity_filter_view.js new file mode 100644 index 0000000..af4544c --- /dev/null +++ b/ambari-web/app/views/main/alerts/severity_filter_view.js @@ -0,0 +1,52 @@ +/** + * 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.AlertSeverityFilterView = Em.View.extend({ + + templateName: require('templates/main/alerts/severity_filter'), + + /** + * Array of Boolean values binded to checkboxes + * @type {Array} + */ + selection: [], + + didInsertElement: function () { + this.set('okChecked', this.get('selection')[0]); + this.set('warningChecked', this.get('selection')[1]); + this.set('criticalChecked', this.get('selection')[2]); + this.set('unknownChecked', this.get('selection')[3]); + this.addObserver('okChecked', this, 'onChange'); + this.addObserver('warningChecked', this, 'onChange'); + this.addObserver('criticalChecked', this, 'onChange'); + this.addObserver('unknownChecked', this, 'onChange'); + }, + + okChecked: true, + + warningChecked: true, + + criticalChecked: true, + + unknownChecked: true, + + onChange: function () { + this.set('selection', [this.get('okChecked'), this.get('warningChecked'), this.get('criticalChecked'), this.get('unknownChecked')]); + } + +}); http://git-wip-us.apache.org/repos/asf/ambari/blob/ca7b8fdb/ambari-web/test/controllers/main/alerts/manage_alert_groups_controller_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/controllers/main/alerts/manage_alert_groups_controller_test.js b/ambari-web/test/controllers/main/alerts/manage_alert_groups_controller_test.js index 89bbc1b..cdf46c6 100644 --- a/ambari-web/test/controllers/main/alerts/manage_alert_groups_controller_test.js +++ b/ambari-web/test/controllers/main/alerts/manage_alert_groups_controller_test.js @@ -17,12 +17,8 @@ */ var App = require('app'); -var c; describe('App.ManageAlertGroupsController', function() { - beforeEach(function() { - c = App.ManageAlertGroupsController.create({}); - }); var manageAlertGroupsController = App.ManageAlertGroupsController.create({}); describe('#addAlertGroup', function() { http://git-wip-us.apache.org/repos/asf/ambari/blob/ca7b8fdb/ambari-web/test/controllers/main/alerts/manage_alert_notifications_controller_test.js ---------------------------------------------------------------------- diff --git a/ambari-web/test/controllers/main/alerts/manage_alert_notifications_controller_test.js b/ambari-web/test/controllers/main/alerts/manage_alert_notifications_controller_test.js new file mode 100644 index 0000000..15f9ede --- /dev/null +++ b/ambari-web/test/controllers/main/alerts/manage_alert_notifications_controller_test.js @@ -0,0 +1,437 @@ +/** + * 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. + */ + +var App = require('app'); +var controller; +describe('App.ManageAlertNotificationsController', function () { + + beforeEach(function () { + controller = App.ManageAlertNotificationsController.create({}); + sinon.spy(App.ajax, 'send'); + }); + + afterEach(function () { + App.ajax.send.restore(); + }); + + describe('#alertNotifications', function () { + + beforeEach(function () { + sinon.stub(App.AlertNotification, 'find', function () { + return [1, 2, 3]; + }); + }); + + afterEach(function () { + App.AlertNotification.find.restore(); + }); + + it("should return all alert notifications if controller isLoaded", function () { + + controller.set('isLoaded', true); + expect(controller.get('alertNotifications')).to.eql([1, 2, 3]); + }); + + it("should return [] if controller isLoaded=false", function () { + + controller.set('isLoaded', false); + expect(controller.get('alertNotifications')).to.eql([]); + }); + + }); + + describe('#loadAlertNotifications()', function () { + + it("should send ajax request and set isLoaded to false", function () { + + controller.set('isLoaded', true); + controller.loadAlertNotifications(); + expect(controller.get('isLoaded')).to.be.false; + expect(App.ajax.send.calledOnce).to.be.true; + }); + + }); + + describe('#getAlertNotificationsSuccessCallback()', function () { + + beforeEach(function () { + sinon.spy(App.alertNotificationMapper, 'map'); + }); + + afterEach(function () { + App.alertNotificationMapper.map.restore(); + }); + + it("should call mapper and set isLoaded to true", function () { + + controller.set('isLoaded', false); + controller.getAlertNotificationsSuccessCallback('test'); + expect(controller.get('isLoaded')).to.be.true; + expect(App.alertNotificationMapper.map.calledWith('test')).to.be.true; + }); + + }); + + describe('#getAlertNotificationsErrorCallback()', function () { + + it("should set isLoaded to true", function () { + + controller.set('isLoaded', false); + controller.getAlertNotificationsSuccessCallback('test'); + expect(controller.get('isLoaded')).to.be.true; + }); + + }); + + describe('#addAlertNotification()', function () { + + beforeEach(function () { + sinon.spy(controller, 'showCreateEditPopup'); + }); + + afterEach(function () { + controller.showCreateEditPopup.restore(); + }); + + it("should set value for inputFields and call showCreateEditPopup", function () { + + controller.set('inputFields', Em.Object.create({ + a: { + value: '', + defaultValue: 'a' + }, + b: { + value: '', + defaultValue: 'b' + }, + c: { + value: '', + defaultValue: 'c' + }, + severityFilter: { + value: [], + defaultValue: [true, true, true, true] + } + })); + controller.addAlertNotification(); + + Em.keys(controller.get('inputFields')).forEach(function (key) { + expect(controller.get('inputFields.' + key + '.value')).to.equal(controller.get('inputFields.' + key + '.defaultValue')); + }); + expect(controller.showCreateEditPopup.calledOnce).to.be.true; + }); + + }); + + describe('#editAlertNotification()', function () { + + beforeEach(function () { + sinon.stub(controller, 'showCreateEditPopup', Em.K); + sinon.stub(controller, 'fillEditCreateInputs', Em.K); + }); + + afterEach(function () { + controller.showCreateEditPopup.restore(); + controller.fillEditCreateInputs.restore(); + }); + + it("should call fillEditCreateInputs and showCreateEditPopup", function () { + + controller.editAlertNotification(); + + expect(controller.fillEditCreateInputs.calledOnce).to.be.true; + expect(controller.showCreateEditPopup.calledWith(true)).to.be.true; + }); + + }); + + describe('#fillEditCreateInputs()', function () { + + it("should map properties from selectedAlertNotification to inputFields", function () { + + controller.set('selectedAlertNotification', Em.Object.create({ + name: 'test_name', + description: 'test_description', + type: 'EMAIL', + alertStates: ['OK', 'UNKNOWN'], + properties: { + 'ambari.dispatch.recipients': [ + '[email protected]', + '[email protected]' + ] + } + })); + + controller.set('inputFields', Em.Object.create({ + name: { + value: '' + }, + groups: { + value: '' + }, + method: { + value: '' + }, + email: { + value: '' + }, + severityFilter: { + value: [] + }, + description: { + value: '' + } + })); + + controller.fillEditCreateInputs(); + + expect(JSON.stringify(controller.get('inputFields'))).to.equal(JSON.stringify({ + name: { + value: 'test_name' + }, + groups: { + value: '' + }, + method: { + value: 'EMAIL' + }, + email: { + value: '[email protected], [email protected]' + }, + severityFilter: { + value: [true, false, false, true] + }, + description: { + value: 'test_description' + } + })); + + }); + + }); + + describe("#showCreateEditPopup()", function () { + + before(function () { + sinon.stub(App.ModalPopup, 'show', function () { + return 'popup'; + }); + }); + + after(function () { + App.ModalPopup.show.restore(); + }); + + it("should open popup and set popup object to createEditPopup", function () { + + controller.set('createEditPopup', null); + + controller.showCreateEditPopup(); + + expect(App.ModalPopup.show.calledOnce).to.be.true; + expect(controller.get('createEditPopup')).to.equal('popup'); + }); + + }); + + describe("#formatNotificationAPIObject()", function () { + + it("should create object with properties from inputFields values", function () { + + controller.set('inputFields', Em.Object.create({ + name: { + value: 'test_name' + }, + groups: { + value: '' + }, + method: { + value: 'EMAIL' + }, + email: { + value: '[email protected], [email protected],[email protected] , [email protected]' + }, + severityFilter: { + value: [true, false, true, false] + }, + description: { + value: 'test_description' + } + })); + + var result = controller.formatNotificationAPIObject(); + + expect(result).to.eql({ + AlertTarget: { + name: 'test_name', + description: 'test_description', + notification_type: 'EMAIL', + alert_states: ['OK', 'CRITICAL'], + properties: { + 'ambari.dispatch.recipients': [ + '[email protected]', + '[email protected]', + '[email protected]', + '[email protected]' + ] + } + } + }); + }); + + }); + + describe('#createAlertNotification()', function () { + + it("should send ajax request", function () { + + controller.createAlertNotification(); + expect(App.ajax.send.calledOnce).to.be.true; + }); + + }); + + describe('#createAlertNotificationSuccessCallback()', function () { + + beforeEach(function () { + controller.set('createEditPopup', { + hide: Em.K + }); + sinon.stub(controller, 'loadAlertNotifications', Em.K); + sinon.spy(controller.createEditPopup, 'hide'); + }); + + afterEach(function () { + controller.loadAlertNotifications.restore(); + controller.createEditPopup.hide.restore(); + }); + + it("should call loadAlertNotifications and createEditPopup.hide", function () { + + controller.createAlertNotificationSuccessCallback(); + + expect(controller.loadAlertNotifications.calledOnce).to.be.true; + expect(controller.createEditPopup.hide.calledOnce).to.be.true; + }); + + }); + + describe('#updateAlertNotification()', function () { + + it("should send ajax request", function () { + + controller.createAlertNotification(); + expect(App.ajax.send.calledOnce).to.be.true; + }); + + }); + + describe('#updateAlertNotificationSuccessCallback()', function () { + + beforeEach(function () { + controller.set('createEditPopup', { + hide: Em.K + }); + sinon.stub(controller, 'loadAlertNotifications', Em.K); + sinon.spy(controller.createEditPopup, 'hide'); + }); + + afterEach(function () { + controller.loadAlertNotifications.restore(); + controller.createEditPopup.hide.restore(); + }); + + it("should call loadAlertNotifications and createEditPopup.hide", function () { + + controller.updateAlertNotificationSuccessCallback(); + + expect(controller.loadAlertNotifications.calledOnce).to.be.true; + expect(controller.createEditPopup.hide.calledOnce).to.be.true; + }); + + }); + + describe('#deleteAlertNotification()', function () { + + beforeEach(function () { + sinon.spy(App, 'showConfirmationPopup'); + }); + + afterEach(function () { + App.showConfirmationPopup.restore(); + }); + + it("should show popup and send request on confirmation", function () { + + var popup = controller.deleteAlertNotification(); + + expect(App.showConfirmationPopup.calledOnce).to.be.true; + popup.onPrimary(); + expect(App.ajax.send.calledOnce).to.be.true; + }); + + }); + + + describe('#deleteAlertNotificationSuccessCallback()', function () { + + it("should call loadAlertNotifications, selectedAlertNotification.deleteRecord and set null to selectedAlertNotification", function () { + + var mockSelectedAlertNotification = { + deleteRecord: Em.K + }; + controller.set('selectedAlertNotification', mockSelectedAlertNotification); + sinon.stub(controller, 'loadAlertNotifications', Em.K); + sinon.spy(mockSelectedAlertNotification, 'deleteRecord'); + + controller.deleteAlertNotificationSuccessCallback(); + + expect(controller.loadAlertNotifications.calledOnce).to.be.true; + expect(mockSelectedAlertNotification.deleteRecord.calledOnce).to.be.true; + expect(controller.get('selectedAlertNotification')).to.equal(null); + + controller.loadAlertNotifications.restore(); + mockSelectedAlertNotification.deleteRecord.restore(); + }); + + }); + + describe('#duplicateAlertNotification()', function () { + + beforeEach(function () { + sinon.stub(controller, 'fillEditCreateInputs', Em.K); + sinon.stub(controller, 'showCreateEditPopup', Em.K); + }); + + afterEach(function () { + controller.fillEditCreateInputs.restore(); + controller.showCreateEditPopup.restore(); + }); + + it("should call fillEditCreateInputs and showCreateEditPopup", function () { + + controller.duplicateAlertNotification(); + + expect(controller.fillEditCreateInputs.calledWith(true)).to.be.true; + expect(controller.showCreateEditPopup.calledOnce).to.be.true; + }); + + }); + +}); +
