diff --git a/app/assets/javascripts/components/generic_object/assign-buttons.js b/app/assets/javascripts/components/generic_object/assign-buttons.js new file mode 100644 index 000000000000..687e82ffba57 --- /dev/null +++ b/app/assets/javascripts/components/generic_object/assign-buttons.js @@ -0,0 +1,153 @@ +ManageIQ.angular.app.component('assignButtons', { + bindings: { + assignedButtons: '<', + unassignedButtons: '<', + updateButtons: '<' + }, + require: { + parent: '^^mainCustomButtonGroupForm' + }, + controllerAs: 'vm', + controller: assignButtonsController, + templateUrl: '/static/generic_object/assign-buttons.html.haml', +}); + +function assignButtonsController() { + var vm = this; + + vm.model = { + selectedAssignedButtons: [], + selectedUnassignedButtons: [], + }; + + function getIndexes(arr, ids) { + var indexes= []; + ids.forEach(function (id) { + var i = arr.findIndex(function(el){ + return el.id == id; + }); + if (i >= 0){ + indexes.push(i); + } + }); + return indexes; + }; + + vm.$onInit = function() { + vm.model.assignedButtons = [].concat(vm.assignedButtons); + vm.model.unassignedButtons = [].concat(vm.unassignedButtons); + }; + + function filterIndexes(indexes) { + if (indexes[0] !== 0) { + return indexes; + } + var previous = 0; + var filteredIndexes = []; + indexes.forEach(function(index) { + if (index !== 0 && index - 1 !== previous) { + filteredIndexes.push(index); + } else { + previous = index; + } + }); + return filteredIndexes; + }; + + function filterReverseIndexes(indexes, endIndex) { + if (indexes[0] !== endIndex) { + return indexes; + } + var previous = endIndex; + var filteredIndexes = []; + indexes.forEach(function(index) { + if (index !== endIndex && index + 1 !== previous) { + filteredIndexes.push(index); + } else { + previous = index; + } + }); + return filteredIndexes; + }; + + function copyData() { + vm.model.assignedButtons = [].concat(vm.assignedButtons); + vm.model.unassignedButtons = [].concat(vm.unassignedButtons); + }; + + vm.leftButtonClicked = function() { + copyData(); + var indexes = getIndexes(vm.model.assignedButtons, vm.model.selectedAssignedButtons); + var movedElements = []; + indexes.forEach(function(index) { + movedElements.push(vm.model.assignedButtons[index]); + }); + _.remove(vm.model.assignedButtons, function(n) { return movedElements.includes(n) }); + vm.model.unassignedButtons = vm.model.unassignedButtons.concat( movedElements); + vm.updateButtons(vm.model.assignedButtons, vm.model.unassignedButtons); + }; + + vm.rightButtonClicked = function() { + copyData(); + var indexes = getIndexes(vm.model.unassignedButtons, vm.model.selectedUnassignedButtons); + var movedElements = []; + indexes.forEach(function(index) { + movedElements.push(vm.model.unassignedButtons[index]); + }); + _.remove(vm.model.unassignedButtons, function(n) { return movedElements.includes(n) }); + vm.model.assignedButtons = vm.model.assignedButtons.concat( movedElements); + vm.updateButtons(vm.model.assignedButtons, vm.model.unassignedButtons); + }; + + vm.upButtonClicked = function() { + copyData(); + var indexes = getIndexes(vm.model.assignedButtons, vm.model.selectedAssignedButtons); + indexes = filterIndexes(indexes); + indexes.forEach(function(index) { + if (index > 0) { + var temp = vm.model.assignedButtons[index]; + vm.model.assignedButtons[index] = vm.model.assignedButtons[index - 1]; + vm.model.assignedButtons[index - 1] = temp; + } + }); + vm.updateButtons(vm.model.assignedButtons, vm.model.unassignedButtons); + }; + + vm.downButtonClicked = function() { + copyData(); + var indexes = getIndexes(vm.model.assignedButtons, vm.model.selectedAssignedButtons).reverse(); + indexes = filterReverseIndexes(indexes, vm.model.assignedButtons.length - 1); + indexes.forEach(function(index) { + if (index < vm.model.assignedButtons.length - 1) { + var temp = vm.model.assignedButtons[index]; + vm.model.assignedButtons[index] = vm.model.assignedButtons[index + 1]; + vm.model.assignedButtons[index + 1] = temp; + } + }); + vm.updateButtons(vm.model.assignedButtons, vm.model.unassignedButtons); + }; + + vm.topButtonClicked = function() { + copyData(); + var indexes = getIndexes(vm.model.assignedButtons, vm.model.selectedAssignedButtons); + var movedElements = []; + indexes.forEach(function(index) { + movedElements.push(vm.model.assignedButtons[index]); + }); + _.remove(vm.model.assignedButtons, function(n) { return movedElements.includes(n) }); + vm.model.assignedButtons = movedElements.concat( vm.model.assignedButtons); + vm.updateButtons(vm.model.assignedButtons, vm.model.unassignedButtons); + }; + + vm.bottomButtonClicked = function() { + copyData(); + var indexes = getIndexes(vm.model.assignedButtons, vm.model.selectedAssignedButtons); + var movedElements = []; + indexes.forEach(function(index) { + movedElements.push(vm.model.assignedButtons[index]); + }); + _.remove(vm.model.assignedButtons, function(n) { return movedElements.includes(n) }); + vm.model.assignedButtons = vm.model.assignedButtons.concat(movedElements); + vm.updateButtons(vm.model.assignedButtons, vm.model.unassignedButtons); + }; +} diff --git a/app/assets/javascripts/components/generic_object/main-custom-button-group-form.js b/app/assets/javascripts/components/generic_object/main-custom-button-group-form.js index 9cc6e013c286..2deffa805dbc 100644 --- a/app/assets/javascripts/components/generic_object/main-custom-button-group-form.js +++ b/app/assets/javascripts/components/generic_object/main-custom-button-group-form.js @@ -9,9 +9,9 @@ ManageIQ.angular.app.component('mainCustomButtonGroupForm', { templateUrl: '/static/generic_object/main_custom_button_group_form.html.haml', }); -mainCustomButtonGroupFormController.$inject = ['API', 'miqService']; +mainCustomButtonGroupFormController.$inject = ['API', 'miqService', '$http']; -function mainCustomButtonGroupFormController(API, miqService) { +function mainCustomButtonGroupFormController(API, miqService, $http) { var vm = this; vm.$onInit = function() { @@ -26,21 +26,33 @@ function mainCustomButtonGroupFormController(API, miqService) { button_icon: '', button_color: '#4d5258', set_data: {}, + assigned_buttons: [], + unassigned_buttons: [], }; - if (vm.customButtonGroupRecordId) { - vm.newRecord = false; - miqService.sparkleOn(); - API.get('/api/custom_button_sets/' + vm.customButtonGroupRecordId) - .then(getCustomButtonGroupFormData) - .catch(miqService.handleFailure); - } else { - vm.newRecord = true; + $http.get('/generic_object_definition/custom_buttons_in_set/?custom_button_set_id=' + vm.customButtonGroupRecordId + '&generic_object_definition_id=' + vm.genericObjectDefnRecordId) + .then(function(response) { + Object.assign(vm.customButtonGroupModel, response.data); + if (vm.customButtonGroupRecordId) { + vm.newRecord = false; + miqService.sparkleOn(); + API.get('/api/custom_button_sets/' + vm.customButtonGroupRecordId) + .then(getCustomButtonGroupFormData) + .catch(miqService.handleFailure); + } else { + vm.newRecord = true; + + API.get('/api/custom_button_sets?expand=resources&attributes=set_data') + .then(getCustomButtonSetGroupIndex) + .catch(miqService.handleFailure); + } + }) + .catch(miqService.handleFailure); + }; - API.get('/api/custom_button_sets?expand=resources&attributes=set_data') - .then(getCustomButtonSetGroupIndex) - .catch(miqService.handleFailure); - } + vm.updateButtons = function(assignedButtons, unassignedButtons) { + vm.customButtonGroupModel.assigned_buttons = assignedButtons; + vm.customButtonGroupModel.unassigned_buttons = unassignedButtons; }; vm.cancelClicked = function() { @@ -71,11 +83,19 @@ function mainCustomButtonGroupFormController(API, miqService) { vm.saveWithAPI('post', '/api/custom_button_sets/', vm.prepSaveObject(), saveMsg); }; + vm.buttonOrder = function() { + var orderedButtons = []; + vm.customButtonGroupModel.assigned_buttons.forEach(function(button) { + orderedButtons.push(button.id); + }); + return orderedButtons; + }; + vm.prepSaveObject = function() { vm.customButtonGroupModel.set_data = { button_icon: vm.customButtonGroupModel.button_icon, button_color: vm.customButtonGroupModel.button_color, - button_order: vm.customButtonGroupModel.button_order, + button_order: vm.buttonOrder(), display: vm.customButtonGroupModel.display, applies_to_class: 'GenericObjectDefinition', applies_to_id: parseInt(vm.genericObjectDefnRecordId, 10), @@ -94,7 +114,14 @@ function mainCustomButtonGroupFormController(API, miqService) { vm.saveWithAPI = function(method, url, saveObject, saveMsg) { miqService.sparkleOn(); API[method](url, saveObject) - .then(miqService.redirectBack.bind(vm, saveMsg, 'success', vm.redirectUrl)) + // TODO remove once API supports adding/removing buttons from button set + .then( function() { + $http.post('/generic_object_definition/add_custom_buttons_in_set',{custom_button_set_id: vm.customButtonGroupRecordId, assigned_custom_buttons: vm.customButtonGroupModel.assigned_buttons}) + .then(function() { + miqService.redirectBack(saveMsg, 'success', vm.redirectUrl); + }) + .catch(miqService.handleFailure) + }) .catch(miqService.handleFailure); }; diff --git a/app/controllers/generic_object_definition_controller.rb b/app/controllers/generic_object_definition_controller.rb index 036958a583cb..7707550a2e54 100644 --- a/app/controllers/generic_object_definition_controller.rb +++ b/app/controllers/generic_object_definition_controller.rb @@ -104,6 +104,7 @@ def custom_button_group_edit assert_privileges('ab_group_edit') @custom_button_group = CustomButtonSet.find(params[:id]) title = _("Edit Custom Button Group '%{name}'") % {:name => @custom_button_group.name} + @generic_object_definition = GenericObjectDefinition.find(@custom_button_group.set_data[:applies_to_id]) render_form(title, 'custom_button_group_form') end @@ -144,6 +145,28 @@ def add_button_in_group custom_button_set.save! end + def add_custom_buttons_in_set + custom_button_set = CustomButtonSet.find(params[:custom_button_set_id]) + custom_buttons = params[:assigned_custom_buttons].pluck(:id).map { |id| CustomButton.find_by(:id => id) } + custom_button_set.replace_children(custom_buttons) + custom_button_set.save! + render :json => {:status => 200} + end + + def custom_buttons_in_set + assigned_buttons = if params[:custom_button_set_id].present? + button_set = CustomButtonSet.find(params[:custom_button_set_id]) + button_set.custom_buttons + else + [] + end + generic_object_definition = GenericObjectDefinition.find(params[:generic_object_definition_id]) + unassigned_buttons = generic_object_definition.custom_buttons + assigned_buttons.map! { |button| {:name => button.name, :id => button.id} } + unassigned_buttons.map! { |button| {:name => button.name, :id => button.id} } + render :json => {:assigned_buttons => assigned_buttons, :unassigned_buttons => unassigned_buttons} + end + private def node_type(node) diff --git a/app/views/static/generic_object/assign-buttons.html.haml b/app/views/static/generic_object/assign-buttons.html.haml new file mode 100644 index 000000000000..81d13034ae2b --- /dev/null +++ b/app/views/static/generic_object/assign-buttons.html.haml @@ -0,0 +1,57 @@ +.form-horizontal + %hr + %h3 + = _('Assign Buttons') + #column_lists + .col-md-5 + = _('Unassigned:') + %select{:name => 'unassigned_buttons', + "ng-model" => "vm.model.selectedUnassignedButtons", + "ng-options" => "item.id as item.name for item in vm.unassignedButtons", + :multiple => true, + :class => "form-control", + :style => "overflow-x: scroll;", + :size => 8, + :id => "available_fields"} + .col-md-1{:style => "padding: 10px"} + .spacer + .spacer + %button.btn.btn-default.btn-block{:title => _("Move selected fields right"), + "ng-click" => "vm.rightButtonClicked()" } + %i.fa.fa-angle-right.fa-lg.hidden-xs.hidden-sm + %i.fa.fa-lg.fa-angle-right.fa-rotate-90.hidden-md.hidden-lg + %button.btn.btn-default.btn-block{:title => _("Move selected fields left"), + "ng-click" => "vm.leftButtonClicked()"} + %i.fa.fa-angle-left.fa-lg.hidden-xs.hidden-sm + %i.fa.fa-lg.fa-angle-left.fa-rotate-90.hidden-md.hidden-lg + .spacer + .col-md-5 + = _('Selected:') + %select{:name => 'assigned_buttons', + "ng-model" => "vm.model.selectedAssignedButtons", + "ng-options" => "item.id as item.name for item in vm.assignedButtons", + :multiple => true, + :class => "form-control", + :style => "overflow-x: scroll;", + :size => 8, + :id => "selected_fields"} + .col-md-1{:style => "padding: 10px"} + .spacer + .spacer + %button.btn.btn-default.btn-block{:title => _("Move selected fields to top"), + "ng-enabled" => "vm.moveButtonsEnabled()", + "ng-click" => "vm.topButtonClicked()"} + %i.fa.fa-angle-double-up.fa-lg + %button.btn.btn-default.btn-block{:title => _("Move selected fields up"), + :enabled => "vm.moveButtonsEnabled()", + "ng-click" => "vm.upButtonClicked()"} + %i.fa.fa-angle-up.fa-lg + %button.btn.btn-default.btn-block{:title => _("Move selected fields down"), + "ng-enabled" => "vm.moveButtonsEnabled()", + "ng-click" => "vm.downButtonClicked()"} + %i.fa.fa-angle-down.fa-lg + %button.btn.btn-default.btn-block{:title => _("Move selected fields to bottom"), + "ng-enabled" => "vm.moveButtonsEnabled()", + "ng-click" => "vm.bottomButtonClicked()"} + %i.fa.fa-angle-double-down + .spacer diff --git a/app/views/static/generic_object/main_custom_button_group_form.html.haml b/app/views/static/generic_object/main_custom_button_group_form.html.haml index c564ece4c298..a1c883043700 100644 --- a/app/views/static/generic_object/main_custom_button_group_form.html.haml +++ b/app/views/static/generic_object/main_custom_button_group_form.html.haml @@ -8,4 +8,7 @@ "miq-form" => true} %custom-button-group-form{"model" => "vm.customButtonGroupModel", "angular-form" => "angularForm"} + %assign-buttons{"assigned-buttons" => 'vm.customButtonGroupModel.assigned_buttons', + "unassigned-buttons" => 'vm.customButtonGroupModel.unassigned_buttons', + "update-buttons" => 'vm.updateButtons'} = render :partial => "layouts/angular/generic_form_buttons" diff --git a/config/routes.rb b/config/routes.rb index a24ae59d51c9..e2672cf7088a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1997,6 +1997,7 @@ :generic_object_definition => { :get => %w( + custom_buttons_in_set download_data download_summary_pdf edit @@ -2008,6 +2009,7 @@ ), :post => %w( add_button_in_group + add_custom_buttons_in_set button create_del custom_button_group_new