Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom Button CRUD for Generic Object Definitions #2569

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
e790c5c
Add support for Custom Button node
AparnaKarve Oct 27, 2017
80a8b03
Set up Toolbars for Custom Buttons
AparnaKarve Oct 27, 2017
e991145
Add Custom Button Add and Edit Actions and Routes
AparnaKarve Oct 27, 2017
fe5ad42
Created partials and methods for Custom Button Add/Edit
AparnaKarve Oct 27, 2017
f830fb7
Add support for no regex for the Name column for the table component
AparnaKarve Oct 27, 2017
c2216b8
Add the Main Custom Button form and component
AparnaKarve Oct 27, 2017
2b0c2a6
Add a route and GET action `retrieve_distinct_instances_across_domains`
AparnaKarve Oct 27, 2017
fce183c
Retrieve the domain instances over $http.get
AparnaKarve Oct 27, 2017
498b8aa
Retrieve GOD id from existing Custom Button Record for Edit
AparnaKarve Oct 27, 2017
6ef85e2
Set Roles to ALL if Roles array length = 0
AparnaKarve Oct 28, 2017
43102e0
Fix for dirty-checking in the attribute/value table
AparnaKarve Oct 28, 2017
b5ecae9
Dirty checking fix for Available roles array
AparnaKarve Oct 28, 2017
adebb31
Add Delete support for Custom Buttons
AparnaKarve Oct 28, 2017
324864c
More Toolbar adjustments for Custom Buttons
AparnaKarve Oct 30, 2017
adb9324
Add support for Delete and other recordId adjustments
AparnaKarve Oct 30, 2017
51ef387
Add Custom Button partial and node methods
AparnaKarve Oct 30, 2017
7059eac
Make Custom Button specific changes post rebase #2524
AparnaKarve Oct 30, 2017
cff9d53
Add support for Custom Button under Button Group
AparnaKarve Oct 30, 2017
140998b
Miscellaneous fine-tuning
AparnaKarve Oct 30, 2017
ff6b92d
Address Rubocop and CC
AparnaKarve Oct 31, 2017
2fa2e50
Adjustments for Custom Button related code - post #2635 merge
AparnaKarve Nov 6, 2017
7ce4688
PR feedback - Use full word `definition` as opposed to `defn`
AparnaKarve Nov 6, 2017
69bed9c
Revert of c01d1184c331a5a97769ac8927a457276681ffac
AparnaKarve Nov 8, 2017
22a4a01
Removed `GenericListMixin` and some related adjustments
AparnaKarve Nov 8, 2017
a43115c
Toolbar cleanup
AparnaKarve Nov 8, 2017
cf64828
Address feedback on Toolbar cleanup
AparnaKarve Nov 9, 2017
1488f68
Remove `rescue StandardError => _err`
AparnaKarve Nov 9, 2017
a0144e3
Show/Hide the searchbox appropriately based on the node selection
AparnaKarve Nov 9, 2017
ed47c6f
The default `roles` value (_ALL_) is already set
AparnaKarve Nov 13, 2017
2045cce
Convert the `id` for `applies_to_id` to Integer prior to saving
AparnaKarve Nov 13, 2017
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
ManageIQ.angular.app.component('genericObjectDefinitionToolbar', {
bindings: {
recordId: '=?',
entity: '@',
entityName: '@?',
redirectUrl: '@?',
},
Expand All @@ -20,10 +19,13 @@ function genericObjectDefinitionToolbarController(API, miqService, $window) {

ManageIQ.angular.genericObjectDefinitionSubsription = ManageIQ.angular.rxSubject.subscribe(function(event) {
toolbar.action = event.type;
toolbar.entity = event.entity;

if (toolbar.action) {
if (toolbar.recordId) {
toolbar.genericObjectDefinitions = _.union(toolbar.genericObjectDefinitions, [toolbar.recordId]);
} else if (ManageIQ.record.recordId) {
toolbar.genericObjectDefinitions = _.union(toolbar.genericObjectDefinitions, [ManageIQ.record.recordId]);
} else {
toolbar.genericObjectDefinitions = ManageIQ.gridChecks;
}
Expand All @@ -33,16 +35,19 @@ function genericObjectDefinitionToolbarController(API, miqService, $window) {

// private functions
function postGenericObjectDefinitionAction() {
if (toolbar.action === 'delete' && ! toolbar.recordId) {
var currentRecordId = toolbar.recordId || ManageIQ.record.recordId;
if (toolbar.action === 'delete' && ! currentRecordId) {
_.forEach(toolbar.genericObjectDefinitions, function(recordId) {
API.get('/api/generic_object_definitions/' + recordId + '?attributes=generic_objects_count')
.then(checkGenericObjectCountAndDelete)
.catch(miqService.handleFailure);
});
} else if (toolbar.action === 'delete' && toolbar.recordId) {
deleteWithAPI('/api/generic_object_definitions/', toolbar.recordId);
} else if (toolbar.action === 'delete_custom_button_set' && toolbar.recordId) {
deleteWithAPI('/api/custom_button_sets/', toolbar.recordId);
} else if (toolbar.action === 'delete' && currentRecordId) {
deleteWithAPI('/api/generic_object_definitions/', currentRecordId);
} else if (toolbar.action === 'delete_custom_button_set' && currentRecordId) {
deleteWithAPI('/api/custom_button_sets/', currentRecordId);
} else if (toolbar.action === 'delete_custom_button' && currentRecordId) {
deleteWithAPI('/api/custom_buttons/', currentRecordId);
}
}

Expand All @@ -64,7 +69,13 @@ function genericObjectDefinitionToolbarController(API, miqService, $window) {
}

function postAction(response) {
var saveMsg = sprintf(__('%s:"%s" was successfully deleted'), toolbar.entity, toolbar.entityName || response.name);
var entityName = toolbar.entityName || response.name;
var saveMsg;
if (entityName) {
saveMsg = sprintf(__('%s:"%s" was successfully deleted'), toolbar.entity, entityName);
} else {
saveMsg = sprintf(__('%s was successfully deleted'), toolbar.entity);
}
if (toolbar.redirectUrl) {
miqService.redirectBack(saveMsg, 'success', toolbar.redirectUrl);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ ManageIQ.angular.app.component('genericObjectTableComponent', {
requiredRule: '@?',
tableRendered: '=',
uniqueProperty: '&',
noPattern: '<',
addValueColumn: '<',
angularForm: '<',
},
controllerAs: 'vm',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,304 @@
ManageIQ.angular.app.component('mainCustomButtonFormComponent', {
bindings: {
genericObjectDefinitionRecordId: '@?',
customButtonGroupRecordId: '@?',
customButtonRecordId: '@?',
redirectUrl: '@',
},
controllerAs: 'vm',
controller: mainCustomButtonFormController,
templateUrl: '/static/generic_object/main_custom_button_form.html.haml',
});

mainCustomButtonFormController.$inject = ['API', 'miqService', '$q', '$http'];

function mainCustomButtonFormController(API, miqService, $q, $http) {
var vm = this;

var optionsPromise = null;
var serviceDialogsPromise = null;
var rolesPromise = null;
var instancesPromise = null;

vm.$onInit = function() {
vm.entity = __('Custom Button');
vm.saveable = miqService.saveable;
vm.afterGet = false;

vm.customButtonModel = {
button_type: 'default',
name: '',
description: '',
display: true,
button_icon: '',
button_color: '#4d5258',
options: {},
resource_action: {},
visibility: {},
dialog_id: undefined,
open_url: false,
display_for: 'single',
submit_how: 'one',
ae_instance: 'Request',
ae_message: 'create',
request: '',
roles: ['_ALL_'],
attribute_names: [],
attribute_values: [],
attributeValuesTableChanged: false,
current_visibility: 'all',
available_roles: [],
};

vm.dialogs = [];
vm.button_types = [];
vm.ae_instances = [];

vm.attributeValueTableHeaders = [__("Name"), __("Value")];

vm.display_for = [
{id: 'single', name: __('Single Entity')},
{id: 'list', name: __('List')},
{id: 'both', name: __('Single and List')},
];

vm.submit_how = [
{id: 'all', name: __('Submit all')},
{id: 'one', name: __('One by one')},
];

vm.visibilities = [
{id: 'all', name: __('<To All>')},
{id: 'role', name: __('<By Role>')},
];

miqService.sparkleOn();
optionsPromise = API.options('/api/custom_buttons')
.then(getCustomButtonOptions)
.catch(miqService.handleFailure);

serviceDialogsPromise = API.get('/api/service_dialogs?expand=resources&attributes=label')
.then(getServiceDialogs)
.catch(miqService.handleFailure);

rolesPromise = API.get('/api/roles?expand=resources&attributes=name')
.then(getRoles)
.catch(miqService.handleFailure);

instancesPromise = $http.get('/generic_object_definition/retrieve_distinct_instances_across_domains')
.then(getDistinctInstancesAcrossDomains)
.catch(miqService.handleFailure);

if (vm.customButtonRecordId) {
vm.newRecord = false;
miqService.sparkleOn();
var dataPromise = API.get('/api/custom_buttons/' + vm.customButtonRecordId + '?attributes=resource_action')
.then(getCustomButtonFormData)
.catch(miqService.handleFailure);
} else {
vm.newRecord = true;
vm.modelCopy = angular.copy( vm.customButtonModel );
}

$q.all([optionsPromise, serviceDialogsPromise, rolesPromise, instancesPromise, dataPromise])
.then(promisesResolvedForLoad);
};

vm.cancelClicked = function() {
miqService.sparkleOn();
if (vm.newRecord) {
miqService.redirectBack(sprintf(__('Creation of new %s was canceled by the user.'), vm.entity), 'warning', vm.redirectUrl);
} else {
miqService.redirectBack(sprintf(__('Edit of %s \"%s\" was canceled by the user.'), vm.entity, vm.customButtonModel.name), 'warning', vm.redirectUrl);
}
};

vm.resetClicked = function(angularForm) {
vm.customButtonModel = angular.element.extend(true, {}, vm.modelCopy);

assignAllObjectsToKeyValueArrays(true);

angularForm.$setUntouched(true);
angularForm.$setPristine(true);

miqService.miqFlash('warn', __('All changes have been reset'));
};

vm.saveClicked = function() {
var saveMsg = sprintf(__('%s \"%s\" has been successfully saved.'), vm.entity, vm.customButtonModel.name);
vm.saveWithAPI('put', '/api/custom_buttons/' + vm.customButtonRecordId, vm.prepSaveObject(), saveMsg);
};

vm.addClicked = function() {
var saveMsg = sprintf(__('%s \"%s\" has been successfully added.'), vm.entity, vm.customButtonModel.name);
vm.saveWithAPI('post', '/api/custom_buttons/', vm.prepSaveObject(), saveMsg);
};

vm.prepSaveObject = function() {
vm.customButtonModel.options = {};
vm.customButtonModel.resource_action = {};
vm.customButtonModel.visibility = {};

vm.customButtonModel.options = {
button_icon: vm.customButtonModel.button_icon,
button_color: vm.customButtonModel.button_color,
button_type: vm.customButtonModel.button_type,
display: vm.customButtonModel.display,
open_url: vm.customButtonModel.open_url,
display_for: vm.customButtonModel.display_for,
submit_how: vm.customButtonModel.submit_how,
};

vm.customButtonModel.resource_action.ae_attributes = _.zipObject(
vm.customButtonModel.attribute_names,
vm.customButtonModel.attribute_values);
vm.customButtonModel.resource_action.ae_attributes.request = vm.customButtonModel.request;

vm.customButtonModel.resource_action = {
dialog_id: vm.customButtonModel.dialog_id,
ae_namespace: 'SYSTEM',
ae_class: 'PROCESS',
ae_instance: vm.customButtonModel.ae_instance,
ae_message: vm.customButtonModel.ae_message,
ae_attributes: vm.customButtonModel.resource_action.ae_attributes,
};

if (vm.customButtonModel.current_visibility === 'role') {
vm.customButtonModel.roles = _.pluck(_.filter(vm.customButtonModel.available_roles, function(role) {
return role.value === true;
}), 'name');
}

vm.customButtonModel.visibility = {
roles: vm.customButtonModel.roles.length === 0 ? ['_ALL_'] : vm.customButtonModel.roles,
};

return {
name: vm.customButtonModel.name,
description: vm.customButtonModel.description,
applies_to_class: 'GenericObjectDefinition',
applies_to_id: vm.genericObjectDefinitionRecordId,
options: vm.customButtonModel.options,
resource_action: vm.customButtonModel.resource_action,
visibility: vm.customButtonModel.visibility,
};
};

vm.saveWithAPI = function(method, url, saveObject, saveMsg) {
miqService.sparkleOn();

if (vm.customButtonGroupRecordId) {
var saveCustomButtonPromise = API[method](url, saveObject);
var saveMsgBtnInGrp = sprintf(__('%s \"%s\" has been successfully added under the selected button group.'), vm.entity, vm.customButtonModel.name);

saveCustomButtonPromise.then(function(response) {
$http.post('/generic_object_definition/add_button_in_group/' + vm.customButtonGroupRecordId + '?button_id=' + response.results[0].id)
.then(miqService.redirectBack.bind(vm, saveMsgBtnInGrp, 'success', vm.redirectUrl))
.catch(miqService.handleFailure);
});
} else {
API[method](url, saveObject)
.then(miqService.redirectBack.bind(vm, saveMsg, 'success', vm.redirectUrl))
.catch(miqService.handleFailure);
}
};

// private functions
function getCustomButtonFormData(response) {
Object.assign(vm.customButtonModel, response);

vm.customButtonModel.button_icon = response.options.button_icon;
vm.customButtonModel.button_color = response.options.button_color;
vm.customButtonModel.button_type = response.options.button_type;
vm.customButtonModel.display = response.options.display;
vm.customButtonModel.open_url = response.options.open_url;
vm.customButtonModel.display_for = response.options.display_for;
vm.customButtonModel.submit_how = response.options.submit_how;

vm.customButtonModel.dialog_id = response.resource_action.dialog_id;
vm.customButtonModel.ae_instance = response.resource_action.ae_instance;
vm.customButtonModel.ae_message = response.resource_action.ae_message;
vm.customButtonModel.request = response.resource_action.ae_attributes.request;

vm.customButtonModel.current_visibility = response.visibility.roles[0] === '_ALL_' || response.visibility.roles.length === 0 ? 'all' : 'role';

vm.genericObjectDefinitionRecordId = response.applies_to_id;

optionsPromise.then(function() {
if (vm.customButtonModel.current_visibility === 'role') {
_.forEach(vm.customButtonModel.available_roles, function(role, index) {
if (_.includes(response.visibility.roles, role.name)) {
vm.customButtonModel.available_roles[index].value = true;
}
});
}

delete vm.customButtonModel.resource_action.ae_attributes.request;
vm.customButtonModel.noOfAttributeValueRows = assignObjectToKeyValueArrays(
vm.customButtonModel.resource_action.ae_attributes,
vm.customButtonModel.attribute_names,
vm.customButtonModel.attribute_values);

vm.modelCopy = angular.element.extend(true, {}, vm.customButtonModel);
});
}

function assignAllObjectsToKeyValueArrays(purge) {
if (purge) {
vm.customButtonModel.attribute_names = [];
vm.customButtonModel.attribute_values = [];
}

vm.customButtonModel.noOfAttributeValueRows = assignObjectToKeyValueArrays(
vm.customButtonModel.resource_action.ae_attributes,
vm.customButtonModel.attribute_names,
vm.customButtonModel.attribute_values);

vm.modelCopy = angular.element.extend(true, {}, vm.customButtonModel);
}

function assignObjectToKeyValueArrays(obj, keyArray, valueArray) {
if (_.size(obj) === 0) {
keyArray.push('');
} else {
_.forEach(obj, function(value, key) {
if (valueArray) {
keyArray.push(key);
valueArray.push(value);
} else {
keyArray.push(value);
}
});
}
return _.size(keyArray);
}

function getCustomButtonOptions(response) {
_.forEach(response.data.custom_button_types, function(name, id) {
vm.button_types.push({id: id, name: name});
});
}

function getServiceDialogs(response) {
_.forEach(response.resources, function(item) {
vm.dialogs.push({id: item.id, label: item.label});
});
}

function getRoles(response) {
_.forEach(response.resources, function(item) {
vm.customButtonModel.available_roles.push({name: item.name, value: false});
});
}

function getDistinctInstancesAcrossDomains(response) {
_.forEach(response.data.distinct_instances_across_domains, function(item) {
vm.ae_instances.push({id: item, name: item});
});
}

function promisesResolvedForLoad() {
vm.afterGet = true;
miqService.sparkleOff();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ function mainCustomButtonGroupFormController(API, miqService) {
button_color: vm.customButtonGroupModel.button_color,
display: vm.customButtonGroupModel.display,
applies_to_class: 'GenericObjectDefinition',
applies_to_id: vm.genericObjectDefnRecordId,
applies_to_id: parseInt(vm.genericObjectDefnRecordId, 10),
};

return {
Expand Down
Loading