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

GOD's button group can have buttons assign/unassign during create/edit #4913

Merged
merged 22 commits into from
Aug 2, 2019
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
831bda5
Add assign button section to Custom Button Group in GOD
ZitaNemeckova Nov 14, 2018
2dce5ab
Add specs for right/left/up/down/buttom/top clicked
ZitaNemeckova Jan 14, 2019
0879c47
Use _.some instead of includes
ZitaNemeckova Jan 16, 2019
41de4b1
vm.model.assigned/unassignedButtons - change to local variables
himdel Feb 12, 2019
d7475ec
AssignButtons - don't update unassigned buttons unless dealing with l…
himdel Feb 12, 2019
e84e54a
eslint fixes
himdel Feb 12, 2019
be2cacb
assign buttons spec - test the state after updateButtons, not a local…
himdel Feb 12, 2019
99bef04
Pull out idsToIndexes & removeElements
himdel Feb 12, 2019
e88642a
add moveBetween, replace left & right
himdel Feb 12, 2019
1a15728
idsToElements - rewrite left & right in terms of idsToElements instea…
himdel Feb 12, 2019
67628cf
moveTop, moveBottom - selected.concat(unselected) or unselected.conca…
himdel Feb 12, 2019
b0f132a
assign-buttons_spec - fix name in describe, simplify inject
himdel Feb 15, 2019
e31ea87
move up,down
himdel Feb 15, 2019
5ac2c05
Create move.js, use move.* names, move code there
himdel Feb 15, 2019
f5face0
move.js update exports
himdel Feb 15, 2019
e30e46c
move.js - es6 & lodash
himdel Feb 15, 2019
9b0cf63
move.js - stepUp & stepDown
himdel Feb 15, 2019
0955e0a
Use angular.copy instead of Object.assign to prevent error when origi…
ZitaNemeckova Jul 29, 2019
3f926f3
Use cloneDeep to prevent use of references. DO NOT add undefined to e…
ZitaNemeckova Jul 31, 2019
59fafce
Move class to correct place. Linter fixes
ZitaNemeckova Jul 31, 2019
0f8c328
Remove add_custom_buttons_in_set method. Use RBAC.
ZitaNemeckova Jul 31, 2019
03d6c5f
Move mpve function to be on ManageIQ instead of global
ZitaNemeckova Aug 1, 2019
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
@@ -0,0 +1,63 @@
/* globals move */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no longer needed


ManageIQ.angular.app.component('assignButtons', {
bindings: {
assignedButtons: '<',
unassignedButtons: '<',
updateButtons: '<',
},
require: {
parent: '^^mainCustomButtonGroupForm',
},
controllerAs: 'vm',
controller: assignButtonsController,
templateUrl: '/static/generic_object/assign-buttons.html.haml',
});


// move comes from app/javascript/helpers/move.js
function assignButtonsController() {
var vm = this;

vm.model = {
selectedAssignedButtons: [],
selectedUnassignedButtons: [],
};

vm.leftButtonClicked = function() {
var ret = move.between({
from: [].concat(vm.assignedButtons),
to: [].concat(vm.unassignedButtons),
selected: vm.model.selectedAssignedButtons,
});

vm.updateButtons(ret.from, ret.to);
};

vm.rightButtonClicked = function() {
var ret = move.between({
from: [].concat(vm.unassignedButtons),
to: [].concat(vm.assignedButtons),
selected: vm.model.selectedUnassignedButtons,
});

vm.updateButtons(ret.to, ret.from);
};

function wrap(fn) {
return function() {
var assigned = fn({
array: [].concat(vm.assignedButtons),
selected: vm.model.selectedAssignedButtons,
});

vm.updateButtons(assigned);
};
}

vm.topButtonClicked = wrap(move.top);
vm.bottomButtonClicked = wrap(move.bottom);

vm.upButtonClicked = wrap(move.up);
vm.downButtonClicked = wrap(move.down);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand All @@ -26,20 +26,35 @@ 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);
};

vm.updateButtons = function(assignedButtons, unassignedButtons) {
vm.customButtonGroupModel.assigned_buttons = assignedButtons;

API.get('/api/custom_button_sets?expand=resources&attributes=set_data')
.then(getCustomButtonSetGroupIndex)
.catch(miqService.handleFailure);
if (unassignedButtons) {
vm.customButtonGroupModel.unassigned_buttons = unassignedButtons;
}
};

Expand All @@ -53,7 +68,7 @@ function mainCustomButtonGroupFormController(API, miqService) {
};

vm.resetClicked = function(angularForm) {
vm.customButtonGroupModel = Object.assign({}, vm.modelCopy);
vm.customButtonGroupModel = _.cloneDeep(vm.modelCopy);

angularForm.$setUntouched(true);
angularForm.$setPristine(true);
Expand All @@ -71,11 +86,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),
Expand All @@ -94,7 +117,17 @@ 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is done in ManageIQ/manageiq#18368

.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);
};

Expand All @@ -112,7 +145,8 @@ function mainCustomButtonGroupFormController(API, miqService) {

vm.customButtonGroupModel.set_data = {};

vm.modelCopy = Object.assign({}, vm.customButtonGroupModel);
vm.modelCopy = _.cloneDeep(vm.customButtonGroupModel);

vm.afterGet = true;
miqService.sparkleOff();
}
Expand All @@ -123,6 +157,6 @@ function mainCustomButtonGroupFormController(API, miqService) {
return setData.applies_to_class === 'GenericObject';
}).length;
vm.customButtonGroupModel.group_index = currentGroupIndex + 1;
vm.modelCopy = angular.copy( vm.customButtonGroupModel );
vm.modelCopy = _.cloneDeep(vm.customButtonGroupModel);
}
}
2 changes: 1 addition & 1 deletion app/assets/javascripts/directives/form_changed.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ ManageIQ.angular.app.directive('formChanged', function() {

var compare = function(original, copy, key) {
// add missing keys in copy from original so recursion works
if (_.isObject(copy) && _.isObject(original)) {
if (_.isObject(copy) && _.isObject(original) && !_.isArray(copy) && !_.isArray(original)) {
_.difference(Object.keys(original), Object.keys(copy)).forEach(function(k) {
copy[k] = undefined;
});
Expand Down
23 changes: 23 additions & 0 deletions app/controllers/generic_object_definition_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ def custom_button_group_edit
assert_privileges('ab_group_edit')
@custom_button_group = CustomButtonSet.find(params[:id])
@right_cell_text = _("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(@right_cell_text, 'custom_button_group_form')
end

Expand Down Expand Up @@ -148,6 +149,28 @@ def add_button_in_group
custom_button_set.save!
end

def add_custom_buttons_in_set
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(probably not needed - the API now does it too)

custom_button_set = CustomButtonSet.find(params[:custom_button_set_id])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

find_record_with_rbac

custom_buttons = params[:assigned_custom_buttons].pluck(:id).map { |id| CustomButton.find_by(:id => id) }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

custom_buttons = find_records_with_rbac(CustomButton, params[:assigned_custom_buttons].pluck(:id)

custom_button_set.replace_children(custom_buttons)
custom_button_set.save!
render :json => {:status => 200}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

find_record_with_rbac

button_set.custom_buttons
else
[]
end
generic_object_definition = GenericObjectDefinition.find(params[:generic_object_definition_id])
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rbac

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)
Expand Down
109 changes: 109 additions & 0 deletions app/javascript/helpers/move.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import { find, findIndex, some, reject } from 'lodash';

// [{id: 123}], [123] => [0]
function idsToElements(arr, ids) {
return ids.map((id) => find(arr, { id }));
}

function idsToIndexes(arr, ids) {
return ids.map((id) => findIndex(arr, { id }));
}

function removeElements(arr, elements) {
return reject(arr, (elem) => some(elements, elem));
}

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 stepUp(array, index) {
if (index < 1) {
return;
}

[array[index], array[index - 1]] = [array[index - 1], array[index]];
}

function stepDown(array, index) {
if ((index < 0) || (index >= array.length - 1)) {
return;
}

[array[index], array[index + 1]] = [array[index + 1], array[index]];
}


// move selected elements between two arrays
export function between({from, to, selected}) {
var moved = idsToElements(from, selected);

return {
from: removeElements(from, moved),
to: to.concat(moved),
};
}

// move selected elements to the top of the array
export function top({array, selected}) {
var moved = idsToElements(array, selected);
array = removeElements(array, moved);

return moved.concat(array);
}

// move selected elements to the bottom of the array
export function bottom({array, selected}) {
var moved = idsToElements(array, selected);
array = removeElements(array, moved);

return array.concat(moved);
}

// move selected elements one position up
export function up({array, selected}) {
var indexes = idsToIndexes(array, selected);
indexes = filterIndexes(indexes);

indexes.forEach((index) => stepUp(array, index));

return array;
}

// move selected elements one position up
export function down({array, selected}) {
var indexes = idsToIndexes(array, selected).reverse();
indexes = filterReverseIndexes(indexes, array.length - 1);

indexes.forEach((index) => stepDown(array, index));

return array;
}
2 changes: 2 additions & 0 deletions app/javascript/packs/globals.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,5 @@ require('codemirror/mode/xml/xml.js');
require('codemirror/mode/yaml/yaml.js');
require('codemirror/lib/codemirror.css');
require('codemirror/theme/eclipse.css');
import * as move from '../helpers/move.js';
window.move = move;
ZitaNemeckova marked this conversation as resolved.
Show resolved Hide resolved
Loading