提交 0e570857 编写于 作者: D Dmitriy Zaporozhets

Merge branch 'feature/select2-user-ajax'

...@@ -113,6 +113,7 @@ group :assets do ...@@ -113,6 +113,7 @@ group :assets do
gem "therubyracer" gem "therubyracer"
gem 'chosen-rails', "0.9.8" gem 'chosen-rails', "0.9.8"
gem 'select2-rails'
gem 'jquery-atwho-rails', "0.1.7" gem 'jquery-atwho-rails', "0.1.7"
gem "jquery-rails", "2.1.3" gem "jquery-rails", "2.1.3"
gem "jquery-ui-rails", "2.0.2" gem "jquery-ui-rails", "2.0.2"
......
...@@ -384,6 +384,9 @@ GEM ...@@ -384,6 +384,9 @@ GEM
seed-fu (2.2.0) seed-fu (2.2.0)
activerecord (~> 3.1) activerecord (~> 3.1)
activesupport (~> 3.1) activesupport (~> 3.1)
select2-rails (3.3.1)
sass-rails (>= 3.2)
thor (~> 0.14)
selenium-webdriver (2.30.0) selenium-webdriver (2.30.0)
childprocess (>= 0.2.5) childprocess (>= 0.2.5)
multi_json (~> 1.0) multi_json (~> 1.0)
...@@ -534,6 +537,7 @@ DEPENDENCIES ...@@ -534,6 +537,7 @@ DEPENDENCIES
sass-rails (~> 3.2.5) sass-rails (~> 3.2.5)
sdoc sdoc
seed-fu seed-fu
select2-rails
settingslogic settingslogic
shoulda-matchers (= 1.3.0) shoulda-matchers (= 1.3.0)
sidekiq sidekiq
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
//= require bootstrap //= require bootstrap
//= require modernizr //= require modernizr
//= require chosen-jquery //= require chosen-jquery
//= require select2
//= require raphael //= require raphael
//= require g.raphael-min //= require g.raphael-min
//= require g.bar-min //= require g.bar-min
......
function md5 (str) {
// http://kevin.vanzonneveld.net
// + original by: Webtoolkit.info (http://www.webtoolkit.info/)
// + namespaced by: Michael White (http://getsprink.com)
// + tweaked by: Jack
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + input by: Brett Zamir (http://brett-zamir.me)
// + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// - depends on: utf8_encode
// * example 1: md5('Kevin van Zonneveld');
// * returns 1: '6e658d4bfcb59cc13f96c14450ac40b9'
var xl;
var rotateLeft = function (lValue, iShiftBits) {
return (lValue << iShiftBits) | (lValue >>> (32 - iShiftBits));
};
var addUnsigned = function (lX, lY) {
var lX4, lY4, lX8, lY8, lResult;
lX8 = (lX & 0x80000000);
lY8 = (lY & 0x80000000);
lX4 = (lX & 0x40000000);
lY4 = (lY & 0x40000000);
lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
if (lX4 & lY4) {
return (lResult ^ 0x80000000 ^ lX8 ^ lY8);
}
if (lX4 | lY4) {
if (lResult & 0x40000000) {
return (lResult ^ 0xC0000000 ^ lX8 ^ lY8);
} else {
return (lResult ^ 0x40000000 ^ lX8 ^ lY8);
}
} else {
return (lResult ^ lX8 ^ lY8);
}
};
var _F = function (x, y, z) {
return (x & y) | ((~x) & z);
};
var _G = function (x, y, z) {
return (x & z) | (y & (~z));
};
var _H = function (x, y, z) {
return (x ^ y ^ z);
};
var _I = function (x, y, z) {
return (y ^ (x | (~z)));
};
var _FF = function (a, b, c, d, x, s, ac) {
a = addUnsigned(a, addUnsigned(addUnsigned(_F(b, c, d), x), ac));
return addUnsigned(rotateLeft(a, s), b);
};
var _GG = function (a, b, c, d, x, s, ac) {
a = addUnsigned(a, addUnsigned(addUnsigned(_G(b, c, d), x), ac));
return addUnsigned(rotateLeft(a, s), b);
};
var _HH = function (a, b, c, d, x, s, ac) {
a = addUnsigned(a, addUnsigned(addUnsigned(_H(b, c, d), x), ac));
return addUnsigned(rotateLeft(a, s), b);
};
var _II = function (a, b, c, d, x, s, ac) {
a = addUnsigned(a, addUnsigned(addUnsigned(_I(b, c, d), x), ac));
return addUnsigned(rotateLeft(a, s), b);
};
var convertToWordArray = function (str) {
var lWordCount;
var lMessageLength = str.length;
var lNumberOfWords_temp1 = lMessageLength + 8;
var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - (lNumberOfWords_temp1 % 64)) / 64;
var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
var lWordArray = new Array(lNumberOfWords - 1);
var lBytePosition = 0;
var lByteCount = 0;
while (lByteCount < lMessageLength) {
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
lBytePosition = (lByteCount % 4) * 8;
lWordArray[lWordCount] = (lWordArray[lWordCount] | (str.charCodeAt(lByteCount) << lBytePosition));
lByteCount++;
}
lWordCount = (lByteCount - (lByteCount % 4)) / 4;
lBytePosition = (lByteCount % 4) * 8;
lWordArray[lWordCount] = lWordArray[lWordCount] | (0x80 << lBytePosition);
lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
return lWordArray;
};
var wordToHex = function (lValue) {
var wordToHexValue = "",
wordToHexValue_temp = "",
lByte, lCount;
for (lCount = 0; lCount <= 3; lCount++) {
lByte = (lValue >>> (lCount * 8)) & 255;
wordToHexValue_temp = "0" + lByte.toString(16);
wordToHexValue = wordToHexValue + wordToHexValue_temp.substr(wordToHexValue_temp.length - 2, 2);
}
return wordToHexValue;
};
var x = [],
k, AA, BB, CC, DD, a, b, c, d, S11 = 7,
S12 = 12,
S13 = 17,
S14 = 22,
S21 = 5,
S22 = 9,
S23 = 14,
S24 = 20,
S31 = 4,
S32 = 11,
S33 = 16,
S34 = 23,
S41 = 6,
S42 = 10,
S43 = 15,
S44 = 21;
str = this.utf8_encode(str);
x = convertToWordArray(str);
a = 0x67452301;
b = 0xEFCDAB89;
c = 0x98BADCFE;
d = 0x10325476;
xl = x.length;
for (k = 0; k < xl; k += 16) {
AA = a;
BB = b;
CC = c;
DD = d;
a = _FF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
d = _FF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
c = _FF(c, d, a, b, x[k + 2], S13, 0x242070DB);
b = _FF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
a = _FF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
d = _FF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
c = _FF(c, d, a, b, x[k + 6], S13, 0xA8304613);
b = _FF(b, c, d, a, x[k + 7], S14, 0xFD469501);
a = _FF(a, b, c, d, x[k + 8], S11, 0x698098D8);
d = _FF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
c = _FF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
b = _FF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
a = _FF(a, b, c, d, x[k + 12], S11, 0x6B901122);
d = _FF(d, a, b, c, x[k + 13], S12, 0xFD987193);
c = _FF(c, d, a, b, x[k + 14], S13, 0xA679438E);
b = _FF(b, c, d, a, x[k + 15], S14, 0x49B40821);
a = _GG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
d = _GG(d, a, b, c, x[k + 6], S22, 0xC040B340);
c = _GG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
b = _GG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
a = _GG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
d = _GG(d, a, b, c, x[k + 10], S22, 0x2441453);
c = _GG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
b = _GG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
a = _GG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
d = _GG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
c = _GG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
b = _GG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
a = _GG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
d = _GG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);
c = _GG(c, d, a, b, x[k + 7], S23, 0x676F02D9);
b = _GG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);
a = _HH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);
d = _HH(d, a, b, c, x[k + 8], S32, 0x8771F681);
c = _HH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);
b = _HH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);
a = _HH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);
d = _HH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);
c = _HH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);
b = _HH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);
a = _HH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);
d = _HH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);
c = _HH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);
b = _HH(b, c, d, a, x[k + 6], S34, 0x4881D05);
a = _HH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);
d = _HH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);
c = _HH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);
b = _HH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);
a = _II(a, b, c, d, x[k + 0], S41, 0xF4292244);
d = _II(d, a, b, c, x[k + 7], S42, 0x432AFF97);
c = _II(c, d, a, b, x[k + 14], S43, 0xAB9423A7);
b = _II(b, c, d, a, x[k + 5], S44, 0xFC93A039);
a = _II(a, b, c, d, x[k + 12], S41, 0x655B59C3);
d = _II(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);
c = _II(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);
b = _II(b, c, d, a, x[k + 1], S44, 0x85845DD1);
a = _II(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);
d = _II(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);
c = _II(c, d, a, b, x[k + 6], S43, 0xA3014314);
b = _II(b, c, d, a, x[k + 13], S44, 0x4E0811A1);
a = _II(a, b, c, d, x[k + 4], S41, 0xF7537E82);
d = _II(d, a, b, c, x[k + 11], S42, 0xBD3AF235);
c = _II(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);
b = _II(b, c, d, a, x[k + 9], S44, 0xEB86D391);
a = addUnsigned(a, AA);
b = addUnsigned(b, BB);
c = addUnsigned(c, CC);
d = addUnsigned(d, DD);
}
var temp = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d);
return temp.toLowerCase();
}
$ ->
userFormatResult = (user) ->
avatar = gon.gravatar_url
avatar = avatar.replace('%{hash}', md5(user.email))
avatar = avatar.replace('%{size}', '24')
markup = "<div class='user-result'>"
markup += "<div class='user-image'><img class='avatar s24' src='" + avatar + "'></div>"
markup += "<div class='user-name'>" + user.name + "</div>"
markup += "<div class='user-username'>" + user.username + "</div>"
markup += "</div>"
markup
userFormatSelection = (user) ->
user.name
$('.ajax-users-select').select2
placeholder: "Search for a user"
multiple: $('.ajax-users-select').hasClass('multiselect')
minimumInputLength: 0
ajax: # instead of writing the function to execute the request we use Select2's convenient helper
url: "/api/" + gon.api_version + "/users.json"
dataType: "json"
data: (term, page) ->
search: term # search term
per_page: 10
private_token: gon.api_token
results: (data, page) -> # parse the results into the format expected by Select2.
# since we are using custom formatting functions we do not need to alter remote JSON data
results: data
initSelection: (element, callback) ->
id = $(element).val()
if id isnt ""
$.ajax(
"/api/" + gon.api_version + "/users/" + id + ".json",
dataType: "json"
data:
private_token: gon.api_token
).done (data) ->
callback data
formatResult: userFormatResult # omitted for brevity, see the source of this page
formatSelection: userFormatSelection # omitted for brevity, see the source of this page
dropdownCssClass: "ajax-users-dropdown" # apply css that makes the dropdown taller
escapeMarkup: (m) -> # we do not want to escape markup since we are displaying html in results
m
function utf8_encode (argString) {
// http://kevin.vanzonneveld.net
// + original by: Webtoolkit.info (http://www.webtoolkit.info/)
// + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// + improved by: sowberry
// + tweaked by: Jack
// + bugfixed by: Onno Marsman
// + improved by: Yves Sucaet
// + bugfixed by: Onno Marsman
// + bugfixed by: Ulrich
// + bugfixed by: Rafal Kukawski
// + improved by: kirilloid
// + bugfixed by: kirilloid
// * example 1: utf8_encode('Kevin van Zonneveld');
// * returns 1: 'Kevin van Zonneveld'
if (argString === null || typeof argString === "undefined") {
return "";
}
var string = (argString + ''); // .replace(/\r\n/g, "\n").replace(/\r/g, "\n");
var utftext = '',
start, end, stringl = 0;
start = end = 0;
stringl = string.length;
for (var n = 0; n < stringl; n++) {
var c1 = string.charCodeAt(n);
var enc = null;
if (c1 < 128) {
end++;
} else if (c1 > 127 && c1 < 2048) {
enc = String.fromCharCode(
(c1 >> 6) | 192,
( c1 & 63) | 128
);
} else if (c1 & 0xF800 != 0xD800) {
enc = String.fromCharCode(
(c1 >> 12) | 224,
((c1 >> 6) & 63) | 128,
( c1 & 63) | 128
);
} else { // surrogate pairs
if (c1 & 0xFC00 != 0xD800) { throw new RangeError("Unmatched trail surrogate at " + n); }
var c2 = string.charCodeAt(++n);
if (c2 & 0xFC00 != 0xDC00) { throw new RangeError("Unmatched lead surrogate at " + (n-1)); }
c1 = ((c1 & 0x3FF) << 10) + (c2 & 0x3FF) + 0x10000;
enc = String.fromCharCode(
(c1 >> 18) | 240,
((c1 >> 12) & 63) | 128,
((c1 >> 6) & 63) | 128,
( c1 & 63) | 128
);
}
if (enc !== null) {
if (end > start) {
utftext += string.slice(start, end);
}
utftext += enc;
start = end = n + 1;
}
}
if (end > start) {
utftext += string.slice(start, stringl);
}
return utftext;
}
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
*= require jquery.ui.gitlab *= require jquery.ui.gitlab
*= require jquery.atwho *= require jquery.atwho
*= require chosen *= require chosen
*= require select2
*= require_self *= require_self
*/ */
...@@ -14,7 +15,7 @@ ...@@ -14,7 +15,7 @@
@import "gitlab_bootstrap.scss"; @import "gitlab_bootstrap.scss";
@import "common.scss"; @import "common.scss";
@import "ref_select.scss"; @import "selects.scss";
@import "sections/header.scss"; @import "sections/header.scss";
@import "sections/nav.scss"; @import "sections/nav.scss";
......
...@@ -554,3 +554,4 @@ img.emoji { ...@@ -554,3 +554,4 @@ img.emoji {
.appear-data { .appear-data {
display: none; display: none;
} }
.ajax-users-select {
width: 400px;
}
.user-result {
.user-image {
float: left;
}
.user-name {
}
.user-username {
color: #999;
}
}
.select2-no-results {
padding: 7px;
color: #666;
}
/** Branch/tag selector **/ /** Branch/tag selector **/
.project-refs-form { .project-refs-form {
margin: 0; margin: 0;
......
...@@ -152,5 +152,8 @@ class ApplicationController < ActionController::Base ...@@ -152,5 +152,8 @@ class ApplicationController < ActionController::Base
def add_gon_variables def add_gon_variables
gon.default_issues_tracker = Project.issues_tracker.default_value gon.default_issues_tracker = Project.issues_tracker.default_value
gon.api_version = Gitlab::API.version
gon.api_token = current_user.private_token if current_user
gon.gravatar_url = request.ssl? ? Gitlab.config.gravatar.ssl_url : Gitlab.config.gravatar.plain_url
end end
end end
...@@ -16,7 +16,7 @@ class TeamMembersController < ProjectResourceController ...@@ -16,7 +16,7 @@ class TeamMembersController < ProjectResourceController
end end
def create def create
users = User.where(id: params[:user_ids]) users = User.where(id: params[:user_ids].split(','))
@project.team << [users, params[:project_access]] @project.team << [users, params[:project_access]]
......
...@@ -13,7 +13,7 @@ class Teams::MembersController < Teams::ApplicationController ...@@ -13,7 +13,7 @@ class Teams::MembersController < Teams::ApplicationController
def create def create
unless params[:user_ids].blank? unless params[:user_ids].blank?
user_ids = params[:user_ids] user_ids = params[:user_ids].split(',')
access = params[:default_project_access] access = params[:default_project_access]
is_admin = params[:group_admin] is_admin = params[:group_admin]
user_team.add_members(user_ids, access, is_admin) user_team.add_members(user_ids, access, is_admin)
......
...@@ -169,4 +169,10 @@ module ApplicationHelper ...@@ -169,4 +169,10 @@ module ApplicationHelper
end end
alias_method :url_to_image, :image_url alias_method :url_to_image, :image_url
def users_select_tag(id, opts = {})
css_class = "ajax-users-select"
css_class << " multiselect" if opts[:multiple]
hidden_field_tag(id, '', class: css_class)
end
end end
...@@ -69,6 +69,9 @@ class UserTeam < ActiveRecord::Base ...@@ -69,6 +69,9 @@ class UserTeam < ActiveRecord::Base
end end
def add_members(users, access, group_admin) def add_members(users, access, group_admin)
# reject existing users
users.reject! { |id| member_ids.include?(id.to_i) }
users.each do |user| users.each do |user|
add_member(user, access, group_admin) add_member(user, access, group_admin)
end end
......
...@@ -11,7 +11,8 @@ ...@@ -11,7 +11,8 @@
%h6 1. Choose people you want in the team %h6 1. Choose people you want in the team
.clearfix .clearfix
= f.label :user_ids, "People" = f.label :user_ids, "People"
.input= select_tag(:user_ids, options_from_collection_for_select(User.active.not_in_project(@project).alphabetically, :id, :name_with_username), {data: {placeholder: "Select users"}, class: "chosen xxlarge", multiple: true}) .input
= users_select_tag(:user_ids, multiple: true)
%h6 2. Set access level for them %h6 2. Set access level for them
.clearfix .clearfix
......
...@@ -20,7 +20,8 @@ ...@@ -20,7 +20,8 @@
%td= @team.admin?(member) ? "Admin" : "Member" %td= @team.admin?(member) ? "Admin" : "Member"
%td %td
%tr %tr
%td= select_tag :user_ids, options_from_collection_for_select(@users , :id, :name_with_username), multiple: true, data: {placeholder: 'Select users'}, class: 'chosen span5' %td
= users_select_tag(:user_ids, multiple: true)
%td= select_tag :default_project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3" } %td= select_tag :default_project_access, options_for_select(Project.access_options), {class: "project-access-select chosen span3" }
%td %td
%span= check_box_tag :group_admin %span= check_box_tag :group_admin
......
...@@ -11,6 +11,7 @@ Feature: Project Team management ...@@ -11,6 +11,7 @@ Feature: Project Team management
Then I should be able to see myself in team Then I should be able to see myself in team
And I should see "Sam" in team list And I should see "Sam" in team list
@javascript
Scenario: Add user to project Scenario: Add user to project
Given I click link "New Team Member" Given I click link "New Team Member"
And I select "Mike" as "Reporter" And I select "Mike" as "Reporter"
......
...@@ -2,6 +2,7 @@ class ProjectTeamManagement < Spinach::FeatureSteps ...@@ -2,6 +2,7 @@ class ProjectTeamManagement < Spinach::FeatureSteps
include SharedAuthentication include SharedAuthentication
include SharedProject include SharedProject
include SharedPaths include SharedPaths
include Select2Helper
Then 'I should be able to see myself in team' do Then 'I should be able to see myself in team' do
page.should have_content(@user.name) page.should have_content(@user.name)
...@@ -20,8 +21,9 @@ class ProjectTeamManagement < Spinach::FeatureSteps ...@@ -20,8 +21,9 @@ class ProjectTeamManagement < Spinach::FeatureSteps
And 'I select "Mike" as "Reporter"' do And 'I select "Mike" as "Reporter"' do
user = User.find_by_name("Mike") user = User.find_by_name("Mike")
select2(user.id, from: "#user_ids", multiple: true)
within "#new_team_member" do within "#new_team_member" do
select "#{user.name} (#{user.username})", :from => "user_ids"
select "Reporter", :from => "project_access" select "Reporter", :from => "project_access"
end end
click_button "Add users" click_button "Add users"
......
...@@ -2,238 +2,239 @@ class Userteams < Spinach::FeatureSteps ...@@ -2,238 +2,239 @@ class Userteams < Spinach::FeatureSteps
include SharedAuthentication include SharedAuthentication
include SharedPaths include SharedPaths
include SharedProject include SharedProject
include Select2Helper
When 'I do not have teams with me' do When 'I do not have teams with me' do
UserTeam.with_member(current_user).destroy_all UserTeam.with_member(current_user).destroy_all
end end
Then 'I should see dashboard page without teams info block' do Then 'I should see dashboard page without teams info block' do
page.has_no_css?(".teams-box").must_equal true page.has_no_css?(".teams-box").must_equal true
end end
When 'I have teams with my membership' do When 'I have teams with my membership' do
team = create :user_team, owner: current_user team = create :user_team, owner: current_user
team.add_member(current_user, UserTeam.access_roles["Master"], true) team.add_member(current_user, UserTeam.access_roles["Master"], true)
end end
Then 'I should see dashboard page with teams information block' do Then 'I should see dashboard page with teams information block' do
page.should have_css(".teams-box") page.should have_css(".teams-box")
end end
When 'exist user teams' do When 'exist user teams' do
team = create :user_team team = create :user_team
team.add_member(current_user, UserTeam.access_roles["Master"], true) team.add_member(current_user, UserTeam.access_roles["Master"], true)
end end
And 'I click on "All teams" link' do And 'I click on "All teams" link' do
click_link("All Teams") click_link("All Teams")
end end
Then 'I should see "All teams" page' do Then 'I should see "All teams" page' do
current_path.should == teams_path current_path.should == teams_path
end end
And 'I should see exist teams in teams list' do And 'I should see exist teams in teams list' do
team = UserTeam.last team = UserTeam.last
find_in_list(".teams_list tr", team).must_equal true find_in_list(".teams_list tr", team).must_equal true
end end
When 'I click to "New team" link' do When 'I click to "New team" link' do
click_link("New Team") click_link("New Team")
end end
And 'I submit form with new team info' do And 'I submit form with new team info' do
fill_in 'name', with: 'gitlab' fill_in 'name', with: 'gitlab'
fill_in 'user_team_description', with: 'team description' fill_in 'user_team_description', with: 'team description'
click_button 'Create team' click_button 'Create team'
end end
And 'I should see newly created team' do And 'I should see newly created team' do
page.should have_content "gitlab" page.should have_content "gitlab"
page.should have_content "team description" page.should have_content "team description"
end end
Then 'I should be redirected to new team page' do Then 'I should be redirected to new team page' do
team = UserTeam.last team = UserTeam.last
current_path.should == team_path(team) current_path.should == team_path(team)
end end
When 'I have teams with projects and members' do When 'I have teams with projects and members' do
team = create :user_team, owner: current_user team = create :user_team, owner: current_user
@project = create :project @project = create :project
team.add_member(current_user, UserTeam.access_roles["Master"], true) team.add_member(current_user, UserTeam.access_roles["Master"], true)
team.assign_to_project(@project, UserTeam.access_roles["Master"]) team.assign_to_project(@project, UserTeam.access_roles["Master"])
@event = create(:closed_issue_event, project: @project) @event = create(:closed_issue_event, project: @project)
end end
When 'I visit team page' do When 'I visit team page' do
visit team_path(UserTeam.last) visit team_path(UserTeam.last)
end end
Then 'I should see projects list' do Then 'I should see projects list' do
page.should have_css(".projects_box") page.should have_css(".projects_box")
projects_box = find(".projects_box") projects_box = find(".projects_box")
projects_box.should have_content(@project.name) projects_box.should have_content(@project.name)
end end
And 'project from team has issues assigned to me' do And 'project from team has issues assigned to me' do
team = UserTeam.last team = UserTeam.last
team.projects.each do |project| team.projects.each do |project|
project.issues << create(:issue, assignee: current_user) project.issues << create(:issue, assignee: current_user)
end
end end
end
When 'I visit team issues page' do When 'I visit team issues page' do
team = UserTeam.last team = UserTeam.last
visit issues_team_path(team) visit issues_team_path(team)
end end
Then 'I should see issues from this team assigned to me' do Then 'I should see issues from this team assigned to me' do
team = UserTeam.last team = UserTeam.last
team.projects.each do |project| team.projects.each do |project|
project.issues.assigned(current_user).each do |issue| project.issues.assigned(current_user).each do |issue|
page.should have_content issue.title page.should have_content issue.title
end
end end
end end
end
Given 'I have team with projects and members' do Given 'I have team with projects and members' do
team = create :user_team, owner: current_user team = create :user_team, owner: current_user
project = create :project project = create :project
user = create :user user = create :user
team.add_member(current_user, UserTeam.access_roles["Master"], true) team.add_member(current_user, UserTeam.access_roles["Master"], true)
team.add_member(user, UserTeam.access_roles["Developer"], false) team.add_member(user, UserTeam.access_roles["Developer"], false)
team.assign_to_project(project, UserTeam.access_roles["Master"]) team.assign_to_project(project, UserTeam.access_roles["Master"])
end end
Given 'project from team has issues assigned to teams members' do Given 'project from team has issues assigned to teams members' do
team = UserTeam.last team = UserTeam.last
team.projects.each do |project| team.projects.each do |project|
team.members.each do |member| team.members.each do |member|
project.issues << create(:issue, assignee: member) project.issues << create(:issue, assignee: member)
end
end end
end end
end
Then 'I should see issues from this team assigned to teams members' do Then 'I should see issues from this team assigned to teams members' do
team = UserTeam.last team = UserTeam.last
team.projects.each do |project| team.projects.each do |project|
team.members.each do |member| team.members.each do |member|
project.issues.assigned(member).each do |issue| project.issues.assigned(member).each do |issue|
page.should have_content issue.title page.should have_content issue.title
end
end end
end end
end end
end
Given 'project from team has merge requests assigned to me' do Given 'project from team has merge requests assigned to me' do
team = UserTeam.last team = UserTeam.last
team.projects.each do |project| team.projects.each do |project|
team.members.each do |member| team.members.each do |member|
3.times { project.merge_requests << create(:merge_request, assignee: member) } 3.times { project.merge_requests << create(:merge_request, assignee: member) }
end
end end
end end
end
When 'I visit team merge requests page' do When 'I visit team merge requests page' do
team = UserTeam.last team = UserTeam.last
visit merge_requests_team_path(team) visit merge_requests_team_path(team)
end end
Then 'I should see merge requests from this team assigned to me' do Then 'I should see merge requests from this team assigned to me' do
team = UserTeam.last team = UserTeam.last
team.projects.each do |project| team.projects.each do |project|
team.members.each do |member| team.members.each do |member|
project.issues.assigned(member).each do |merge_request| project.issues.assigned(member).each do |merge_request|
page.should have_content merge_request.title page.should have_content merge_request.title
end
end end
end end
end end
end
Given 'project from team has merge requests assigned to team members' do Given 'project from team has merge requests assigned to team members' do
team = UserTeam.last team = UserTeam.last
team.projects.each do |project| team.projects.each do |project|
team.members.each do |member| team.members.each do |member|
3.times { project.merge_requests << create(:merge_request, assignee: member) } 3.times { project.merge_requests << create(:merge_request, assignee: member) }
end
end end
end end
end
Then 'I should see merge requests from this team assigned to me' do Then 'I should see merge requests from this team assigned to me' do
team = UserTeam.last team = UserTeam.last
team.projects.each do |project| team.projects.each do |project|
team.members.each do |member| team.members.each do |member|
project.issues.assigned(member).each do |merge_request| project.issues.assigned(member).each do |merge_request|
page.should have_content merge_request.title page.should have_content merge_request.title
end
end end
end end
end end
end
Given 'I have new user "John"' do Given 'I have new user "John"' do
create :user, name: "John" create :user, name: "John"
end end
When 'I visit team people page' do When 'I visit team people page' do
team = UserTeam.last team = UserTeam.last
visit team_members_path(team) visit team_members_path(team)
end end
And 'I select user "John" from list with role "Reporter"' do And 'I select user "John" from list with role "Reporter"' do
user = User.find_by_name("John") user = User.find_by_name("John")
within "#team_members" do select2(user.id, from: "#user_ids", multiple: true)
select "#{user.name} (#{user.username})", from: "user_ids" within "#team_members" do
select "Reporter", from: "default_project_access" select "Reporter", from: "default_project_access"
end
click_button "Add"
end end
click_button "Add"
end
Then 'I should see user "John" in team list' do Then 'I should see user "John" in team list' do
user = User.find_by_name("John") user = User.find_by_name("John")
team_members_list = find(".team-table") team_members_list = find(".team-table")
team_members_list.should have_content user.name team_members_list.should have_content user.name
end end
And 'I have my own project without teams' do And 'I have my own project without teams' do
@project = create :project, namespace: current_user.namespace @project = create :project, namespace: current_user.namespace
end end
And 'I visit my team page' do And 'I visit my team page' do
team = UserTeam.where(owner_id: current_user.id).last team = UserTeam.where(owner_id: current_user.id).last
visit team_path(team) visit team_path(team)
end end
When 'I click on link "Projects"' do When 'I click on link "Projects"' do
click_link "Projects" click_link "Projects"
end end
And 'I click link "Assign project to Team"' do And 'I click link "Assign project to Team"' do
click_link "Assign project to Team" click_link "Assign project to Team"
end end
Then 'I should see form with my own project in avaliable projects list' do Then 'I should see form with my own project in avaliable projects list' do
projects_select = find("#project_ids") projects_select = find("#project_ids")
projects_select.should have_content(@project.name) projects_select.should have_content(@project.name)
end end
When 'I submit form with selected project and max access' do When 'I submit form with selected project and max access' do
within "#assign_projects" do within "#assign_projects" do
select @project.name_with_namespace, from: "project_ids" select @project.name_with_namespace, from: "project_ids"
select "Reporter", from: "greatest_project_access" select "Reporter", from: "greatest_project_access"
end
click_button "Add"
end end
click_button "Add"
end
Then 'I should see my own project in team projects list' do Then 'I should see my own project in team projects list' do
projects = find(".projects-table") projects = find(".projects-table")
projects.should have_content(@project.name) projects.should have_content(@project.name)
end end
When 'I click link "New Team Member"' do When 'I click link "New Team Member"' do
click_link "New Team Member" click_link "New Team Member"
end end
protected protected
...@@ -257,5 +258,4 @@ class Userteams < Spinach::FeatureSteps ...@@ -257,5 +258,4 @@ class Userteams < Spinach::FeatureSteps
end end
entered entered
end end
end end
...@@ -14,7 +14,7 @@ require 'spinach/capybara' ...@@ -14,7 +14,7 @@ require 'spinach/capybara'
require 'sidekiq/testing/inline' require 'sidekiq/testing/inline'
%w(stubbed_repository valid_commit).each do |f| %w(stubbed_repository valid_commit select2_helper).each do |f|
require Rails.root.join('spec', 'support', f) require Rails.root.join('spec', 'support', f)
end end
......
...@@ -46,6 +46,7 @@ Feature: UserTeams ...@@ -46,6 +46,7 @@ Feature: UserTeams
When I visit team merge requests page When I visit team merge requests page
Then I should see merge requests from this team assigned to me Then I should see merge requests from this team assigned to me
@javascript
Scenario: I should add user to projects in Team Scenario: I should add user to projects in Team
Given I have team with projects and members Given I have team with projects and members
Given I have new user "John" Given I have new user "John"
......
...@@ -9,7 +9,8 @@ module Gitlab ...@@ -9,7 +9,8 @@ module Gitlab
# Example Request: # Example Request:
# GET /users # GET /users
get do get do
@users = paginate User @users = User.scoped
@users = @users.search(params[:search]) if params[:search].present?
present @users, with: Entities::User present @users, with: Entities::User
end end
......
# Select2 ajax programatic helper
# It allows you to select value from select2
#
# Params
# value - real value of selected item
# opts - options containing css selector
#
# Usage:
#
# select2(2, from: '#user_ids')
#
module Select2Helper
def select2(value, options={})
raise "Must pass a hash containing 'from'" if not options.is_a?(Hash) or not options.has_key?(:from)
selector = options[:from]
if options[:multiple]
page.execute_script("$('#{selector}').select2('val', ['#{value}']);")
else
page.execute_script("$('#{selector}').select2('val', '#{value}');")
end
end
end
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册