Support multiple role selection in projects
Horizon currently overwrites existing roles when saving project membership. The backend was only initialising the form with the first role of each user, so when the form was submitted any other roles on *all* users were removed. Changes: - Fix backend to pass through all roles - Keep role dropdown open on click, clicks add a tick to a role - Show the first two roles on the dropdown label, add a "..." for three or more. Fixes bug #1081374. Change-Id: Iaf64afc4c50d4d24d6acb529a6e810a0ba154505
This commit is contained in:
parent
db410ce91a
commit
4c34f5f1e8
@ -19,11 +19,20 @@ horizon.projects = {
|
||||
|
||||
/*
|
||||
* Gets the html select element associated with a given
|
||||
* role id for role_id.
|
||||
* role id.
|
||||
**/
|
||||
get_role_element: function(role_id) {
|
||||
return $('select[id^="id_role_' + role_id + '"]');
|
||||
},
|
||||
|
||||
/*
|
||||
* Gets the html ul element associated with a given
|
||||
* user id. I.e., the user's row.
|
||||
**/
|
||||
get_user_element: function(user_id) {
|
||||
return $('li[data-user-id$=' + user_id + ']').parent();
|
||||
},
|
||||
|
||||
/*
|
||||
|
||||
* Gets the html select element associated with a given
|
||||
@ -115,16 +124,16 @@ horizon.projects = {
|
||||
});
|
||||
},
|
||||
/*
|
||||
* Checks to see whether a user is a member of the current project.
|
||||
* If they are, returns the id of their primary role.
|
||||
* Returns the ids of roles the user is a member of.
|
||||
**/
|
||||
is_project_member: function(user_id) {
|
||||
get_user_roles: function(user_id) {
|
||||
var roles = [];
|
||||
for (var role in horizon.projects.current_membership) {
|
||||
if ($.inArray(user_id, horizon.projects.current_membership[role]) >= 0) {
|
||||
return role;
|
||||
roles.push(role);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return roles;
|
||||
},
|
||||
|
||||
/*
|
||||
@ -133,8 +142,6 @@ horizon.projects = {
|
||||
**/
|
||||
update_role_lists: function(role_id, new_list) {
|
||||
this.get_role_element(role_id).val(new_list);
|
||||
this.get_role_element(role_id).find("option[value='" + role_id + "").attr("selected", "selected");
|
||||
|
||||
horizon.projects.current_membership[role_id] = new_list;
|
||||
},
|
||||
|
||||
@ -178,11 +185,45 @@ horizon.projects = {
|
||||
horizon.projects.update_role_lists(role_id, role_list);
|
||||
},
|
||||
|
||||
update_user_role_dropdown: function(user_id, role_ids, user_el) {
|
||||
if (typeof(role_ids) === 'undefined') {
|
||||
role_ids = horizon.projects.get_user_roles(user_id);
|
||||
}
|
||||
if (typeof(user_el) === 'undefined') {
|
||||
user_el = horizon.projects.get_user_element(user_id);
|
||||
}
|
||||
|
||||
var $dropdown = user_el.find("li.member").siblings('.dropdown');
|
||||
var $role_items = $dropdown.children('.role_dropdown').children('li');
|
||||
|
||||
$role_items.each(function (idx, el) {
|
||||
if (_.contains(role_ids, $(el).data('role-id'))) {
|
||||
$(el).addClass('selected');
|
||||
} else {
|
||||
$(el).removeClass('selected');
|
||||
}
|
||||
});
|
||||
|
||||
// set the selection back to default role
|
||||
var $roles_display = $dropdown.children('.dropdown-toggle').children('.roles_display');
|
||||
var roles_to_display = [];
|
||||
for (var i = 0; i < role_ids.length; i++) {
|
||||
if (i == 2) {
|
||||
roles_to_display.push('...');
|
||||
break;
|
||||
}
|
||||
roles_to_display.push(horizon.projects.roles[role_ids[i]]);
|
||||
}
|
||||
text = roles_to_display.join(', ');
|
||||
if (text.length == 0) text = 'No roles';
|
||||
$roles_display.text(text);
|
||||
},
|
||||
|
||||
/*
|
||||
* Generates the HTML structure for a user that will be displayed
|
||||
* as a list item in the project member list.
|
||||
**/
|
||||
generate_user_element: function(user_name, user_id, text) {
|
||||
generate_user_element: function(user_name, user_id, role_ids, text) {
|
||||
var str_id = "id_user_" + user_id;
|
||||
|
||||
var roles = [];
|
||||
@ -200,6 +241,7 @@ horizon.projects = {
|
||||
text: text,
|
||||
roles: roles},
|
||||
user_el = $(template.render(params));
|
||||
this.update_user_role_dropdown(str_id, role_ids, user_el);
|
||||
return $(user_el);
|
||||
},
|
||||
|
||||
@ -213,11 +255,6 @@ horizon.projects = {
|
||||
return $li;
|
||||
},
|
||||
|
||||
set_selected_role: function(selected_el, role_id) {
|
||||
$(selected_el).text(horizon.projects.roles[role_id]);
|
||||
$(selected_el).attr('data-role-id', role_id);
|
||||
},
|
||||
|
||||
/*
|
||||
* Generates the HTML structure for the project membership UI.
|
||||
**/
|
||||
@ -226,14 +263,12 @@ horizon.projects = {
|
||||
for (user in horizon.projects.users) {
|
||||
var user_id = user;
|
||||
var user_name = horizon.projects.users[user];
|
||||
var role_id = this.is_project_member(user_id);
|
||||
if (role_id) {
|
||||
$(".project_members").append(this.generate_user_element(user_name, user_id, "-"));
|
||||
var $selected_role = $("li[data-user-id$='" + user_id + "']").siblings('.dropdown').children('.dropdown-toggle').children('span');
|
||||
horizon.projects.set_selected_role($selected_role, role_id);
|
||||
var role_ids = this.get_user_roles(user_id);
|
||||
if (role_ids.length > 0) {
|
||||
$(".project_members").append(this.generate_user_element(user_name, user_id, role_ids, "-"));
|
||||
}
|
||||
else {
|
||||
$(".available_users").append(this.generate_user_element(user_name, user_id, "+"));
|
||||
$(".available_users").append(this.generate_user_element(user_name, user_id, role_ids, "+"));
|
||||
}
|
||||
}
|
||||
horizon.projects.detect_no_results();
|
||||
@ -313,26 +348,24 @@ horizon.projects = {
|
||||
evt.preventDefault();
|
||||
var available = $(".available_users").has($(this)).length;
|
||||
var user_id = horizon.projects.get_field_id($(this).parent().siblings().attr('data-user-id'));
|
||||
var user_el = $(this).parent().parent();
|
||||
|
||||
if (available) {
|
||||
$(this).text("-");
|
||||
if (horizon.projects.has_roles) {
|
||||
$(this).parent().siblings(".role_options").show();
|
||||
}
|
||||
$(".project_members").append($(this).parent().parent());
|
||||
$(".project_members").append(user_el);
|
||||
|
||||
horizon.projects.add_user_to_role(user_id, horizon.projects.default_role_id);
|
||||
if (horizon.projects.has_roles) {
|
||||
var default_role = horizon.projects.default_role_id;
|
||||
$(this).parent().siblings(".role_options").show();
|
||||
horizon.projects.add_user_to_role(user_id, default_role);
|
||||
horizon.projects.update_user_role_dropdown(user_id, [default_role], user_el);
|
||||
}
|
||||
}
|
||||
else {
|
||||
$(this).text("+");
|
||||
$(this).parent().siblings(".role_options").hide();
|
||||
$(".available_users").append($(this).parent().parent());
|
||||
|
||||
$(".available_users").append(user_el);
|
||||
horizon.projects.remove_user_from_role(user_id);
|
||||
|
||||
// set the selection back to default role
|
||||
var $selected_role = $(this).parent().siblings('.dropdown').children('.dropdown-toggle').children('.selected_role');
|
||||
horizon.projects.set_selected_role($selected_role, horizon.projects.default_role_id);
|
||||
}
|
||||
|
||||
// update lists
|
||||
@ -368,8 +401,8 @@ horizon.projects = {
|
||||
**/
|
||||
select_member_role: function() {
|
||||
$(".available_users, .project_members").on('click', '.role_dropdown li', function (evt) {
|
||||
var $selected_el = $(this).parent().prev().children('.selected_role');
|
||||
$selected_el.text($(this).text());
|
||||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
|
||||
// get the newly selected role and the member's name
|
||||
var new_role_id = $(this).attr("data-role-id");
|
||||
@ -377,8 +410,14 @@ horizon.projects = {
|
||||
var user_id = horizon.projects.get_field_id(id_str);
|
||||
|
||||
// update role lists
|
||||
horizon.projects.remove_user_from_role(user_id, $selected_el.attr('data-role-id'));
|
||||
horizon.projects.add_user_to_role(user_id, new_role_id);
|
||||
if ($(this).hasClass('selected')) {
|
||||
$(this).removeClass('selected');
|
||||
horizon.projects.remove_user_from_role(user_id, new_role_id);
|
||||
} else {
|
||||
$(this).addClass('selected');
|
||||
horizon.projects.add_user_to_role(user_id, new_role_id);
|
||||
}
|
||||
horizon.projects.update_user_role_dropdown(user_id);
|
||||
});
|
||||
},
|
||||
|
||||
@ -390,12 +429,13 @@ horizon.projects = {
|
||||
// add the user to the visible list
|
||||
var user_name = $(this).find("option").text();
|
||||
var user_id = $(this).find("option").attr("value");
|
||||
$(".project_members").append(horizon.projects.generate_user_element(user_name, user_id, "-"));
|
||||
var default_role_id = horizon.projects.default_role_id;
|
||||
$(".project_members").append(horizon.projects.generate_user_element(user_name, user_id, [default_role_id], "-"));
|
||||
|
||||
// add the user to the hidden role lists and the users list
|
||||
horizon.projects.users[user_id] = user_name;
|
||||
$("select[multiple='multiple']").append("<option value='" + user_id + "'>" + horizon.projects.users[user_id] + "</option>");
|
||||
horizon.projects.add_user_to_role(user_id, horizon.projects.default_role_id);
|
||||
horizon.projects.add_user_to_role(user_id, default_role_id);
|
||||
|
||||
// remove option from hidden select
|
||||
$(this).text("");
|
||||
|
@ -12,12 +12,12 @@
|
||||
<li class="active"><a class="btn btn-primary" href="#add_remove">[[text]]</a></li>
|
||||
<li class="dropdown role_options">
|
||||
<a class="dropdown-toggle" data-toggle="dropdown" href="#">
|
||||
<span class="selected_role">[[default_role]]</span>
|
||||
<span class="roles_display">Roles</span>
|
||||
<b class="caret"></b>
|
||||
</a>
|
||||
<ul class="dropdown-menu role_dropdown clearfix">
|
||||
[[#roles]]
|
||||
<li data-role-id="[[role_id]]">[[role_name]]</li>
|
||||
<li data-role-id="[[role_id]]"><i class="icon-ok"></i> [[role_name]]</li>
|
||||
[[/roles]]
|
||||
</ul>
|
||||
</li>
|
||||
|
@ -166,9 +166,8 @@ class UpdateProjectMembersAction(workflows.Action):
|
||||
exceptions.handle(request,
|
||||
err_msg,
|
||||
redirect=reverse(INDEX_URL))
|
||||
if roles:
|
||||
primary_role = roles[0].id
|
||||
self.fields["role_" + primary_role].initial.append(user.id)
|
||||
for role in roles:
|
||||
self.fields["role_" + role.id].initial.append(user.id)
|
||||
|
||||
class Meta:
|
||||
name = _("Project Members")
|
||||
|
@ -1453,10 +1453,20 @@ label.log-length {
|
||||
-moz-box-shadow: none;
|
||||
box-shadow: none;
|
||||
z-index: 99999;
|
||||
i {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #CDCDCD;
|
||||
}
|
||||
&.selected i {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
.dropdown-menu.role_dropdown {
|
||||
right: 0;
|
||||
left: auto;
|
||||
}
|
||||
.nav .role_options {
|
||||
float: right;
|
||||
|
Loading…
Reference in New Issue
Block a user