/**
* 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 validator = require('utils/validator');
var numberUtils = require('utils/number_utils');
App.ManageAlertGroupsController = Em.Controller.extend({
name: 'manageAlertGroupsController',
/**
* @type {boolean}
*/
isLoaded: false,
/**
* Property used to trigger Alert Groups Filter content updating
* @type {Boolean}
*/
changeTrigger: false,
/**
* @type {App.AlertGroup[]}
*/
alertGroups: [],
/**
* @type {App.AlertGroup[]}
*/
originalAlertGroups: [],
/**
* @type {App.AlertGroup}
*/
selectedAlertGroup: null,
/**
* @type {App.AlertDefinition[]}
*/
selectedDefinitions: [],
/**
* List of all Alert Notifications
* @type {App.AlertNotification[]}
*/
alertNotifications: function () {
return this.get('isLoaded') ? App.AlertNotification.find().map(function (target) {
return Em.Object.create({
name: target.get('name'),
id: target.get('id'),
description: target.get('description'),
type: target.get('type'),
global: target.get('global')
});
}) : [];
}.property('isLoaded'),
/**
* List of all global Alert Notifications
* @type {App.AlertNotification[]}
*/
alertGlobalNotifications: function () {
return this.get('alertNotifications').filterProperty('global');
}.property('alertNotifications'),
/**
* @type {boolean}
*/
isRemoveButtonDisabled: true,
/**
* @type {boolean}
*/
isRenameButtonDisabled: true,
/**
* @type {boolean}
*/
isDuplicateButtonDisabled: true,
/**
* @type {boolean}
*/
isDeleteDefinitionsDisabled: function () {
var selectedGroup = this.get('selectedAlertGroup');
return selectedGroup ? (selectedGroup.default || this.get('selectedDefinitions').length === 0) : true;
}.property('selectedAlertGroup', 'selectedAlertGroup.definitions.length', 'selectedDefinitions.length'),
/**
* observes if any group changed including: group name, newly created group, deleted group, group with definitions/notifications changed
* @type {{toDelete: App.AlertGroup[], toSet: App.AlertGroup[], toCreate: App.AlertGroup[]}}
*/
defsModifiedAlertGroups: {},
/**
* Determines if some group was edited/created/deleted
* @type {boolean}
*/
isDefsModified: function () {
var modifiedGroups = this.get('defsModifiedAlertGroups');
if (!this.get('isLoaded')) {
return false;
}
return !!(modifiedGroups.toSet.length || modifiedGroups.toCreate.length || modifiedGroups.toDelete.length);
}.property('defsModifiedAlertGroups'),
/**
* Check when some config group was changed and updates defsModifiedAlertGroups
once
* @method defsModifiedAlertGroupsObs
*/
defsModifiedAlertGroupsObs: function() {
Em.run.once(this, this.defsModifiedAlertGroupsObsOnce);
}.observes('selectedAlertGroup.definitions.@each', 'selectedAlertGroup.definitions.length', 'selectedAlertGroup.notifications.@each', 'selectedAlertGroup.notifications.length', 'alertGroups', 'isLoaded'),
/**
* Update defsModifiedAlertGroups
-value
* Called once in the defsModifiedAlertGroupsObs
* @method defsModifiedAlertGroupsObsOnce
* @returns {boolean}
*/
defsModifiedAlertGroupsObsOnce: function() {
if (!this.get('isLoaded')) {
return false;
}
var groupsToDelete = [];
var groupsToSet = [];
var groupsToCreate = [];
var groups = this.get('alertGroups'); //current alert groups
var originalGroups = this.get('originalAlertGroups'); // original alert groups
var mappedOriginalGroups = {}; // map is faster than `originalGroups.findProperty('id', ...)`
originalGroups.forEach(function(group) {
mappedOriginalGroups[group.get('id')] = group;
});
var originalGroupsIds = originalGroups.mapProperty('id');
groups.forEach(function (group) {
var originalGroup = mappedOriginalGroups[group.get('id')];
if (originalGroup) {
// should update definitions or notifications
if (JSON.stringify(group.get('definitions').slice().sort()) !== JSON.stringify(originalGroup.get('definitions').slice().sort())
|| JSON.stringify(group.get('notifications').slice().sort()) !== JSON.stringify(originalGroup.get('notifications').slice().sort())) {
groupsToSet.push(group.set('id', originalGroup.get('id')));
}
else
if (group.get('name') !== originalGroup.get('name')) {
// should update name
groupsToSet.push(group.set('id', originalGroup.get('id')));
}
originalGroupsIds = originalGroupsIds.without(group.get('id'));
}
else {
// should add new group
groupsToCreate.push(group);
}
});
// should delete groups
originalGroupsIds.forEach(function (id) {
groupsToDelete.push(originalGroups.findProperty('id', id));
});
this.set('defsModifiedAlertGroups', {
toDelete: groupsToDelete,
toSet: groupsToSet,
toCreate: groupsToCreate
});
},
/**
* Load all Alert Notifications from server
* @returns {$.ajax}
* @method loadAlertNotifications
*/
loadAlertNotifications: function () {
this.setProperties({
isLoaded: false,
alertGroups: [],
originalAlertGroups: [],
selectedAlertGroup: null,
isRemoveButtonDisabled: true,
isRenameButtonDisabled: true,
isDuplicateButtonDisabled: true
});
return App.ajax.send({
name: 'alerts.notifications',
sender: this,
success: 'getAlertNotificationsSuccessCallback',
error: 'getAlertNotificationsErrorCallback'
});
},
/**
* Success-callback for load alert notifications request
* @param {object} json
* @method getAlertNotificationsSuccessCallback
*/
getAlertNotificationsSuccessCallback: function (json) {
App.alertNotificationMapper.map(json);
this.loadAlertGroups();
},
/**
* Error-callback for load alert notifications request
* @method getAlertNotificationsErrorCallback
*/
getAlertNotificationsErrorCallback: function () {
this.set('isLoaded', true);
},
/**
* Load all alert groups from alert group model
* @method loadAlertGroups
*/
loadAlertGroups: function () {
var alertGroups = App.AlertGroup.find().map(function (group) {
var definitions = group.get('definitions').map(function (def) {
return Em.Object.create({
name: def.get('name'),
serviceName: def.get('serviceName'),
componentName: def.get('componentName'),
serviceNameDisplay: def.get('service.displayName'),
componentNameDisplay: def.get('componentNameFormatted'),
label: def.get('label'),
id: def.get('id')
});
});
var targets = group.get('targets').map(function (target) {
return Em.Object.create({
name: target.get('name'),
id: target.get('id'),
description: target.get('description'),
type: target.get('type'),
global: target.get('global')
});
});
return Em.Object.create({
id: group.get('id'),
name: group.get('name'),
default: group.get('default'),
displayName: function () {
var name = this.get('name');
if (name && name.length > App.config.CONFIG_GROUP_NAME_MAX_LENGTH) {
var middle = Math.floor(App.config.CONFIG_GROUP_NAME_MAX_LENGTH / 2);
name = name.substring(0, middle) + "..." + name.substring(name.length - middle);
}
return this.get('default') ? (name + ' Default') : name;
}.property('name', 'default'),
label: function () {
return this.get('displayName') + ' (' + this.get('definitions.length') + ')';
}.property('displayName', 'definitions.length'),
definitions: definitions,
isAddDefinitionsDisabled: group.get('isAddDefinitionsDisabled'),
notifications: targets
});
});
this.setProperties({
alertGroups: alertGroups,
isLoaded: true,
originalAlertGroups: this.copyAlertGroups(alertGroups),
selectedAlertGroup: this.get('alertGroups')[0]
});
},
/**
* Enable/disable "Remove"/"Rename"/"Duplicate" buttons basing on controller.selectedAlertGroup
* @method buttonObserver
*/
buttonObserver: function () {
var selectedAlertGroup = this.get('selectedAlertGroup');
var flag = selectedAlertGroup && selectedAlertGroup.get('default');
this.setProperties({
isRemoveButtonDisabled: flag,
isRenameButtonDisabled: flag,
isDuplicateButtonDisabled: false
});
}.observes('selectedAlertGroup'),
/**
* @method resortAlertGroup
*/
resortAlertGroup: function () {
var alertGroups = Em.copy(this.get('alertGroups'));
if (alertGroups.length < 2) {
return;
}
var defaultGroups = alertGroups.filterProperty('default');
defaultGroups.forEach(function (defaultGroup) {
alertGroups.removeObject(defaultGroup);
});
var sorted = defaultGroups.sortProperty('name').concat(alertGroups.sortProperty('name'));
this.removeObserver('alertGroups.@each.name', this, 'resortAlertGroup');
this.set('alertGroups', sorted);
this.addObserver('alertGroups.@each.name', this, 'resortAlertGroup');
}.observes('alertGroups.@each.name'),
/**
* remove definitions from group
* @method deleteDefinitions
*/
deleteDefinitions: function () {
if (this.get('isDeleteDefinitionsDisabled')) {
return;
}
var groupDefinitions = this.get('selectedAlertGroup.definitions');
this.get('selectedDefinitions').slice().forEach(function (defObj) {
groupDefinitions.removeObject(defObj);
}, this);
this.set('selectedDefinitions', []);
},
/**
* Provides alert definitions which are available for inclusion in
* non-default alert groups.
* @param {App.AlertGroup} selectedAlertGroup
* @method getAvailableDefinitions
* @return {{name: string, serviceName: string, componentName: string, serviceNameDisplay: string, componentNameDisplay: string, label: string, id: number}[]}
*/
getAvailableDefinitions: function (selectedAlertGroup) {
if (selectedAlertGroup.get('default')) return [];
var usedDefinitionsMap = {};
var availableDefinitions = [];
var sharedDefinitions = App.AlertDefinition.find();
usedDefinitionsMap = selectedAlertGroup.get('definitions').toWickMapByProperty('name');
selectedAlertGroup.get('definitions').forEach(function (def) {
usedDefinitionsMap[def.name] = true;
});
sharedDefinitions.forEach(function (shared_def) {
if (!usedDefinitionsMap[shared_def.get('name')]) {
availableDefinitions.pushObject(shared_def);
}
});
return availableDefinitions.map(function (def) {
return Em.Object.create({
name: def.get('name'),
serviceName: def.get('serviceName'),
componentName: def.get('componentName'),
serviceNameDisplay: def.get('service.displayName'),
componentNameDisplay: def.get('componentNameFormatted'),
label: def.get('label'),
id: def.get('id')
});
});
},
/**
* add alert definitions to a group
* @method addDefinitions
*/
addDefinitions: function () {
if (this.get('selectedAlertGroup.isAddDefinitionsDisabled')) {
return false;
}
var availableDefinitions = this.getAvailableDefinitions(this.get('selectedAlertGroup'));
var popupDescription = {
header: Em.I18n.t('alerts.actions.manage_alert_groups_popup.selectDefsDialog.title'),
dialogMessage: Em.I18n.t('alerts.actions.manage_alert_groups_popup.selectDefsDialog.message').format(this.get('selectedAlertGroup.displayName'))
};
var validComponents = App.StackServiceComponent.find().map(function (component) {
return Em.Object.create({
componentName: component.get('componentName'),
displayName: App.format.role(component.get('componentName')),
selected: false
});
});
var validServices = App.Service.find().map(function (service) {
return Em.Object.create({
serviceName: service.get('serviceName'),
displayName: App.format.role(service.get('serviceName')),
selected: false
});
});
this.launchDefsSelectionDialog(availableDefinitions, [], validServices, validComponents, this.addDefinitionsCallback.bind(this), popupDescription);
},
/**
* Launch a table view of all available definitions to choose
* @method launchDefsSelectionDialog
* @return {App.ModalPopup}
*/
launchDefsSelectionDialog: function (initialDefs, selectedDefs, validServices, validComponents, callback, popupDescription) {
return App.ModalPopup.show({
classNames: [ 'sixty-percent-width-modal' ],
header: popupDescription.header,
/**
* @type {string}
*/
dialogMessage: popupDescription.dialogMessage,
/**
* @type {string|null}
*/
warningMessage: null,
/**
* @type {App.AlertDefinition[]}
*/
availableDefs: [],
onPrimary: function () {
this.set('warningMessage', null);
var arrayOfSelectedDefs = this.get('availableDefs').filterProperty('selected', true);
if (arrayOfSelectedDefs.length < 1) {
this.set('warningMessage', Em.I18n.t('alerts.actions.manage_alert_groups_popup.selectDefsDialog.message.warning'));
return;
}
callback(arrayOfSelectedDefs);
this.hide();
},
/**
* Primary button should be disabled while alert definitions are not loaded
* @type {boolean}
*/
disablePrimary: Em.computed.not('isLoaded'),
onSecondary: function () {
callback(null);
this.hide();
},
bodyClass: App.SelectDefinitionsPopupBodyView.extend({
filterComponents: validComponents,
filterServices: validServices,
initialDefs: initialDefs
})
});
},
/**
* add alert definitions callback
* @method addDefinitionsCallback
*/
addDefinitionsCallback: function (selectedDefs) {
var group = this.get('selectedAlertGroup');
if (selectedDefs) {
group.get('definitions').pushObjects(selectedDefs);
}
},
/**
* copy alert groups for backup, to compare with current alert groups, so will know if some groups changed/added/deleted
* @param {App.AlertGroup[]} originGroups
* @return {App.AlertGroup[]}
* @method copyAlertGroups
*/
copyAlertGroups: function (originGroups) {
var alertGroups = [];
originGroups.forEach(function (alertGroup) {
var copiedGroup = Em.Object.create($.extend(true, {}, alertGroup));
alertGroups.pushObject(copiedGroup);
});
return alertGroups;
},
/**
* Create a new alert group
* @param {Em.Object} newAlertGroupData
* @param {callback} callback Callback function for Success or Error handling
* @return {App.AlertGroup} Returns the created alert group
* @method postNewAlertGroup
*/
postNewAlertGroup: function (newAlertGroupData, callback) {
// create a new group with name , definition and notifications
var data = {
'name': newAlertGroupData.get('name')
};
if (newAlertGroupData.get('definitions').length > 0) {
data.definitions = newAlertGroupData.get('definitions').mapProperty('id');
}
if (newAlertGroupData.get('notifications').length > 0) {
data.targets = newAlertGroupData.get('notifications').mapProperty('id');
}
var sendData = {
name: 'alert_groups.create',
data: data,
success: 'successFunction',
error: 'errorFunction',
successFunction: function () {
if (callback) {
callback();
}
},
errorFunction: function (xhr, text, errorThrown) {
if (callback) {
callback(xhr, text, errorThrown);
}
}
};
sendData.sender = sendData;
App.ajax.send(sendData);
return newAlertGroupData;
},
/**
* PUTs the new alert group information on the server.
* Changes possible here are the name, definitions, notifications
*
* @param {App.AlertGroup} alertGroup
* @param {Function} successCallback
* @param {Function} errorCallback
* @method updateAlertGroup
*/
updateAlertGroup: function (alertGroup, successCallback, errorCallback) {
var sendData = {
name: 'alert_groups.update',
data: {
"group_id": alertGroup.id,
'name': alertGroup.get('name'),
'definitions': alertGroup.get('definitions').mapProperty('id'),
'targets': alertGroup.get('notifications').mapProperty('id')
},
success: 'successFunction',
error: 'errorFunction',
successFunction: function () {
if (successCallback) {
successCallback();
}
},
errorFunction: function (xhr, text, errorThrown) {
if (errorCallback) {
errorCallback(xhr, text, errorThrown);
}
}
};
sendData.sender = sendData;
App.ajax.send(sendData);
},
/**
* Request for deleting alert group
* @param {App.AlertGroup} alertGroup
* @param {callback} successCallback
* @param {callback} errorCallback
* @method removeAlertGroup
*/
removeAlertGroup: function (alertGroup, successCallback, errorCallback) {
var sendData = {
name: 'alert_groups.delete',
data: {
"group_id": alertGroup.id
},
success: 'successFunction',
error: 'errorFunction',
successFunction: function () {
if (successCallback) {
successCallback();
}
},
errorFunction: function (xhr, text, errorThrown) {
if (errorCallback) {
errorCallback(xhr, text, errorThrown);
}
}
};
sendData.sender = sendData;
App.ajax.send(sendData);
},
/**
* confirm delete alert group
* @method confirmDelete
*/
confirmDelete: function () {
if (this.get('isRemoveButtonDisabled')) return;
var self = this;
App.showConfirmationPopup(function () {
self.deleteAlertGroup();
});
},
/**
* delete selected alert group
* @method deleteAlertGroup
*/
deleteAlertGroup: function () {
var selectedAlertGroup = this.get('selectedAlertGroup');
if (this.get('isDeleteAlertDisabled')) {
return;
}
this.get('alertGroups').removeObject(selectedAlertGroup);
this.set('selectedAlertGroup', this.get('alertGroups')[0]);
},
/**
* Rename non-default alert group
* @method renameAlertGroup
*/
renameAlertGroup: function () {
if (this.get('selectedAlertGroup.default')) {
return;
}
var self = this;
var popup;
popup = App.ModalPopup.show({
header: Em.I18n.t('alerts.actions.manage_alert_groups_popup.renameButton'),
bodyClass: Ember.View.extend({
templateName: require('templates/main/alerts/create_new_alert_group')
}),
/**
* @type {string}
*/
alertGroupName: self.get('selectedAlertGroup.name'),
/**
* @type {string|null}
*/
warningMessage: null,
/**
* New group name should be unique and valid
* @method validate
*/
validate: function () {
var warningMessage = '';
var originalGroup = self.get('selectedAlertGroup');
var groupName = this.get('alertGroupName').trim();
if (originalGroup.get('name').trim() === groupName) {
warningMessage = Em.I18n.t("alerts.actions.manage_alert_groups_popup.addGroup.exist");
}
else {
if (self.get('alertGroups').mapProperty('displayName').contains(groupName)) {
warningMessage = Em.I18n.t("alerts.actions.manage_alert_groups_popup.addGroup.exist");
}
else {
if (groupName && !validator.isValidAlertGroupName(groupName)) {
warningMessage = Em.I18n.t("form.validator.alertGroupName");
}
}
}
this.set('warningMessage', warningMessage);
}.observes('alertGroupName'),
/**
* Primary button is disabled while user doesn't input valid group name
* @type {boolean}
*/
disablePrimary: function () {
return !(this.get('alertGroupName').trim().length > 0 && (this.get('warningMessage') !== null && !this.get('warningMessage')));
}.property('warningMessage', 'alertGroupName'),
onPrimary: function () {
self.set('selectedAlertGroup.name', this.get('alertGroupName'));
this.hide();
}
});
this.set('renameGroupPopup', popup);
},
/**
* Create new alert group
* @param {boolean} duplicated is new group a copy of the existing group
* @method addAlertGroup
*/
addAlertGroup: function (duplicated) {
duplicated = (duplicated === true);
var self = this;
var popup = App.ModalPopup.show({
header: Em.I18n.t('alerts.actions.manage_alert_groups_popup.addButton'),
bodyClass: Em.View.extend({
templateName: require('templates/main/alerts/create_new_alert_group')
}),
/**
* Name for new alert group
* @type {string}
*/
alertGroupName: duplicated ? self.get('selectedAlertGroup.name') + ' Copy' : "",
/**
* @type {string}
*/
warningMessage: '',
didInsertElement: function () {
this._super();
this.validate();
},
/**
* alert group name should be unique and valid
* @method validate
*/
validate: function () {
var warningMessage = '';
var groupName = this.get('alertGroupName').trim();
if (self.get('alertGroups').mapProperty('displayName').contains(groupName)) {
warningMessage = Em.I18n.t("alerts.actions.manage_alert_groups_popup.addGroup.exist");
}
else {
if (groupName && !validator.isValidAlertGroupName(groupName)) {
warningMessage = Em.I18n.t("form.validator.alertGroupName");
}
}
this.set('warningMessage', warningMessage);
}.observes('alertGroupName'),
/**
* Primary button is disabled while user doesn't input valid group name
* @type {boolean}
*/
disablePrimary: function () {
return !(this.get('alertGroupName').trim().length > 0 && !this.get('warningMessage'));
}.property('warningMessage', 'alertGroupName'),
onPrimary: function () {
var newAlertGroup = Em.Object.create({
name: this.get('alertGroupName').trim(),
default: false,
displayName: function () {
var name = this.get('name');
if (name && name.length > App.config.CONFIG_GROUP_NAME_MAX_LENGTH) {
var middle = Math.floor(App.config.CONFIG_GROUP_NAME_MAX_LENGTH / 2);
name = name.substring(0, middle) + "..." + name.substring(name.length - middle);
}
return this.get('default') ? (name + ' Default') : name;
}.property('name', 'default'),
label: function () {
return this.get('displayName') + ' (' + this.get('definitions.length') + ')';
}.property('displayName', 'definitions.length'),
definitions: duplicated ? self.get('selectedAlertGroup.definitions').slice(0) : [],
notifications: self.get('alertGlobalNotifications'),
isAddDefinitionsDisabled: false
});
self.get('alertGroups').pushObject(newAlertGroup);
self.set('selectedAlertGroup', newAlertGroup);
this.hide();
}
});
this.set('addGroupPopup', popup);
},
/**
* @method duplicateAlertGroup
*/
duplicateAlertGroup: function () {
this.addAlertGroup(true);
}
});