Hi Salgado, Thanks for the review. Comments below. > Hi Edwin, > > This is a nice branch but I think we're missing some test coverage for > some changes you introduced. > > review needsfixing > > On Fri, 2009-12-18 at 06:36 +0000, Edwin Grubbs wrote: > > Summary > > ------- > > > > This branch is dependent on > > lp:~edwin-grubbs/launchpad/bug-482176-add-team-member-ajax-part1 > > > > I made the following changes: > > * Added a windmill test > > * Changed the return value from IPerson.addMember() so > > the UI knows what status it decided to use. > > * If the user is allowed to invite a member because they can admin > > the owning team and if the user is allowed to accept the invitation > > because they can admin the member team, addMember() now just fully > > approves the membership. > > > > Over 50 tests broke because I changed the return value for > > addMember() and setStatus(). I only fixed one of them as a sample. > > The rest will have to wait for a followup branch, since I'm interested > > in getting feedback on the changes I made already. > > I think most of these tests are probably not interested in the return > value of addMember(), and in that case I suggest you change these ones > to assign the return value of addMember() to a dummy variable so that > they don't break again when we need to change the return value once > again. I added the dummy variable in the mailinglist-views.txt test, and I will do that for the others. > > === modified file 'lib/canonical/launchpad/javascript/registry/team.js' > > --- lib/canonical/launchpad/javascript/registry/team.js 2009-12-18 06:36:27 > +0000 > > +++ lib/canonical/launchpad/javascript/registry/team.js 2009-12-18 06:36:29 > +0000 > > @@ -15,87 +15,122 @@ > > * @method setup_add_member_handler > > */ > > module.setup_add_member_handler = function() { > > + if (Y.UA.ie) { > > + return; > > + } > > + > > var config = { > > header: 'Add a member', > > step_title: 'Search', > > picker_activator: '.menu-link-add_member' > > }; > > > > - var picker = Y.lp.picker.create( > > - 'ValidTeamMember', > > - function(result) { _add_member(result); }, > > - config); > > + Y.lp.picker.create('ValidTeamMember', _add_member, config); > > }; > > > > -var _add_member = function(result) { > > - var spinner = Y.one('#add-member-spinner'); > > - var addmember_link = Y.one('.menu-link-add_member'); > > - addmember_link.setStyle('display', 'none'); > > - spinner.setStyle('display', 'inline'); > > - function disable_spinner() { > > - addmember_link.setStyle('display', 'inline'); > > - spinner.setStyle('display', 'none'); > > - } > > +var _add_member = function(selected_person) { > > + var box = Y.one('#membership'); > > + var spinner = box.query('#add-member-spinner'); > > + var addmember_link = box.query('.menu-link-add_member'); > > + addmember_link.addClass('unseen'); > > + spinner.removeClass('unseen'); > > + var disable_spinner = function() { > > + addmember_link.removeClass('unseen'); > > + spinner.addClass('unseen'); > > + }; > > lp_client = new LP.client.Launchpad(); > > > > var error_handler = new LP.client.ErrorHandler(); > > error_handler.clearProgressUI = disable_spinner; > > error_handler.showError = function(error_msg) { > > - Y.lp.display_error(Y.one('.menu-link-add_member'), error_msg); > > + Y.lp.display_error(addmember_link, error_msg); > > }; > > > > - config = { > > + addmember_config = { > > on: { > > - success: function(member_added) { > > - if (!member_added) { > > - disable_spinner(); > > - alert('Already a member.'); > > - return; > > - } > > - if (result.css.match("team")) { > > - disable_spinner(); > > - alert('This is a team'); > > - return; > > - } > > - var members_section = Y.one('#recently-approved'); > > - var members_ul = Y.one('#recently-approved-ul'); > > + success: function(change_and_status) { > > + var did_status_change = change_and_status[0]; > > + var current_status = change_and_status[1]; > > + var members_section, members_ul, count_elem; > > + if (did_status_change === false) { > > + disable_spinner(); > > + Y.lp.display_error( > > + addmember_link, > > + selected_person.title + ' is already ' + > > + current_status + '.'); > > + return; > > + } > > + var is_team = false; > > + if (current_status == 'Invited') { > > I thought current_status would be a JSON representation of an > ITeamMembership, which is what's returned by addMember(), but I guess > I'm wrong? Yes, the REST API represents vocabulary values with strings instead of expanding it into full Entry objects. > Also, since it's capitalized, I think it'd make sense to lower case it > in the error message above. And btw, it should be just an informational > notice as the user hasn't done anything wrong. Done. > > + is_team = true; > > + members_section = box.query('#recently-invited'); > > + members_ul = box.query('#recently-invited-ul'); > > + count_elem = box.query('#invited-member-count'); > > + } else if (current_status == 'Proposed') { > > + is_team = true; > > + members_section = box.query('#recently-proposed'); > > + members_ul = box.query('#recently-proposed-ul'); > > + count_elem = box.query('#proposed-member-count'); > > + } else if (current_status == 'Approved') { > > + members_section = box.query('#recently-approved'); > > + members_ul = box.query('#recently-approved-ul'); > > + count_elem = box.query('#approved-member-count'); > > + } else { > > + Y.lp.display_error( > > + addmember_link, > > + 'Unexpected status: ' + current_status); > > Don't you want an early return here? Yes, done. > > + } > > var first_node = members_ul.get('firstChild'); > > - config = { > > + > > + var xhtml_person_handler = function(person_html) { > > + if (count_elem === null && is_team) { > > + count_elem = Y.Node.create( > > + '' + > > + '1'); > > + var count_box = Y.one( > > + '#membership #membership-counts'); > > + count_box.append(Y.Node.create( > > + ', ')); > > + count_box.append(count_elem); > > + count_box.append(Y.Node.create( > > + ' ' + > > + 'invited members')); > > s/members/member, since there's only one? But then if the user adds > another team which ends up invited, we'll have some trouble to change it > from "2 member" into "2 members". Let's leave it as is, I guess. > > > + } else { > > + var count = count_elem.get('innerHTML'); > > + count = parseInt(count, 10) + 1; > > + count_elem.set('innerHTML', count); > > + } > > + person_repr = Y.Node.create( > > + '