Commit cc043f32d8bfa7da5e94061806ae56fc11902d71

Authored by Dmitriy Zaporozhets
1 parent a769204f

Admin area improved

Showing 39 changed files with 434 additions and 334 deletions   Show diff stats
app/assets/stylesheets/application.css
@@ -7,5 +7,5 @@ @@ -7,5 +7,5 @@
7 *= require jquery-ui/jquery.tagify 7 *= require jquery-ui/jquery.tagify
8 *= require chosen 8 *= require chosen
9 *= require_self 9 *= require_self
10 - *= require common 10 + *= require main
11 */ 11 */
app/assets/stylesheets/common.scss
1 -@import "bootstrap";  
2 -  
3 -/** GITLAB colors **/  
4 -$text_color:#222;  
5 -$lite_text_color: #666;  
6 -$link_color:#111;  
7 -$active_link_color:#2FA0BB;  
8 -$active_bg_color:#79C3E0;  
9 -$active_bd_color: #2FA0BB;  
10 -$border_color:#CCC;  
11 -$lite_border_color:#EEE;  
12 -$min_app_width:980px;  
13 -$max_app_width:980px;  
14 -$app_padding:20px;  
15 -$bg_color: #FFF;  
16 -$styled_border_color: #2FA0BB;  
17 -$color: "#4BB8D2";  
18 -$blue_link: "#2fa0bb";  
19 -  
20 -/** MIXINS **/  
21 -@mixin round-borders-bottom($radius) {  
22 - border-top: 1px solid #eaeaea;  
23 - -moz-border-radius-bottomright: $radius;  
24 - -moz-border-radius-bottomleft: $radius;  
25 - border-bottom-right-radius: $radius;  
26 - border-bottom-left-radius: $radius;  
27 - -webkit-border-bottom-left-radius: $radius;  
28 - -webkit-border-bottom-right-radius: $radius;  
29 -}  
30 -  
31 -@mixin round-borders-top($radius) {  
32 - border-top: 1px solid #eaeaea;  
33 - -moz-border-radius-topright: $radius;  
34 - -moz-border-radius-topleft: $radius;  
35 - border-top-right-radius: $radius;  
36 - border-top-left-radius: $radius;  
37 - -webkit-border-top-left-radius: $radius;  
38 - -webkit-border-top-right-radius: $radius;  
39 -}  
40 -  
41 -@mixin round-borders-all($radius) {  
42 - border: 1px solid #eaeaea;  
43 - -moz-border-radius: $radius;  
44 - -webkit-border-radius: $radius;  
45 - border-radius: $radius;  
46 -}  
47 -  
48 /** COLORS **/ 1 /** COLORS **/
49 .cgray { color:gray; } 2 .cgray { color:gray; }
50 .cred { color:#D12F19; } 3 .cred { color:#D12F19; }
@@ -173,18 +126,38 @@ img.lil_av { @@ -173,18 +126,38 @@ img.lil_av {
173 .author_link { 126 .author_link {
174 color: $active_link_color; 127 color: $active_link_color;
175 } 128 }
  129 +.entry {
  130 + position: relative;
  131 + padding: 7px 15px;
  132 + margin-bottom: 18px;
  133 + color: #404040;
  134 + filter:none;
  135 +
  136 + text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
  137 + text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
  138 +
  139 + -webkit-border-radius: 4px;
  140 + -moz-border-radius: 4px;
  141 + border-radius: 4px;
176 142
177 -@import "reset_bootstrap.scss";  
178 -@import "top_panel.scss";  
179 -@import "projects.css.scss";  
180 -@import "commits.css.scss";  
181 -@import "tree.scss";  
182 -@import "issues.css.scss";  
183 -@import "merge_requests.css.scss";  
184 -@import "notes.css.scss";  
185 -@import "login.scss"; 143 + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
  144 + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
  145 + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);
186 146
187 -/** CODE HIGHTLIGHT **/  
188 -@import "highlight.css.scss";  
189 -@import "highlight.black.css.scss"; 147 + background:#F1F1F1;
  148 + border: 1px solid #ccc;
  149 +
  150 + p {
  151 + margin-bottom: 0;
  152 + img {
  153 + position:relative;
  154 + top:3px;
  155 + }
  156 + }
  157 +}
  158 +
  159 +.widget {
  160 + padding:20px;
  161 + margin-bottom:20px;
  162 +}
190 163
app/assets/stylesheets/issues.css.scss
@@ -1,3 +0,0 @@ @@ -1,3 +0,0 @@
1 -#issue_assignee_id {  
2 - width:300px;  
3 -}  
app/assets/stylesheets/main.scss 0 → 100644
@@ -0,0 +1,64 @@ @@ -0,0 +1,64 @@
  1 +@import "bootstrap";
  2 +
  3 +/** GITLAB colors **/
  4 +$text_color:#222;
  5 +$lite_text_color: #666;
  6 +$link_color:#111;
  7 +$active_link_color:#2FA0BB;
  8 +$active_bg_color:#79C3E0;
  9 +$active_bd_color: #2FA0BB;
  10 +$border_color:#CCC;
  11 +$lite_border_color:#EEE;
  12 +$min_app_width:980px;
  13 +$max_app_width:980px;
  14 +$app_padding:20px;
  15 +$bg_color: #FFF;
  16 +$styled_border_color: #2FA0BB;
  17 +$color: "#4BB8D2";
  18 +$blue_link: "#2fa0bb";
  19 +
  20 +/** MIXINS **/
  21 +@mixin round-borders-bottom($radius) {
  22 + border-top: 1px solid #eaeaea;
  23 + -moz-border-radius-bottomright: $radius;
  24 + -moz-border-radius-bottomleft: $radius;
  25 + border-bottom-right-radius: $radius;
  26 + border-bottom-left-radius: $radius;
  27 + -webkit-border-bottom-left-radius: $radius;
  28 + -webkit-border-bottom-right-radius: $radius;
  29 +}
  30 +
  31 +@mixin round-borders-top($radius) {
  32 + border-top: 1px solid #eaeaea;
  33 + -moz-border-radius-topright: $radius;
  34 + -moz-border-radius-topleft: $radius;
  35 + border-top-right-radius: $radius;
  36 + border-top-left-radius: $radius;
  37 + -webkit-border-top-left-radius: $radius;
  38 + -webkit-border-top-right-radius: $radius;
  39 +}
  40 +
  41 +@mixin round-borders-all($radius) {
  42 + border: 1px solid #eaeaea;
  43 + -moz-border-radius: $radius;
  44 + -webkit-border-radius: $radius;
  45 + border-radius: $radius;
  46 +}
  47 +
  48 +
  49 +@import "reset_bootstrap.scss";
  50 +@import "common.scss";
  51 +@import "top_panel.scss";
  52 +
  53 +@import "projects.css.scss";
  54 +@import "commits.css.scss";
  55 +@import "tree.scss";
  56 +@import "merge_requests.css.scss";
  57 +@import "notes.css.scss";
  58 +@import "login.scss";
  59 +
  60 +/** CODE HIGHTLIGHT **/
  61 +@import "highlight.css.scss";
  62 +@import "highlight.black.css.scss";
  63 +
  64 +
app/assets/stylesheets/projects.css.scss
@@ -201,3 +201,7 @@ input.git_clone_url { @@ -201,3 +201,7 @@ input.git_clone_url {
201 width:60px; 201 width:60px;
202 } 202 }
203 } 203 }
  204 +
  205 +#issue_assignee_id {
  206 + width:300px;
  207 +}
app/assets/stylesheets/reset_bootstrap.scss
@@ -5,38 +5,3 @@ a { @@ -5,38 +5,3 @@ a {
5 color: $active_link_color; 5 color: $active_link_color;
6 } 6 }
7 } 7 }
8 -  
9 -.entry {  
10 - position: relative;  
11 - padding: 7px 15px;  
12 - margin-bottom: 18px;  
13 - color: #404040;  
14 - filter:none;  
15 -  
16 - text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);  
17 - text-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);  
18 -  
19 - -webkit-border-radius: 4px;  
20 - -moz-border-radius: 4px;  
21 - border-radius: 4px;  
22 -  
23 - -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);  
24 - -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);  
25 - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.25);  
26 -  
27 - background:#F1F1F1;  
28 - border: 1px solid #ccc;  
29 -  
30 - p {  
31 - margin-bottom: 0;  
32 - img {  
33 - position:relative;  
34 - top:3px;  
35 - }  
36 - }  
37 -}  
38 -  
39 -.widget {  
40 - padding:20px;  
41 - margin-bottom:20px;  
42 -}  
app/assets/stylesheets/top_panel.scss
@@ -11,6 +11,7 @@ body header { @@ -11,6 +11,7 @@ body header {
11 -moz-box-shadow: 0 -1px 0 white inset; 11 -moz-box-shadow: 0 -1px 0 white inset;
12 -webkit-box-shadow: 0 -1px 0 white inset; 12 -webkit-box-shadow: 0 -1px 0 white inset;
13 13
  14 + z-index:10;
14 height:60px; 15 height:60px;
15 16
16 .wrapper { 17 .wrapper {
app/controllers/admin/team_members_controller.rb
@@ -3,39 +3,15 @@ class Admin::TeamMembersController < ApplicationController @@ -3,39 +3,15 @@ class Admin::TeamMembersController < ApplicationController
3 before_filter :authenticate_user! 3 before_filter :authenticate_user!
4 before_filter :authenticate_admin! 4 before_filter :authenticate_admin!
5 5
6 - def index  
7 - @admin_team_members = UsersProject.page(params[:page]).per(100).order("project_id DESC")  
8 - end  
9 -  
10 - def show  
11 - @admin_team_member = UsersProject.find(params[:id])  
12 - end  
13 -  
14 - def new  
15 - @admin_team_member = UsersProject.new(params[:team_member])  
16 - end  
17 -  
18 def edit 6 def edit
19 @admin_team_member = UsersProject.find(params[:id]) 7 @admin_team_member = UsersProject.find(params[:id])
20 end 8 end
21 9
22 - def create  
23 - @admin_team_member = UsersProject.new(params[:team_member])  
24 - @admin_team_member.project_id = params[:team_member][:project_id]  
25 -  
26 - if @admin_team_member.save  
27 - redirect_to admin_team_member_path(@admin_team_member), notice: 'UsersProject was successfully created.'  
28 - else  
29 - render action: "new"  
30 - end  
31 - end  
32 -  
33 def update 10 def update
34 @admin_team_member = UsersProject.find(params[:id]) 11 @admin_team_member = UsersProject.find(params[:id])
35 - @admin_team_member.project_id = params[:team_member][:project_id]  
36 12
37 if @admin_team_member.update_attributes(params[:team_member]) 13 if @admin_team_member.update_attributes(params[:team_member])
38 - redirect_to admin_team_member_path(@admin_team_member), notice: 'UsersProject was successfully updated.' 14 + redirect_to [:admin, @admin_team_member.project], notice: 'Project Access was successfully updated.'
39 else 15 else
40 render action: "edit" 16 render action: "edit"
41 end 17 end
@@ -45,6 +21,6 @@ class Admin::TeamMembersController < ApplicationController @@ -45,6 +21,6 @@ class Admin::TeamMembersController < ApplicationController
45 @admin_team_member = UsersProject.find(params[:id]) 21 @admin_team_member = UsersProject.find(params[:id])
46 @admin_team_member.destroy 22 @admin_team_member.destroy
47 23
48 - redirect_to admin_team_members_url 24 + redirect_to :back
49 end 25 end
50 end 26 end
app/controllers/admin/users_controller.rb
@@ -9,8 +9,28 @@ class Admin::UsersController < ApplicationController @@ -9,8 +9,28 @@ class Admin::UsersController < ApplicationController
9 9
10 def show 10 def show
11 @admin_user = User.find(params[:id]) 11 @admin_user = User.find(params[:id])
  12 +
  13 + @projects = if @admin_user.projects.empty?
  14 + Project
  15 + else
  16 + Project.without_user(@admin_user)
  17 + end.all
12 end 18 end
13 19
  20 + def team_update
  21 + @admin_user = User.find(params[:id])
  22 +
  23 + UsersProject.user_bulk_import(
  24 + @admin_user,
  25 + params[:project_ids],
  26 + params[:project_access],
  27 + params[:repo_access]
  28 + )
  29 +
  30 + redirect_to [:admin, @admin_user], notice: 'Teams were successfully updated.'
  31 + end
  32 +
  33 +
14 def new 34 def new
15 @admin_user = User.new(:projects_limit => 10) 35 @admin_user = User.new(:projects_limit => 10)
16 end 36 end
app/models/project.rb
@@ -53,6 +53,7 @@ class Project < ActiveRecord::Base @@ -53,6 +53,7 @@ class Project < ActiveRecord::Base
53 attr_protected :private_flag, :owner_id 53 attr_protected :private_flag, :owner_id
54 54
55 scope :public_only, where(:private_flag => false) 55 scope :public_only, where(:private_flag => false)
  56 + scope :without_user, lambda { |user| where("id not in (:ids)", :ids => user.projects.map(&:id) ) }
56 57
57 def self.active 58 def self.active
58 joins(:issues, :notes, :merge_requests).order("issues.created_at, notes.created_at, merge_requests.created_at DESC") 59 joins(:issues, :notes, :merge_requests).order("issues.created_at, notes.created_at, merge_requests.created_at DESC")
app/models/users_project.rb
@@ -27,6 +27,20 @@ class UsersProject < ActiveRecord::Base @@ -27,6 +27,20 @@ class UsersProject < ActiveRecord::Base
27 end 27 end
28 end 28 end
29 29
  30 + def self.user_bulk_import(user, project_ids, project_access, repo_access)
  31 + UsersProject.transaction do
  32 + project_ids.each do |project_id|
  33 + users_project = UsersProject.new(
  34 + :repo_access => repo_access,
  35 + :project_access => project_access,
  36 + )
  37 + users_project.project_id = project_id
  38 + users_project.user_id = user.id
  39 + users_project.save
  40 + end
  41 + end
  42 + end
  43 +
30 def update_repository 44 def update_repository
31 Gitlabhq::GitHost.system.new.configure do |c| 45 Gitlabhq::GitHost.system.new.configure do |c|
32 c.update_project(project.path, project) 46 c.update_project(project.path, project)
app/views/admin/projects/_form.html.haml
1 = form_for [:admin, @admin_project] do |f| 1 = form_for [:admin, @admin_project] do |f|
2 -if @admin_project.errors.any? 2 -if @admin_project.errors.any?
3 - #error_explanation  
4 - %h2= "#{pluralize(@admin_project.errors.count, "error")} prohibited this admin_project from being saved:" 3 + .alert-message.block-message.error
5 %ul 4 %ul
6 - @admin_project.errors.full_messages.each do |msg| 5 - @admin_project.errors.full_messages.each do |msg|
7 %li= msg 6 %li= msg
@@ -10,27 +9,58 @@ @@ -10,27 +9,58 @@
10 = f.label :name 9 = f.label :name
11 .input= f.text_field :name 10 .input= f.text_field :name
12 .clearfix 11 .clearfix
13 - = f.label :code  
14 - .input= f.text_field :code 12 + = f.label :path do
  13 + Path
  14 + .input
  15 + .input-prepend
  16 + %span.add-on= "git@#{GIT_HOST["host"]}:"
  17 + = f.text_field :path, :placeholder => "example_project", :disabled => !@admin_project.new_record?
15 .clearfix 18 .clearfix
16 - = f.label :path  
17 - .input= f.text_field :path 19 + = f.label :code do
  20 + Code
  21 + .input
  22 + .input-prepend
  23 + %span.add-on= "http://#{GIT_HOST["host"]}/"
  24 + = f.text_field :code, :placeholder => "example"
18 25
19 - unless @admin_project.new_record? 26 - unless @admin_project.new_record?
20 .clearfix 27 .clearfix
21 = f.label :owner_id 28 = f.label :owner_id
22 .input= f.select :owner_id, User.all.map { |user| [user.name, user.id] } 29 .input= f.select :owner_id, User.all.map { |user| [user.name, user.id] }
23 30
  31 + - unless @admin_project.heads.empty?
  32 + .clearfix
  33 + = f.label :default_branch, "Default Branch"
  34 + .input= f.select(:default_branch, @admin_project.heads.map(&:name), {}, :style => "width:210px;")
  35 +
  36 + .well
  37 + %h5 Features
  38 +
  39 + .clearfix
  40 + = f.label :issues_enabled, "Issues"
  41 + .input= f.check_box :issues_enabled
  42 +
  43 + .clearfix
  44 + = f.label :merge_requests_enabled, "Merge Requests"
  45 + .input= f.check_box :merge_requests_enabled
  46 +
  47 + .clearfix
  48 + = f.label :wall_enabled, "Wall"
  49 + .input= f.check_box :wall_enabled
  50 +
24 .clearfix 51 .clearfix
25 = f.label :description 52 = f.label :description
26 - .input= f.text_area :description 53 + .input= f.text_area :description, :class => "xxlarge"
27 .clear 54 .clear
28 %br 55 %br
29 .actions 56 .actions
30 - = f.submit 'Save', :class => "btn" 57 + = f.submit 'Save', :class => "btn primary"
  58 + = link_to 'Cancel', [:admin, @admin_project], :class => "btn"
  59 + = link_to 'Destroy', [:admin, @admin_project], :confirm => 'Are you sure?', :method => :delete, :class => "btn danger right"
31 60
32 :javascript 61 :javascript
33 $(function(){ 62 $(function(){
34 taggifyForm(); 63 taggifyForm();
35 $('#project_owner_id').chosen(); 64 $('#project_owner_id').chosen();
  65 + $('#project_default_branch').chosen();
36 }) 66 })
app/views/admin/projects/edit.html.haml
1 -%h2= @admin_project.name 1 +%h3= @admin_project.name
  2 +%hr
2 = render 'form' 3 = render 'form'
3 -  
4 -%br  
5 -= link_to 'Back', admin_projects_path, :class => ""  
6 -|  
7 -= link_to 'Show', [:admin, @admin_project], :class => ""  
app/views/admin/projects/index.html.haml
1 -%table 1 +%h3
  2 + Projects
  3 + = link_to 'New Project', new_admin_project_path, :class => "btn small right"
  4 +%hr
  5 +%table.zebra-striped
2 %thead 6 %thead
3 %th Name 7 %th Name
4 - %th Code  
5 %th Path 8 %th Path
6 %th Team Members 9 %th Team Members
7 %th Last Commit 10 %th Last Commit
@@ -11,12 +14,9 @@ @@ -11,12 +14,9 @@
11 - @admin_projects.each do |project| 14 - @admin_projects.each do |project|
12 %tr 15 %tr
13 %td= link_to project.name, [:admin, project] 16 %td= link_to project.name, [:admin, project]
14 - %td= project.code  
15 %td= project.path 17 %td= project.path
16 %td= project.users_projects.count 18 %td= project.users_projects.count
17 %td= last_commit(project) 19 %td= last_commit(project)
18 - %td= link_to 'Edit', edit_admin_project_path(project), :id => "edit_#{dom_id(project)}"  
19 - %td= link_to 'Destroy', [:admin, project], :confirm => 'Are you sure?', :method => :delete  
20 - 20 + %td= link_to 'Edit', edit_admin_project_path(project), :id => "edit_#{dom_id(project)}", :class => "btn small"
  21 + %td= link_to 'Destroy', [:admin, project], :confirm => 'Are you sure?', :method => :delete, :class => "btn small danger"
21 = paginate @admin_projects 22 = paginate @admin_projects
22 -= link_to 'New Project', new_admin_project_path, :class => "btn"  
app/views/admin/projects/show.html.haml
1 -- unless notice.nil?  
2 - %p#notice= notice 1 +%h3
  2 + = @admin_project.name
  3 + = link_to 'Edit', edit_admin_project_path(@admin_project), :class => "btn right small"
3 4
  5 +%hr
4 6
5 -%h2= @admin_project.name  
6 -  
7 -%table.round-borders 7 +%table.zebra-striped
8 %tr 8 %tr
9 %td 9 %td
10 %b 10 %b
@@ -29,14 +29,33 @@ @@ -29,14 +29,33 @@
29 Description: 29 Description:
30 %td 30 %td
31 = @admin_project.description 31 = @admin_project.description
32 - %tr  
33 - %td{:colspan => 2}  
34 - = link_to 'Edit', edit_admin_project_path(@admin_project), :class => "btn"  
35 32
36 33
37 .span-14 34 .span-14
38 35
39 - %h2 Team 36 + %h3
  37 + Team
  38 + %small
  39 + ( #{@admin_project.users_projects.count} )
  40 +
  41 + %hr
  42 +
  43 + %table.zebra-striped
  44 + %thead
  45 + %tr
  46 + %th Name
  47 + %th Project Access
  48 + %th Repository Access
  49 + %th
  50 +
  51 + - @admin_project.users_projects.each do |tm|
  52 + %tr
  53 + %td
  54 + = link_to tm.user_name, admin_users_path(tm.user)
  55 + %td= select_tag :tm_project_access, options_for_select(Project.access_options, tm.project_access), :class => "medium project-access-select", :disabled => :disabled
  56 + %td= select_tag :tm_repo_access, options_for_select(Repository.access_options, tm.repo_access), :class => "medium repo-access-select", :disabled => :disabled
  57 + %td= link_to 'Edit Access', edit_admin_team_member_path(tm), :class => "btn small"
  58 + %td= link_to 'Remove from team', admin_team_member_path(tm), :confirm => 'Are you sure?', :method => :delete, :class => "btn danger small"
40 59
41 = form_tag team_update_admin_project_path(@admin_project), :class => "bulk_import", :method => :put do 60 = form_tag team_update_admin_project_path(@admin_project), :class => "bulk_import", :method => :put do
42 %table 61 %table
@@ -51,27 +70,8 @@ @@ -51,27 +70,8 @@
51 %td= select_tag :project_access, options_for_select(Project.access_options), :class => "project-access-select" 70 %td= select_tag :project_access, options_for_select(Project.access_options), :class => "project-access-select"
52 %td= select_tag :repo_access, options_for_select(Repository.access_options), :class => "repo-access-select" 71 %td= select_tag :repo_access, options_for_select(Repository.access_options), :class => "repo-access-select"
53 72
54 - %tr  
55 - %td{ :colspan => 3 }  
56 - = submit_tag 'Add', :class => "btn primary"  
57 -  
58 - %table.round-borders  
59 - %thead  
60 - %tr  
61 - %th Name  
62 - %th Added  
63 - %th Project Access  
64 - %th Repository Access  
65 - %th  
66 -  
67 - - @admin_project.users_projects.each do |tm|  
68 - %tr  
69 - %td  
70 - = link_to tm.user_name, admin_team_member_path(tm)  
71 - %td= time_ago_in_words(tm.updated_at) + " ago"  
72 - %td= select_tag :tm_project_access, options_for_select(Project.access_options, tm.project_access), :class => "project-access-select", :disabled => :disabled  
73 - %td= select_tag :tm_repo_access, options_for_select(Repository.access_options, tm.repo_access), :class => "repo-access-select", :disabled => :disabled  
74 - %td= link_to 'Destroy', admin_team_member_path(tm), :confirm => 'Are you sure?', :method => :delete 73 + .actions
  74 + = submit_tag 'Add', :class => "btn primary"
75 75
76 :css 76 :css
77 form select { 77 form select {
app/views/admin/team_members/_form.html.haml
1 -= form_for @admin_team_member, :as => :team_member, :url => @admin_team_member.new_record? ? admin_team_members_path(@admin_team_member) : admin_team_member_path(@admin_team_member) do |f| 1 += form_for @admin_team_member, :as => :team_member, :url => admin_team_member_path(@admin_team_member) do |f|
2 -if @admin_team_member.errors.any? 2 -if @admin_team_member.errors.any?
3 - #error_explanation  
4 - %h2= "#{pluralize(@admin_team_member.errors.count, "error")} prohibited this admin_project from being saved:" 3 + .alert-message.block-message.error
5 %ul 4 %ul
6 - @admin_team_member.errors.full_messages.each do |msg| 5 - @admin_team_member.errors.full_messages.each do |msg|
7 %li= msg 6 %li= msg
8 7
9 - - if @admin_team_member.new_record?  
10 - .span-6  
11 - = f.label :user_id  
12 - .span-6  
13 - = f.select :user_id, User.all.map { |user| [user.name, user.id] }  
14 - .span-6  
15 - = f.label :project_id  
16 - .span-6  
17 - = f.select :project_id, Project.all.map { |user| [user.name, user.id] } 8 + .clearfix
  9 + %label Project Access:
  10 + .input
  11 + = f.select :project_access, options_for_select(Project.access_options, @admin_team_member.project_access), {}, :class => "project-access-select"
18 12
19 - .span-6  
20 - %b Project Access:  
21 - .span-6  
22 - = f.select :project_access, options_for_select(Project.access_options, @admin_team_member.project_access), {}, :class => "project-access-select"  
23 -  
24 - .span-6  
25 - %b Repository Access:  
26 - .span-6  
27 - = f.select :repo_access, options_for_select(Repository.access_options, @admin_team_member.repo_access), {}, :class => "repo-access-select" 13 + .clearfix
  14 + %label Repository Access:
  15 + .input
  16 + = f.select :repo_access, options_for_select(Repository.access_options, @admin_team_member.repo_access), {}, :class => "repo-access-select"
28 %br 17 %br
29 .actions 18 .actions
30 - = f.submit 'Save', :class => "btn" 19 + = f.submit 'Save', :class => "btn primary"
  20 + = link_to 'Cancel', :back, :class => "btn"
31 21
32 :css 22 :css
33 form select { 23 form select {
app/views/admin/team_members/edit.html.haml
1 -= render 'form' 1 +%h3
  2 + Edit access
  3 + %small
  4 + = @admin_team_member.project.name
  5 + –
  6 + = @admin_team_member.user_name
2 7
3 -%br  
4 -= link_to 'Show', admin_team_member_path(@admin_team_member)  
5 -\|  
6 -= link_to 'Back', admin_team_members_path 8 +%hr
  9 +%table.zebra-striped
  10 + %tr
  11 + %td User:
  12 + %td= @admin_team_member.user_name
  13 + %tr
  14 + %td Project:
  15 + %td= @admin_team_member.project.name
  16 + %tr
  17 + %td Since:
  18 + %td= @admin_team_member.updated_at.stamp("Nov 11, 2010")
  19 += render 'form'
app/views/admin/team_members/index.html.haml
@@ -1,28 +0,0 @@ @@ -1,28 +0,0 @@
1 -- @admin_team_members.group_by(&:project).sort.each do |project, members|  
2 - %h3= link_to project.name, [:admin, project]  
3 - %table  
4 - %thead  
5 - %th Name  
6 - %th Project Access  
7 - %th Repo Access  
8 - %th Added  
9 - %th  
10 - %th  
11 - - members.each do |tm|  
12 - - user = tm.user  
13 - %tr  
14 - %td.span-6  
15 - = link_to tm.user_name, admin_team_member_path(tm)  
16 - %br  
17 - %br  
18 - = tm.user_email  
19 - %td.span-3= select_tag :project_access, options_for_select(Project.access_options, tm.project_access), :class => "project-access-select", :disabled => :disabled  
20 - %td.span-3= select_tag :repo_access, options_for_select(Repository.access_options, tm.repo_access), :class => "repo-access-select", :disabled => :disabled  
21 - %td.span-3= time_ago_in_words(tm.updated_at) + " ago"  
22 - %td= link_to 'Edit', edit_admin_team_member_path(tm), :id => "edit_#{dom_id(tm)}"  
23 - %td= link_to 'Destroy', admin_team_member_path(tm), :confirm => 'Are you sure?', :method => :delete  
24 -  
25 -%br  
26 -  
27 -= paginate @admin_team_members  
28 -= link_to 'New Team Member', new_admin_team_member_path, :class => "btn"  
app/views/admin/team_members/new.html.haml
@@ -1,6 +0,0 @@ @@ -1,6 +0,0 @@
1 -%h1 New team member  
2 -  
3 -= render 'form'  
4 -  
5 -%br  
6 -= link_to 'Back', admin_team_members_path  
app/views/admin/team_members/show.html.haml
@@ -1,26 +0,0 @@ @@ -1,26 +0,0 @@
1 -#infoblock  
2 - %p  
3 - %b Name:  
4 - = @admin_team_member.user_name  
5 - %p  
6 - %b Project:  
7 - = @admin_team_member.project.name  
8 - %p  
9 - %b Since:  
10 - = @admin_team_member.updated_at.stamp("Nov 11, 2010")  
11 -  
12 -#infoblock  
13 - .span-6  
14 - %b Project Access:  
15 - = select_tag :project_access, options_for_select(Project.access_options, @admin_team_member.project_access), :class => "project-access-select", :disabled => true  
16 -  
17 - %br  
18 - .span-6  
19 - %b Repository Access:  
20 - = select_tag :repo_access, options_for_select(Repository.access_options, @admin_team_member.repo_access), :class => "repo-access-select", :disabled => true  
21 -  
22 -%br  
23 -  
24 -= link_to 'Edit', edit_admin_team_member_path(@admin_project)  
25 -\|  
26 -= link_to 'Back', admin_team_members_path  
app/views/admin/users/_form.html.haml
@@ -18,9 +18,6 @@ @@ -18,9 +18,6 @@
18 .clearfix 18 .clearfix
19 = f.label :password_confirmation 19 = f.label :password_confirmation
20 .input= f.password_field :password_confirmation 20 .input= f.password_field :password_confirmation
21 - .clearfix  
22 - = f.check_box :admin  
23 - = f.label :admin  
24 21
25 .clearfix 22 .clearfix
26 = f.label :projects_limit 23 = f.label :projects_limit
@@ -35,8 +32,13 @@ @@ -35,8 +32,13 @@
35 .clearfix 32 .clearfix
36 = f.label :twitter 33 = f.label :twitter
37 .input= f.text_field :twitter 34 .input= f.text_field :twitter
38 - .clear  
39 - %br 35 + .clearfix
  36 + = f.label :admin do
  37 + = f.check_box :admin
  38 + %span Administrator
40 .actions 39 .actions
41 = f.submit 'Save', :class => "btn primary" 40 = f.submit 'Save', :class => "btn primary"
42 - = link_to 'Cancel', admin_users_path, :class => "btn" 41 + - if @admin_user.new_record?
  42 + = link_to 'Cancel', admin_users_path, :class => "btn"
  43 + - else
  44 + = link_to 'Cancel', admin_user_path(@admin_user), :class => "btn"
app/views/admin/users/edit.html.haml
  1 +%h3= @admin_user.name
  2 +%hr
1 = render 'form' 3 = render 'form'
2 -  
3 -%br  
4 -= link_to 'Back', admin_users_path, :class => ""  
5 -|  
6 -= link_to 'Show', [:admin, @admin_user], :class => ""  
app/views/admin/users/index.html.haml
1 -%table 1 +%h3
  2 + Users
  3 + = link_to 'New User', new_admin_user_path, :class => "btn small right"
  4 +%hr
  5 +%table.zebra-striped
2 %thead 6 %thead
3 %th Admin 7 %th Admin
4 %th Name 8 %th Name
@@ -13,9 +17,7 @@ @@ -13,9 +17,7 @@
13 %td= link_to user.name, [:admin, user] 17 %td= link_to user.name, [:admin, user]
14 %td= user.email 18 %td= user.email
15 %td= user.users_projects.count 19 %td= user.users_projects.count
16 - %td= link_to 'Edit', edit_admin_user_path(user), :id => "edit_#{dom_id(user)}"  
17 - %td= link_to 'Destroy', [:admin, user], :confirm => 'Are you sure?', :method => :delete 20 + %td= link_to 'Edit', edit_admin_user_path(user), :id => "edit_#{dom_id(user)}", :class => "btn small"
  21 + %td= link_to 'Destroy', [:admin, user], :confirm => 'Are you sure?', :method => :delete, :class => "btn small danger"
18 22
19 = paginate @admin_users 23 = paginate @admin_users
20 -%br  
21 -= link_to 'New User', new_admin_user_path, :class => "btn"  
app/views/admin/users/show.html.haml
1 -%h2= @admin_user.name 1 +%h3
  2 + = @admin_user.name
  3 + = link_to 'Edit', edit_admin_user_path(@admin_user), :class => "btn small right"
2 4
3 -%table.round-borders 5 +%hr
  6 +
  7 +%table.zebra-striped
4 %tr 8 %tr
5 %td 9 %td
6 %b 10 %b
@@ -39,31 +43,57 @@ @@ -39,31 +43,57 @@
39 Twitter: 43 Twitter:
40 %td 44 %td
41 = @admin_user.twitter 45 = @admin_user.twitter
42 - %tr  
43 - %td{:colspan => 2}  
44 - = link_to 'Edit', edit_admin_user_path(@admin_user), :class => "btn"  
45 46
46 -.span-14  
47 - %h2 Projects 47 +%h3 Projects
  48 +%hr
  49 +
  50 +%table.zebra-striped
  51 + %tr
  52 + %thead
  53 + %th Name
  54 + %th Project Access
  55 + %th Repository Access
  56 + %th
  57 + %th
48 58
49 - %table.round-borders 59 + - @admin_user.users_projects.each do |tm|
  60 + - project = tm.project
50 %tr 61 %tr
51 - %thead  
52 - %th Name  
53 - %th Added  
54 - %th Project Access  
55 - %th Repository Access  
56 - %th  
57 - %th 62 + %td= link_to project.name, admin_project_path(project)
  63 + %td= select_tag :tm_project_access, options_for_select(Project.access_options, tm.project_access), :class => "medium project-access-select", :disabled => :disabled
  64 + %td= select_tag :tm_repo_access, options_for_select(Repository.access_options, tm.repo_access), :class => "medium repo-access-select", :disabled => :disabled
  65 + %td= link_to 'Edit Access', edit_admin_team_member_path(tm), :class => "btn small"
  66 + %td= link_to 'Remove from team', admin_team_member_path(tm), :confirm => 'Are you sure?', :method => :delete, :class => "btn small danger"
58 67
59 - - @admin_user.users_projects.each do |tm|  
60 - - project = tm.project 68 += form_tag team_update_admin_user_path(@admin_user), :class => "bulk_import", :method => :put do
  69 + %table
  70 + %thead
61 %tr 71 %tr
62 - %td= link_to project.name, admin_project_path(project)  
63 - %td= time_ago_in_words(tm.updated_at) + " ago"  
64 - %td= select_tag :project_access, options_for_select(Project.access_options, tm.project_access), :class => "project-access-select", :disabled => :disabled  
65 - %td= select_tag :repo_access, options_for_select(Repository.access_options, tm.repo_access), :class => "repo-access-select", :disabled => :disabled  
66 - %td= link_to 'Edit', edit_admin_team_member_path(tm)  
67 - %td= link_to 'Cancel', admin_team_member_path(tm), :confirm => 'Are you sure?', :method => :delete 72 + %th Projects
  73 + %th Project Access:
  74 + %th Repo Access:
  75 +
  76 + %tr
  77 + %td= select_tag :project_ids, options_from_collection_for_select(@projects , :id, :name), :multiple => true
  78 + %td= select_tag :project_access, options_for_select(Project.access_options), :class => "project-access-select"
  79 + %td= select_tag :repo_access, options_for_select(Repository.access_options), :class => "repo-access-select"
  80 +
  81 + .actions
  82 + = submit_tag 'Add', :class => "btn primary"
  83 +
  84 +
  85 +:css
  86 + form select {
  87 + width:150px;
  88 + }
  89 +
  90 + #project_ids {
  91 + width:300px;
  92 + }
  93 +
  94 +
  95 +:javascript
  96 + $('select#project_ids').chosen();
  97 + $('select#repo_access').chosen();
  98 + $('select#project_access').chosen();
68 99
69 - = link_to 'Add To Another Project', new_admin_team_member_path(:team_member => {:user_id => @admin_user.id}), :class => "btn"  
app/views/kaminari/_first_page.html.haml 0 → 100644
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +-# Link to the "First" page
  2 +-# available local variables
  3 +-# url: url to the first page
  4 +-# current_page: a page object for the currently displayed page
  5 +-# num_pages: total number of pages
  6 +-# per_page: number of items to fetch per page
  7 +-# remote: data-remote
  8 +%span.first
  9 + = link_to_unless current_page.first?, raw(t 'views.pagination.first'), url, :remote => remote
app/views/kaminari/_gap.html.haml 0 → 100644
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
  1 +-# Non-link tag that stands for skipped pages...
  2 +-# available local variables
  3 +-# current_page: a page object for the currently displayed page
  4 +-# num_pages: total number of pages
  5 +-# per_page: number of items to fetch per page
  6 +-# remote: data-remote
  7 +%span.page.gap
  8 + = raw(t 'views.pagination.truncate')
app/views/kaminari/_last_page.html.haml 0 → 100644
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +-# Link to the "Last" page
  2 +-# available local variables
  3 +-# url: url to the last page
  4 +-# current_page: a page object for the currently displayed page
  5 +-# num_pages: total number of pages
  6 +-# per_page: number of items to fetch per page
  7 +-# remote: data-remote
  8 +%span.last
  9 + = link_to_unless current_page.last?, raw(t 'views.pagination.last'), url, {:remote => remote}
app/views/kaminari/_next_page.html.haml 0 → 100644
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +-# Link to the "Next" page
  2 +-# available local variables
  3 +-# url: url to the next page
  4 +-# current_page: a page object for the currently displayed page
  5 +-# num_pages: total number of pages
  6 +-# per_page: number of items to fetch per page
  7 +-# remote: data-remote
  8 +%li.next
  9 + = link_to_unless current_page.last?, raw(t 'views.pagination.next'), url, :rel => 'next', :remote => remote
app/views/kaminari/_page.html.haml 0 → 100644
@@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
  1 +-# Link showing page number
  2 +-# available local variables
  3 +-# page: a page object for "this" page
  4 +-# url: url to this page
  5 +-# current_page: a page object for the currently displayed page
  6 +-# num_pages: total number of pages
  7 +-# per_page: number of items to fetch per page
  8 +-# remote: data-remote
  9 +%li{:class => "page#{' active' if page.current?}"}
  10 + = link_to page, url, {:remote => remote, :rel => page.next? ? 'next' : page.prev? ? 'prev' : nil}
app/views/kaminari/_paginator.html.haml 0 → 100644
@@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
  1 +-# The container tag
  2 +-# available local variables
  3 +-# current_page: a page object for the currently displayed page
  4 +-# num_pages: total number of pages
  5 +-# per_page: number of items to fetch per page
  6 +-# remote: data-remote
  7 +-# paginator: the paginator that renders the pagination tags inside
  8 += paginator.render do
  9 + %div.pagination
  10 + %ul
  11 + = prev_page_tag unless current_page.first?
  12 + - each_page do |page|
  13 + - if page.left_outer? || page.right_outer? || page.inside_window?
  14 + = page_tag page
  15 + - elsif !page.was_truncated?
  16 + = gap_tag
  17 + = next_page_tag unless current_page.last?
app/views/kaminari/_prev_page.html.haml 0 → 100644
@@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
  1 +-# Link to the "Previous" page
  2 +-# available local variables
  3 +-# url: url to the previous page
  4 +-# current_page: a page object for the currently displayed page
  5 +-# num_pages: total number of pages
  6 +-# per_page: number of items to fetch per page
  7 +-# remote: data-remote
  8 +%li{:class => "prev" }
  9 + = link_to_unless current_page.first?, raw(t 'views.pagination.previous'), url, :rel => 'prev', :remote => remote
app/views/layouts/_app_side.html.haml
@@ -4,7 +4,4 @@ @@ -4,7 +4,4 @@
4 = link_to "Projects", projects_path, :class => "#{"active" if current_page?(projects_path)}" 4 = link_to "Projects", projects_path, :class => "#{"active" if current_page?(projects_path)}"
5 = link_to "Issues", dashboard_issues_path, :class => "#{"active" if current_page?(dashboard_issues_path)}", :id => "issues_slide" 5 = link_to "Issues", dashboard_issues_path, :class => "#{"active" if current_page?(dashboard_issues_path)}", :id => "issues_slide"
6 = link_to "Requests", dashboard_merge_requests_path, :class => "#{"active" if current_page?(dashboard_merge_requests_path)}", :id => "merge_requests_slide" 6 = link_to "Requests", dashboard_merge_requests_path, :class => "#{"active" if current_page?(dashboard_merge_requests_path)}", :id => "merge_requests_slide"
7 - - if current_user.is_admin?  
8 - = link_to admin_root_path, :class => "admin", :title => "Admin" do  
9 - Admin  
10 = link_to "Help", help_path, :class => "#{"active" if controller.controller_name == "help"}" 7 = link_to "Help", help_path, :class => "#{"active" if controller.controller_name == "help"}"
app/views/layouts/_projects_side.html.haml
@@ -4,8 +4,16 @@ @@ -4,8 +4,16 @@
4 You can create at least 4 You can create at least
5 = current_user.projects_limit 5 = current_user.projects_limit
6 projects. Click on button to add a new one 6 projects. Click on button to add a new one
7 - = link_to new_project_path, :class => "btn small" do  
8 - New Project 7 + .alert-actions
  8 + = link_to new_project_path, :class => "btn small" do
  9 + New Project »
  10 +
  11 + - if current_user.is_admin?
  12 + .alert-message.block-message.info
  13 + You have administrator privilegies. You can configure application following this button:
  14 + .alert-actions
  15 + = link_to admin_root_path, :class => "btn small", :title => "Admin" do
  16 + Visit Admin Area »
9 17
10 - if current_user.projects.count > 0 18 - if current_user.projects.count > 0
11 %div.entry 19 %div.entry
@@ -18,21 +26,5 @@ @@ -18,21 +26,5 @@
18 = project.name 26 = project.name
19 = link_to "More » ", projects_path 27 = link_to "More » ", projects_path
20 28
21 - -#%h5  
22 - -#Your Issues:  
23 - -#%ul  
24 - -#- current_user.assigned_issues.order("id DESC").limit(5).each do |issue|  
25 - -#%li  
26 - -#= link_to project_issue_path(issue.project, issue) do  
27 - -#= truncate issue.title  
28 -  
29 -  
30 - -#%h5  
31 - -#Your Merge Requests:  
32 - -#%ul  
33 - -#- current_user.assigned_merge_requests.order("id DESC").limit(5).each do |issue|  
34 - -#%li  
35 - -#= link_to project_merge_request_path(issue.project, issue) do  
36 - -#= truncate issue.title  
37 29
38 30
app/views/layouts/admin.html.haml
@@ -10,7 +10,6 @@ @@ -10,7 +10,6 @@
10 %aside 10 %aside
11 = link_to "Users", admin_users_path, :class => controller.controller_name == "users" ? "current" : nil 11 = link_to "Users", admin_users_path, :class => controller.controller_name == "users" ? "current" : nil
12 = link_to "Projects", admin_projects_path, :class => controller.controller_name == "projects" ? "current" : nil 12 = link_to "Projects", admin_projects_path, :class => controller.controller_name == "projects" ? "current" : nil
13 - = link_to "Teams", admin_team_members_path, :class => controller.controller_name == "team_members" ? "current" : nil  
14 = link_to "Emails", admin_emails_path, :class => controller.controller_name == "mailer" ? "current" : nil 13 = link_to "Emails", admin_emails_path, :class => controller.controller_name == "mailer" ? "current" : nil
15 = link_to "Resque", "/info/resque" 14 = link_to "Resque", "/info/resque"
16 15
app/views/profile/show.html.haml
@@ -28,5 +28,6 @@ @@ -28,5 +28,6 @@
28 = f.label :twitter 28 = f.label :twitter
29 .input= f.text_field :twitter 29 .input= f.text_field :twitter
30 30
31 - = f.submit 'Save', :class => "primary btn" 31 + .actions
  32 + = f.submit 'Save', :class => "primary btn"
32 33
config/routes.rb
@@ -7,14 +7,18 @@ Gitlab::Application.routes.draw do @@ -7,14 +7,18 @@ Gitlab::Application.routes.draw do
7 get 'help' => 'help#index' 7 get 'help' => 'help#index'
8 8
9 namespace :admin do 9 namespace :admin do
10 - resources :users 10 + resources :users do
  11 + member do
  12 + put :team_update
  13 + end
  14 + end
11 resources :projects, :constraints => { :id => /[^\/]+/ } do 15 resources :projects, :constraints => { :id => /[^\/]+/ } do
12 member do 16 member do
13 get :team 17 get :team
14 put :team_update 18 put :team_update
15 end 19 end
16 end 20 end
17 - resources :team_members 21 + resources :team_members, :only => [:edit, :update, :destroy]
18 get 'emails', :to => 'mailer#preview' 22 get 'emails', :to => 'mailer#preview'
19 get 'mailer/preview_note' 23 get 'mailer/preview_note'
20 get 'mailer/preview_user_new' 24 get 'mailer/preview_user_new'
spec/requests/admin/admin_projects_spec.rb
@@ -18,7 +18,6 @@ describe "Admin::Projects" do @@ -18,7 +18,6 @@ describe "Admin::Projects" do
18 end 18 end
19 19
20 it "should have projects list" do 20 it "should have projects list" do
21 - page.should have_content(@project.code)  
22 page.should have_content(@project.name) 21 page.should have_content(@project.name)
23 end 22 end
24 end 23 end
@@ -103,4 +102,18 @@ describe "Admin::Projects" do @@ -103,4 +102,18 @@ describe "Admin::Projects" do
103 page.should have_content(@project.description) 102 page.should have_content(@project.description)
104 end 103 end
105 end 104 end
  105 +
  106 + describe "Add new team member" do
  107 + before do
  108 + @new_user = Factory :user
  109 + visit admin_project_path(@project)
  110 + end
  111 +
  112 + it "should create new user" do
  113 + select @new_user.name, :from => "user_ids"
  114 + expect { click_button "Add" }.to change { UsersProject.count }.by(1)
  115 + page.should have_content @new_user.name
  116 + current_path.should == admin_project_path(@project)
  117 + end
  118 + end
106 end 119 end
spec/requests/admin/admin_users_spec.rb
@@ -99,4 +99,18 @@ describe "Admin::Users" do @@ -99,4 +99,18 @@ describe "Admin::Users" do
99 end 99 end
100 end 100 end
101 end 101 end
  102 +
  103 + describe "Add new project" do
  104 + before do
  105 + @new_project = Factory :project
  106 + visit admin_user_path(@user)
  107 + end
  108 +
  109 + it "should create new user" do
  110 + select @new_project.name, :from => "project_ids"
  111 + expect { click_button "Add" }.to change { UsersProject.count }.by(1)
  112 + page.should have_content @new_project.name
  113 + current_path.should == admin_user_path(@user)
  114 + end
  115 + end
102 end 116 end
spec/requests/admin/security_spec.rb
@@ -13,12 +13,6 @@ describe "Admin::Projects" do @@ -13,12 +13,6 @@ describe "Admin::Projects" do
13 it { admin_users_path.should be_denied_for :visitor } 13 it { admin_users_path.should be_denied_for :visitor }
14 end 14 end
15 15
16 - describe "GET /admin/team_members" do  
17 - it { admin_team_members_path.should be_allowed_for :admin }  
18 - it { admin_team_members_path.should be_denied_for :user }  
19 - it { admin_team_members_path.should be_denied_for :visitor }  
20 - end  
21 -  
22 describe "GET /admin/emails" do 16 describe "GET /admin/emails" do
23 it { admin_emails_path.should be_allowed_for :admin } 17 it { admin_emails_path.should be_allowed_for :admin }
24 it { admin_emails_path.should be_denied_for :user } 18 it { admin_emails_path.should be_denied_for :user }