Commit e3c3c67b25e2601194293885818ff4dfb39885cd

Authored by Dmitriy Zaporozhets
2 parents 596442f7 d24fd32a

Merge pull request #2787 from gitlabhq/features/projects_page

Feature: Projects page
app/controllers/dashboard_controller.rb
1 class DashboardController < ApplicationController 1 class DashboardController < ApplicationController
2 respond_to :html 2 respond_to :html
3 3
4 - before_filter :projects  
5 - before_filter :event_filter, only: :index 4 + before_filter :load_projects
  5 + before_filter :event_filter, only: :show
6 6
7 - def index 7 + def show
8 @groups = current_user.authorized_groups 8 @groups = current_user.authorized_groups
9 -  
10 @has_authorized_projects = @projects.count > 0 9 @has_authorized_projects = @projects.count > 0
11 -  
12 - @projects = case params[:scope]  
13 - when 'personal' then  
14 - @projects.personal(current_user)  
15 - when 'joined' then  
16 - @projects.joined(current_user)  
17 - else  
18 - @projects  
19 - end  
20 -  
21 @teams = current_user.authorized_teams 10 @teams = current_user.authorized_teams
22 -  
23 - @projects = @projects.page(params[:page]).per(30) 11 + @projects_count = @projects.count
  12 + @projects = @projects.limit(20)
24 13
25 @events = Event.in_projects(current_user.authorized_projects.pluck(:id)) 14 @events = Event.in_projects(current_user.authorized_projects.pluck(:id))
26 @events = @event_filter.apply_filter(@events) 15 @events = @event_filter.apply_filter(@events)
@@ -35,6 +24,19 @@ class DashboardController &lt; ApplicationController @@ -35,6 +24,19 @@ class DashboardController &lt; ApplicationController
35 end 24 end
36 end 25 end
37 26
  27 + def projects
  28 + @projects = case params[:scope]
  29 + when 'personal' then
  30 + @projects.personal(current_user)
  31 + when 'joined' then
  32 + @projects.joined(current_user)
  33 + else
  34 + @projects
  35 + end
  36 +
  37 + @projects = @projects.page(params[:page]).per(30)
  38 + end
  39 +
38 # Get authored or assigned open merge requests 40 # Get authored or assigned open merge requests
39 def merge_requests 41 def merge_requests
40 @merge_requests = current_user.cared_merge_requests 42 @merge_requests = current_user.cared_merge_requests
@@ -57,7 +59,7 @@ class DashboardController &lt; ApplicationController @@ -57,7 +59,7 @@ class DashboardController &lt; ApplicationController
57 59
58 protected 60 protected
59 61
60 - def projects 62 + def load_projects
61 @projects = current_user.authorized_projects.sorted_by_activity 63 @projects = current_user.authorized_projects.sorted_by_activity
62 end 64 end
63 65
app/helpers/dashboard_helper.rb
@@ -9,9 +9,9 @@ module DashboardHelper @@ -9,9 +9,9 @@ module DashboardHelper
9 9
10 case entity 10 case entity
11 when 'issue' then 11 when 'issue' then
12 - dashboard_issues_path(options) 12 + issues_dashboard_path(options)
13 when 'merge_request' 13 when 'merge_request'
14 - dashboard_merge_requests_path(options) 14 + merge_requests_dashboard_path(options)
15 end 15 end
16 end 16 end
17 17
app/helpers/projects_helper.rb
@@ -55,7 +55,9 @@ module ProjectsHelper @@ -55,7 +55,9 @@ module ProjectsHelper
55 55
56 def project_title project 56 def project_title project
57 if project.group 57 if project.group
58 - project.name_with_namespace 58 + content_tag :span do
  59 + link_to(project.group.name, group_path(project.group)) + " / " + project.name
  60 + end
59 else 61 else
60 project.name 62 project.name
61 end 63 end
app/views/dashboard/_projects.html.haml
@@ -2,19 +2,12 @@ @@ -2,19 +2,12 @@
2 %h5.title 2 %h5.title
3 Projects 3 Projects
4 %small 4 %small
5 - (#{projects.total_count}) 5 + (#{@projects_count})
6 - if current_user.can_create_project? 6 - if current_user.can_create_project?
7 %span.right 7 %span.right
8 = link_to new_project_path, class: "btn very_small info" do 8 = link_to new_project_path, class: "btn very_small info" do
9 %i.icon-plus 9 %i.icon-plus
10 New Project 10 New Project
11 - %ul.nav.nav-projects-tabs  
12 - = nav_tab :scope, nil do  
13 - = link_to "All", dashboard_path  
14 - = nav_tab :scope, 'personal' do  
15 - = link_to "Personal", dashboard_path(scope: 'personal')  
16 - = nav_tab :scope, 'joined' do  
17 - = link_to "Joined", dashboard_path(scope: 'joined')  
18 11
19 %ul.well-list 12 %ul.well-list
20 - projects.each do |project| 13 - projects.each do |project|
@@ -33,4 +26,6 @@ @@ -33,4 +26,6 @@
33 - if projects.blank? 26 - if projects.blank?
34 %li 27 %li
35 %h3.nothing_here_message There are no projects here. 28 %h3.nothing_here_message There are no projects here.
36 - .bottom= paginate projects, theme: "gitlab" 29 + - if @projects_count > 20
  30 + %li.bottom
  31 + %strong= link_to "show all projects", projects_dashboard_path
app/views/dashboard/index.atom.builder
@@ -1,30 +0,0 @@ @@ -1,30 +0,0 @@
1 -xml.instruct!  
2 -xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do  
3 - xml.title "Dashboard feed#{" - #{current_user.name}" if current_user.name.present?}"  
4 - xml.link :href => projects_url(:atom), :rel => "self", :type => "application/atom+xml"  
5 - xml.link :href => projects_url, :rel => "alternate", :type => "text/html"  
6 - xml.id projects_url  
7 - xml.updated @events.maximum(:updated_at).strftime("%Y-%m-%dT%H:%M:%SZ") if @events.any?  
8 -  
9 - @events.each do |event|  
10 - if event.proper?  
11 - event = EventDecorator.decorate(event)  
12 - xml.entry do  
13 - event_link = event.feed_url  
14 - event_title = event.feed_title  
15 - event_summary = event.feed_summary  
16 -  
17 - xml.id "tag:#{request.host},#{event.created_at.strftime("%Y-%m-%d")}:#{event.id}"  
18 - xml.link :href => event_link  
19 - xml.title truncate(event_title, :length => 80)  
20 - xml.updated event.created_at.strftime("%Y-%m-%dT%H:%M:%SZ")  
21 - xml.media :thumbnail, :width => "40", :height => "40", :url => gravatar_icon(event.author_email)  
22 - xml.author do |author|  
23 - xml.name event.author_name  
24 - xml.email event.author_email  
25 - end  
26 - xml.summary(:type => "xhtml") { |x| x << event_summary unless event_summary.nil? }  
27 - end  
28 - end  
29 - end  
30 -end  
app/views/dashboard/index.html.haml
@@ -1,12 +0,0 @@ @@ -1,12 +0,0 @@
1 -- if @has_authorized_projects  
2 - .projects  
3 - .activities.span8  
4 - = render 'activities'  
5 - .side.span4  
6 - = render 'sidebar'  
7 -  
8 -- else  
9 - = render "zero_authorized_projects"  
10 -  
11 -:javascript  
12 - dashboardPage();  
app/views/dashboard/index.js.haml
@@ -1,2 +0,0 @@ @@ -1,2 +0,0 @@
1 -:plain  
2 - Pager.append(#{@events.count}, "#{escape_javascript(render(@events))}");  
app/views/dashboard/issues.atom.builder
1 xml.instruct! 1 xml.instruct!
2 xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do 2 xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
3 xml.title "#{current_user.name} issues" 3 xml.title "#{current_user.name} issues"
4 - xml.link :href => dashboard_issues_url(:atom, :private_token => current_user.private_token), :rel => "self", :type => "application/atom+xml"  
5 - xml.link :href => dashboard_issues_url(:private_token => current_user.private_token), :rel => "alternate", :type => "text/html"  
6 - xml.id dashboard_issues_url(:private_token => current_user.private_token) 4 + xml.link :href => issues_dashboard_url(:atom, :private_token => current_user.private_token), :rel => "self", :type => "application/atom+xml"
  5 + xml.link :href => issues_dashboard_url(:private_token => current_user.private_token), :rel => "alternate", :type => "text/html"
  6 + xml.id issues_dashboard_url(:private_token => current_user.private_token)
7 xml.updated @issues.first.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") if @issues.any? 7 xml.updated @issues.first.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") if @issues.any?
8 8
9 @issues.each do |issue| 9 @issues.each do |issue|
app/views/dashboard/projects.html.haml 0 → 100644
@@ -0,0 +1,56 @@ @@ -0,0 +1,56 @@
  1 +%h3.page_title
  2 + Projects
  3 + %span
  4 + (#{@projects.total_count})
  5 + - if current_user.can_create_project?
  6 + %span.right
  7 + = link_to new_project_path, class: "btn very_small info" do
  8 + %i.icon-plus
  9 + New Project
  10 +
  11 +
  12 +%hr
  13 +.row
  14 + .span3
  15 + %ul.nav.nav-pills.nav-stacked
  16 + = nav_tab :scope, nil do
  17 + = link_to "All", projects_dashboard_path
  18 + = nav_tab :scope, 'personal' do
  19 + = link_to "Personal", projects_dashboard_path(scope: 'personal')
  20 + = nav_tab :scope, 'joined' do
  21 + = link_to "Joined", projects_dashboard_path(scope: 'joined')
  22 +
  23 + .span9
  24 + = form_tag projects_dashboard_path, method: 'get' do
  25 + %fieldset.dashboard-search-filter
  26 + = hidden_field_tag "scope", params[:scope]
  27 + = search_field_tag "search", params[:search], { placeholder: 'Search', class: 'left input-xxlarge' }
  28 + = button_tag type: 'submit', class: 'btn' do
  29 + %i.icon-search
  30 +
  31 + %ul.well-list
  32 + - @projects.each do |project|
  33 + %li.clearfix
  34 + .left
  35 + = link_to project_path(project), class: dom_class(project) do
  36 + - if project.namespace
  37 + = project.namespace.human_name
  38 + \/
  39 + %strong.well-title
  40 + = truncate(project.name, length: 25)
  41 + %br
  42 + %small.light
  43 + %strong Last activity:
  44 + %span= project_last_activity(project)
  45 + .right.light
  46 + - if project.owner == current_user
  47 + %i.icon-wrench
  48 + - tm = project.team.get_tm(current_user.id)
  49 + - if tm
  50 + = tm.project_access_human
  51 +
  52 + - if @projects.blank?
  53 + %li
  54 + %h3.nothing_here_message There are no projects here.
  55 + .bottom= paginate @projects, theme: "gitlab"
  56 +
app/views/dashboard/show.atom.builder 0 → 100644
@@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
  1 +xml.instruct!
  2 +xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
  3 + xml.title "Dashboard feed#{" - #{current_user.name}" if current_user.name.present?}"
  4 + xml.link :href => projects_url(:atom), :rel => "self", :type => "application/atom+xml"
  5 + xml.link :href => projects_url, :rel => "alternate", :type => "text/html"
  6 + xml.id projects_url
  7 + xml.updated @events.maximum(:updated_at).strftime("%Y-%m-%dT%H:%M:%SZ") if @events.any?
  8 +
  9 + @events.each do |event|
  10 + if event.proper?
  11 + event = EventDecorator.decorate(event)
  12 + xml.entry do
  13 + event_link = event.feed_url
  14 + event_title = event.feed_title
  15 + event_summary = event.feed_summary
  16 +
  17 + xml.id "tag:#{request.host},#{event.created_at.strftime("%Y-%m-%d")}:#{event.id}"
  18 + xml.link :href => event_link
  19 + xml.title truncate(event_title, :length => 80)
  20 + xml.updated event.created_at.strftime("%Y-%m-%dT%H:%M:%SZ")
  21 + xml.media :thumbnail, :width => "40", :height => "40", :url => gravatar_icon(event.author_email)
  22 + xml.author do |author|
  23 + xml.name event.author_name
  24 + xml.email event.author_email
  25 + end
  26 + xml.summary(:type => "xhtml") { |x| x << event_summary unless event_summary.nil? }
  27 + end
  28 + end
  29 + end
  30 +end
app/views/dashboard/show.html.haml 0 → 100644
@@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
  1 +- if @has_authorized_projects
  2 + .projects
  3 + .activities.span8
  4 + = render 'activities'
  5 + .side.span4
  6 + = render 'sidebar'
  7 +
  8 +- else
  9 + = render "zero_authorized_projects"
  10 +
  11 +:javascript
  12 + dashboardPage();
app/views/dashboard/show.js.haml 0 → 100644
@@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
  1 +:plain
  2 + Pager.append(#{@events.count}, "#{escape_javascript(render(@events))}");
app/views/groups/issues.atom.builder
1 xml.instruct! 1 xml.instruct!
2 xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do 2 xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://search.yahoo.com/mrss/" do
3 xml.title "#{@user.name} issues" 3 xml.title "#{@user.name} issues"
4 - xml.link :href => dashboard_issues_url(:atom, :private_token => @user.private_token), :rel => "self", :type => "application/atom+xml"  
5 - xml.link :href => dashboard_issues_url(:private_token => @user.private_token), :rel => "alternate", :type => "text/html"  
6 - xml.id dashboard_issues_url(:private_token => @user.private_token) 4 + xml.link :href => issues_dashboard_url(:atom, :private_token => @user.private_token), :rel => "self", :type => "application/atom+xml"
  5 + xml.link :href => issues_dashboard_url(:private_token => @user.private_token), :rel => "alternate", :type => "text/html"
  6 + xml.id issues_dashboard_url(:private_token => @user.private_token)
7 xml.updated @issues.first.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") if @issues.any? 7 xml.updated @issues.first.created_at.strftime("%Y-%m-%dT%H:%M:%SZ") if @issues.any?
8 8
9 @issues.each do |issue| 9 @issues.each do |issue|
app/views/layouts/application.html.haml
@@ -6,14 +6,17 @@ @@ -6,14 +6,17 @@
6 = render "layouts/head_panel", title: "Dashboard" 6 = render "layouts/head_panel", title: "Dashboard"
7 .container 7 .container
8 %ul.main_menu 8 %ul.main_menu
9 - = nav_link(path: 'dashboard#index', html_options: {class: 'home'}) do 9 + = nav_link(path: 'dashboard#show', html_options: {class: 'home'}) do
10 = link_to "Home", root_path, title: "Home" 10 = link_to "Home", root_path, title: "Home"
  11 + = nav_link(path: 'dashboard#projects') do
  12 + = link_to projects_dashboard_path do
  13 + Projects
11 = nav_link(path: 'dashboard#issues') do 14 = nav_link(path: 'dashboard#issues') do
12 - = link_to dashboard_issues_path do 15 + = link_to issues_dashboard_path do
13 Issues 16 Issues
14 %span.count= current_user.assigned_issues.opened.count 17 %span.count= current_user.assigned_issues.opened.count
15 = nav_link(path: 'dashboard#merge_requests') do 18 = nav_link(path: 'dashboard#merge_requests') do
16 - = link_to dashboard_merge_requests_path do 19 + = link_to merge_requests_dashboard_path do
17 Merge Requests 20 Merge Requests
18 %span.count= current_user.cared_merge_requests.opened.count 21 %span.count= current_user.cared_merge_requests.opened.count
19 = nav_link(path: 'search#show') do 22 = nav_link(path: 'search#show') do
config/routes.rb
@@ -118,9 +118,13 @@ Gitlab::Application.routes.draw do @@ -118,9 +118,13 @@ Gitlab::Application.routes.draw do
118 # 118 #
119 # Dashboard Area 119 # Dashboard Area
120 # 120 #
121 - get "dashboard" => "dashboard#index"  
122 - get "dashboard/issues" => "dashboard#issues"  
123 - get "dashboard/merge_requests" => "dashboard#merge_requests" 121 + resource :dashboard, controller: "dashboard" do
  122 + member do
  123 + get :projects
  124 + get :issues
  125 + get :merge_requests
  126 + end
  127 + end
124 128
125 # 129 #
126 # Groups Area 130 # Groups Area
@@ -284,5 +288,5 @@ Gitlab::Application.routes.draw do @@ -284,5 +288,5 @@ Gitlab::Application.routes.draw do
284 end 288 end
285 end 289 end
286 290
287 - root to: "dashboard#index" 291 + root to: "dashboard#show"
288 end 292 end
features/dashboard/projects.feature 0 → 100644
@@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
  1 +Feature: Dashboard
  2 + Background:
  3 + Given I sign in as a user
  4 + And I own project "Shop"
  5 + And I visit dashboard projects page
  6 +
  7 + Scenario: I should see issues list
  8 + Then I should see projects list
features/steps/dashboard/dashboard.rb
@@ -63,6 +63,12 @@ class Dashboard &lt; Spinach::FeatureSteps @@ -63,6 +63,12 @@ class Dashboard &lt; Spinach::FeatureSteps
63 @project.team << [current_user, :master] 63 @project.team << [current_user, :master]
64 end 64 end
65 65
  66 + Then 'I should see projects list' do
  67 + @user.authorized_projects.all.each do |project|
  68 + page.should have_link project.name_with_namespace
  69 + end
  70 + end
  71 +
66 Then 'I should see groups list' do 72 Then 'I should see groups list' do
67 Group.all.each do |group| 73 Group.all.each do |group|
68 page.should have_link group.name 74 page.should have_link group.name
features/steps/shared/paths.rb
@@ -33,12 +33,16 @@ module SharedPaths @@ -33,12 +33,16 @@ module SharedPaths
33 visit dashboard_path 33 visit dashboard_path
34 end 34 end
35 35
  36 + Given 'I visit dashboard projects page' do
  37 + visit projects_dashboard_path
  38 + end
  39 +
36 Given 'I visit dashboard issues page' do 40 Given 'I visit dashboard issues page' do
37 - visit dashboard_issues_path 41 + visit issues_dashboard_path
38 end 42 end
39 43
40 Given 'I visit dashboard merge requests page' do 44 Given 'I visit dashboard merge requests page' do
41 - visit dashboard_merge_requests_path 45 + visit merge_requests_dashboard_path
42 end 46 end
43 47
44 Given 'I visit dashboard search page' do 48 Given 'I visit dashboard search page' do
spec/requests/atom/dashboard_issues_spec.rb
@@ -10,7 +10,7 @@ describe &quot;Dashboard Issues Feed&quot; do @@ -10,7 +10,7 @@ describe &quot;Dashboard Issues Feed&quot; do
10 10
11 describe "atom feed" do 11 describe "atom feed" do
12 it "should render atom feed via private token" do 12 it "should render atom feed via private token" do
13 - visit dashboard_issues_path(:atom, private_token: user.private_token) 13 + visit issues_dashboard_path(:atom, private_token: user.private_token)
14 14
15 page.response_headers['Content-Type'].should have_content("application/atom+xml") 15 page.response_headers['Content-Type'].should have_content("application/atom+xml")
16 page.body.should have_selector("title", text: "#{user.name} issues") 16 page.body.should have_selector("title", text: "#{user.name} issues")
spec/routing/routing_spec.rb
@@ -146,14 +146,14 @@ describe KeysController, &quot;routing&quot; do @@ -146,14 +146,14 @@ describe KeysController, &quot;routing&quot; do
146 end 146 end
147 end 147 end
148 148
149 -# dashboard GET /dashboard(.:format) dashboard#index 149 +# dashboard GET /dashboard(.:format) dashboard#show
150 # dashboard_issues GET /dashboard/issues(.:format) dashboard#issues 150 # dashboard_issues GET /dashboard/issues(.:format) dashboard#issues
151 # dashboard_merge_requests GET /dashboard/merge_requests(.:format) dashboard#merge_requests 151 # dashboard_merge_requests GET /dashboard/merge_requests(.:format) dashboard#merge_requests
152 -# root / dashboard#index 152 +# root / dashboard#show
153 describe DashboardController, "routing" do 153 describe DashboardController, "routing" do
154 it "to #index" do 154 it "to #index" do
155 - get("/dashboard").should route_to('dashboard#index')  
156 - get("/").should route_to('dashboard#index') 155 + get("/dashboard").should route_to('dashboard#show')
  156 + get("/").should route_to('dashboard#show')
157 end 157 end
158 158
159 it "to #issues" do 159 it "to #issues" do