summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>2016-01-28 16:58:38 +0000
committerDmitriy Zaporozhets <dmitriy.zaporozhets@gmail.com>2016-01-28 16:58:38 +0000
commit88e16c3d19cbdf4452af713ecc07989dbd3c35f0 (patch)
tree497e41d3e9ae8dd1bde889549788de89d9fa5279
parent3f6bb7bc86a61e406aafdbf2b5975755f4cbe7ad (diff)
parent0ee875f9618f3e14b52165f99dfdae21c0512d7c (diff)
downloadgitlab-ce-88e16c3d19cbdf4452af713ecc07989dbd3c35f0.tar.gz
Merge branch 'issue_2406' into 'master'
Show list of forks for a given Project Closes #2406 See merge request !2376
-rw-r--r--app/assets/javascripts/projects_list.js.coffee4
-rw-r--r--app/assets/stylesheets/pages/projects.scss50
-rw-r--r--app/controllers/projects/forks_controller.rb11
-rw-r--r--app/helpers/blob_helper.rb6
-rw-r--r--app/helpers/icons_helper.rb2
-rw-r--r--app/helpers/projects_helper.rb2
-rw-r--r--app/views/layouts/nav/_project.html.haml7
-rw-r--r--app/views/projects/buttons/_dropdown.html.haml2
-rw-r--r--app/views/projects/forks/index.html.haml58
-rw-r--r--app/views/projects/forks/new.html.haml2
-rw-r--r--app/views/projects/tree/_tree_header.html.haml6
-rw-r--r--app/views/shared/projects/_list.html.haml6
-rw-r--r--app/views/shared/projects/_project.html.haml21
-rw-r--r--config/routes.rb2
-rw-r--r--features/project/fork.feature15
-rw-r--r--features/steps/project/fork.rb25
-rw-r--r--features/steps/project/forked_merge_requests.rb4
-rw-r--r--spec/routing/project_routing_spec.rb4
18 files changed, 205 insertions, 22 deletions
diff --git a/app/assets/javascripts/projects_list.js.coffee b/app/assets/javascripts/projects_list.js.coffee
index f2887af190b..b71509dbc5a 100644
--- a/app/assets/javascripts/projects_list.js.coffee
+++ b/app/assets/javascripts/projects_list.js.coffee
@@ -9,11 +9,13 @@ class @ProjectsList
$(".projects-list-filter").keyup ->
terms = $(this).val()
uiBox = $('div.projects-list-holder')
+ filterSelector = $(this).data('filter-selector') || 'span.filter-title'
+
if terms == "" || terms == undefined
uiBox.find("ul.projects-list li").show()
else
uiBox.find("ul.projects-list li").each (index) ->
- name = $(this).find("span.filter-title").text()
+ name = $(this).find(filterSelector).text()
if name.toLowerCase().search(terms.toLowerCase()) == -1
$(this).hide()
diff --git a/app/assets/stylesheets/pages/projects.scss b/app/assets/stylesheets/pages/projects.scss
index 003a4c22f20..e4ea47cc4a2 100644
--- a/app/assets/stylesheets/pages/projects.scss
+++ b/app/assets/stylesheets/pages/projects.scss
@@ -564,3 +564,53 @@ pre.light-well {
color: #E62958;
margin-top: 2px;
}
+
+/*
+ * Forks list rendered on Project's forks page
+ */
+
+.forks-top-block {
+ padding: 16px 0;
+}
+
+.projects-search-form {
+ .dropdown-toggle.btn {
+ margin-top: -3px;
+ }
+
+ &.fork-search-form {
+ margin: 0;
+ margin-top: -$gl-padding;
+ padding-bottom: 0;
+
+ input {
+ /* Small devices (tablets, 768px and up) */
+ @media (min-width: $screen-sm-min) { width: 180px; }
+
+ /* Medium devices (desktops, 992px and up) */
+ @media (min-width: $screen-md-min) { width: 350px; }
+
+ /* Large devices (large desktops, 1200px and up) */
+ @media (min-width: $screen-lg-min) { width: 400px; }
+ }
+
+ .sort-forks {
+ width: 160px;
+ }
+
+ .fork-link {
+ float: right;
+ margin-left: $gl-padding;
+ }
+ }
+}
+
+.private-forks-notice .private-fork-icon {
+ i:nth-child(1) {
+ color: #2AA056;
+ }
+
+ i:nth-child(2) {
+ color: #FFFFFF;
+ }
+}
diff --git a/app/controllers/projects/forks_controller.rb b/app/controllers/projects/forks_controller.rb
index 750181f0c19..e61e01c4a59 100644
--- a/app/controllers/projects/forks_controller.rb
+++ b/app/controllers/projects/forks_controller.rb
@@ -3,6 +3,15 @@ class Projects::ForksController < Projects::ApplicationController
before_action :require_non_empty_project
before_action :authorize_download_code!
+ def index
+ @sort = params[:sort] || 'id_desc'
+ @all_forks = project.forks.includes(:creator).order_by(@sort)
+
+ @public_forks, @protected_forks = @all_forks.partition do |project|
+ can?(current_user, :read_project, project)
+ end
+ end
+
def new
@namespaces = current_user.manageable_namespaces
@namespaces.delete(@project.namespace)
@@ -10,7 +19,7 @@ class Projects::ForksController < Projects::ApplicationController
def create
namespace = Namespace.find(params[:namespace_key])
-
+
@forked_project = namespace.projects.find_by(path: project.path)
@forked_project = nil unless @forked_project && @forked_project.forked_from_project == project
diff --git a/app/helpers/blob_helper.rb b/app/helpers/blob_helper.rb
index 8b689b29a41..694c03206bd 100644
--- a/app/helpers/blob_helper.rb
+++ b/app/helpers/blob_helper.rb
@@ -36,8 +36,7 @@ module BlobHelper
notice: edit_in_new_fork_notice,
notice_now: edit_in_new_fork_notice_now
}
- fork_path = namespace_project_fork_path(project.namespace, project, namespace_key: current_user.namespace.id,
- continue: continue_params)
+ fork_path = namespace_project_forks_path(project.namespace, project, namespace_key: current_user.namespace.id, continue: continue_params)
link_to "Edit", fork_path, class: 'btn', method: :post
end
@@ -62,8 +61,7 @@ module BlobHelper
notice: edit_in_new_fork_notice + " Try to #{action} this file again.",
notice_now: edit_in_new_fork_notice_now
}
- fork_path = namespace_project_fork_path(project.namespace, project, namespace_key: current_user.namespace.id,
- continue: continue_params)
+ fork_path = namespace_project_forks_path(project.namespace, project, namespace_key: current_user.namespace.id, continue: continue_params)
link_to label, fork_path, class: "btn btn-#{btn_class}", method: :post
end
diff --git a/app/helpers/icons_helper.rb b/app/helpers/icons_helper.rb
index 5724d3aabec..84c6d0883b0 100644
--- a/app/helpers/icons_helper.rb
+++ b/app/helpers/icons_helper.rb
@@ -7,7 +7,7 @@ module IconsHelper
# font-awesome-rails gem, but should we ever use a different icon pack in the
# future we won't have to change hundreds of method calls.
def icon(names, options = {})
- fa_icon(names, options)
+ options.include?(:base) ? fa_stacked_icon(names, options) : fa_icon(names, options)
end
def spinner(text = nil, visible = false)
diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb
index c5823e50096..f70a0f3adf2 100644
--- a/app/helpers/projects_helper.rb
+++ b/app/helpers/projects_helper.rb
@@ -116,7 +116,7 @@ module ProjectsHelper
private
def get_project_nav_tabs(project, current_user)
- nav_tabs = [:home]
+ nav_tabs = [:home, :forks]
if !project.empty_repo? && can?(current_user, :download_code, project)
nav_tabs << [:files, :commits, :network, :graphs]
diff --git a/app/views/layouts/nav/_project.html.haml b/app/views/layouts/nav/_project.html.haml
index 270ccfd387f..319974e12c5 100644
--- a/app/views/layouts/nav/_project.html.haml
+++ b/app/views/layouts/nav/_project.html.haml
@@ -98,6 +98,13 @@
%span
Wiki
+ - if project_nav_tab? :forks
+ = nav_link(controller: :forks, action: :index) do
+ = link_to namespace_project_forks_path(@project.namespace, @project), title: 'Forks' do
+ = icon('code-fork fw')
+ %span
+ Forks
+
- if project_nav_tab? :snippets
= nav_link(controller: :snippets) do
= link_to namespace_project_snippets_path(@project.namespace, @project), title: 'Snippets', class: 'shortcuts-snippets' do
diff --git a/app/views/projects/buttons/_dropdown.html.haml b/app/views/projects/buttons/_dropdown.html.haml
index 511863d774e..e7c85edff96 100644
--- a/app/views/projects/buttons/_dropdown.html.haml
+++ b/app/views/projects/buttons/_dropdown.html.haml
@@ -46,7 +46,7 @@
- continue_params = { to: namespace_project_new_blob_path(@project.namespace, @project, @project.default_branch || 'master'),
notice: edit_in_new_fork_notice,
notice_now: edit_in_new_fork_notice_now }
- - fork_path = namespace_project_fork_path(@project.namespace, @project, namespace_key: current_user.namespace.id,
+ - fork_path = namespace_project_forks_path(@project.namespace, @project, namespace_key: current_user.namespace.id,
continue: continue_params)
= link_to fork_path, method: :post do
= icon('file fw')
diff --git a/app/views/projects/forks/index.html.haml b/app/views/projects/forks/index.html.haml
new file mode 100644
index 00000000000..a362185210a
--- /dev/null
+++ b/app/views/projects/forks/index.html.haml
@@ -0,0 +1,58 @@
+.gray-content-block.top-block.clearfix.white.forks-top-block
+ .pull-left
+ - public_count = @public_forks.size
+ - protected_count = @protected_forks.size
+ - full_count_title = "#{public_count} public and #{protected_count} private"
+ == #{pluralize(@all_forks.size, 'fork')}: #{full_count_title}
+
+ .pull-right
+ .projects-search-form.fork-search-form
+ = search_field_tag :filter_projects, nil, placeholder: 'Search forks', class: 'projects-list-filter form-control',
+ spellcheck: false, data: { 'filter-selector' => 'span.namespace-name' }
+
+ .dropdown.inline.prepend-left-10
+ %button.dropdown-toggle.btn.sort-forks{type: 'button', 'data-toggle' => 'dropdown'}
+ %span.light sort:
+ - if @sort.present?
+ = sort_options_hash[@sort]
+ - else
+ = sort_title_recently_created
+ %b.caret
+ %ul.dropdown-menu.dropdown-menu-align-right
+ %li
+ - excluded_filters = [:state, :scope, :label_name, :milestone_id, :assignee_id, :author_id]
+ = link_to page_filter_path(sort: sort_value_recently_created, without: excluded_filters) do
+ = sort_title_recently_created
+ = link_to page_filter_path(sort: sort_value_oldest_created, without: excluded_filters) do
+ = sort_title_oldest_created
+ = link_to page_filter_path(sort: sort_value_recently_updated, without: excluded_filters) do
+ = sort_title_recently_updated
+ = link_to page_filter_path(sort: sort_value_oldest_updated, without: excluded_filters) do
+ = sort_title_oldest_updated
+
+ .fork-link.inline
+ - if current_user.already_forked?(@project) && current_user.manageable_namespaces.size < 2
+ = link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: 'Go to your fork', class: 'pull-right btn btn-new' do
+ = icon('code-fork fw')
+ Fork
+ - else
+ = link_to new_namespace_project_fork_path(@project.namespace, @project), title: "Fork project", class: 'pull-right btn btn-new' do
+ = icon('code-fork fw')
+ Fork
+
+
+.projects-list-holder
+ - if @public_forks.blank?
+ %ul.content-list
+ %li
+ .nothing-here-block No forks to show
+ - else
+ = render 'shared/projects/list', projects: @public_forks, use_creator_avatar: true,
+ forks: true, show_last_commit_as_description: true
+
+ - if protected_count > 0
+ %ul.projects-list.private-forks-notice
+ %li.project-row
+ = icon('lock fw', base: 'circle', class: 'fa-lg private-fork-icon')
+ %strong= pluralize(protected_count, 'private fork')
+ %span you have no access to.
diff --git a/app/views/projects/forks/new.html.haml b/app/views/projects/forks/new.html.haml
index 8a2c027a455..edabc2d3b44 100644
--- a/app/views/projects/forks/new.html.haml
+++ b/app/views/projects/forks/new.html.haml
@@ -22,7 +22,7 @@
- else
.fork-thumbnail
- = link_to namespace_project_fork_path(@project.namespace, @project, namespace_key: namespace.id), title: "Fork here", method: "POST", class: 'has_tooltip' do
+ = link_to namespace_project_forks_path(@project.namespace, @project, namespace_key: namespace.id), title: "Fork here", method: "POST", class: 'has_tooltip' do
= image_tag namespace_icon(namespace, 100)
.caption
%strong
diff --git a/app/views/projects/tree/_tree_header.html.haml b/app/views/projects/tree/_tree_header.html.haml
index 3343288ad2b..3eb626e6dca 100644
--- a/app/views/projects/tree/_tree_header.html.haml
+++ b/app/views/projects/tree/_tree_header.html.haml
@@ -40,7 +40,7 @@
- continue_params = { to: namespace_project_new_blob_path(@project.namespace, @project, @id),
notice: edit_in_new_fork_notice,
notice_now: edit_in_new_fork_notice_now }
- - fork_path = namespace_project_fork_path(@project.namespace, @project, namespace_key: current_user.namespace.id,
+ - fork_path = namespace_project_forks_path(@project.namespace, @project, namespace_key: current_user.namespace.id,
continue: continue_params)
= link_to fork_path, method: :post do
= icon('pencil fw')
@@ -49,7 +49,7 @@
- continue_params = { to: request.fullpath,
notice: edit_in_new_fork_notice + " Try to upload a file again.",
notice_now: edit_in_new_fork_notice_now }
- - fork_path = namespace_project_fork_path(@project.namespace, @project, namespace_key: current_user.namespace.id,
+ - fork_path = namespace_project_forks_path(@project.namespace, @project, namespace_key: current_user.namespace.id,
continue: continue_params)
= link_to fork_path, method: :post do
= icon('file fw')
@@ -58,7 +58,7 @@
- continue_params = { to: request.fullpath,
notice: edit_in_new_fork_notice + " Try to create a new directory again.",
notice_now: edit_in_new_fork_notice_now }
- - fork_path = namespace_project_fork_path(@project.namespace, @project, namespace_key: current_user.namespace.id,
+ - fork_path = namespace_project_forks_path(@project.namespace, @project, namespace_key: current_user.namespace.id,
continue: continue_params)
= link_to fork_path, method: :post do
= icon('folder fw')
diff --git a/app/views/shared/projects/_list.html.haml b/app/views/shared/projects/_list.html.haml
index e5ffe1e29ae..b3f45373f6b 100644
--- a/app/views/shared/projects/_list.html.haml
+++ b/app/views/shared/projects/_list.html.haml
@@ -1,14 +1,18 @@
- projects_limit = 20 unless local_assigns[:projects_limit]
- avatar = true unless local_assigns[:avatar] == false
+- use_creator_avatar = false unless local_assigns[:use_creator_avatar] == true
- stars = true unless local_assigns[:stars] == false
+- forks = false unless local_assigns[:forks] == true
- ci = false unless local_assigns[:ci] == true
- skip_namespace = false unless local_assigns[:skip_namespace] == true
+- show_last_commit_as_description = false unless local_assigns[:show_last_commit_as_description] == true
%ul.projects-list
- projects.each_with_index do |project, i|
- css_class = (i >= projects_limit) ? 'hide' : nil
= render "shared/projects/project", project: project, skip_namespace: skip_namespace,
- avatar: avatar, stars: stars, css_class: css_class, ci: ci
+ avatar: avatar, stars: stars, css_class: css_class, ci: ci, use_creator_avatar: use_creator_avatar,
+ forks: forks, show_last_commit_as_description: show_last_commit_as_description
- if projects.size > projects_limit
%li.bottom.center
diff --git a/app/views/shared/projects/_project.html.haml b/app/views/shared/projects/_project.html.haml
index 5db8056b77c..2aeeed63c95 100644
--- a/app/views/shared/projects/_project.html.haml
+++ b/app/views/shared/projects/_project.html.haml
@@ -1,9 +1,11 @@
- avatar = true unless local_assigns[:avatar] == false
- stars = true unless local_assigns[:stars] == false
+- forks = false unless local_assigns[:forks] == true
- ci = false unless local_assigns[:ci] == true
- skip_namespace = false unless local_assigns[:skip_namespace] == true
- css_class = '' unless local_assigns[:css_class]
-- css_class += " no-description" unless project.description.present?
+- show_last_commit_as_description = false unless local_assigns[:show_last_commit_as_description] == true
+- css_class += " no-description" if project.description.blank? && !show_last_commit_as_description
- ci_commit = project.ci_commit(project.commit.sha) if ci && !project.empty_repo? && project.commit
- cache_key = [project.namespace, project, controller.controller_name, controller.action_name, current_application_settings, 'v2.2']
- cache_key.push(ci_commit.status) if ci_commit
@@ -13,7 +15,10 @@
= link_to project_path(project), class: dom_class(project) do
- if avatar
.dash-project-avatar
- = project_icon(project, alt: '', class: 'avatar project-avatar s46')
+ - if use_creator_avatar
+ = image_tag avatar_icon(project.creator.email, 46), class: "avatar s46", alt:''
+ - else
+ = project_icon(project, alt: '', class: 'avatar project-avatar s46')
%span.project-full-name
%span.namespace-name
- if project.namespace && !skip_namespace
@@ -26,10 +31,18 @@
- if ci_commit
= render_ci_status(ci_commit)
&nbsp;
+ - if forks
+ %span
+ = icon('code-fork')
+ = project.forks_count
- if stars
%span
- %i.fa.fa-star
+ = icon('star')
= project.star_count
- - if project.description.present?
+ - if show_last_commit_as_description
+ .project-description
+ = link_to_gfm project.commit.title, namespace_project_commit_path(project.namespace, project, project.commit),
+ class: "commit-row-message"
+ - elsif project.description.present?
.project-description
= markdown(project.description, pipeline: :description)
diff --git a/config/routes.rb b/config/routes.rb
index 75418db8d25..fdfdb449085 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -554,7 +554,7 @@ Rails.application.routes.draw do
end
end
- resource :fork, only: [:new, :create]
+ resources :forks, only: [:index, :new, :create]
resource :import, only: [:new, :create, :show]
resources :refs, only: [] do
diff --git a/features/project/fork.feature b/features/project/fork.feature
index 37cd53ee977..12695204e47 100644
--- a/features/project/fork.feature
+++ b/features/project/fork.feature
@@ -25,3 +25,18 @@ Feature: Project Fork
Then I should see "New merge request"
And I click link "New merge request"
Then I should see the new merge request page for my namespace
+
+ Scenario: Viewing forks of a Project
+ Given I click link "Fork"
+ When I fork to my namespace
+ And I visit the forks page of the "Shop" project
+ Then I should see my fork on the list
+
+ Scenario: Viewing private forks of a Project
+ Given There is an existent fork of the "Shop" project
+ And I click link "Fork"
+ When I fork to my namespace
+ And I visit the forks page of the "Shop" project
+ Then I should see my fork on the list
+ And I should not see the other fork listed
+ And I should see a private fork notice
diff --git a/features/steps/project/fork.rb b/features/steps/project/fork.rb
index e98bd51ca89..5810276ced3 100644
--- a/features/steps/project/fork.rb
+++ b/features/steps/project/fork.rb
@@ -49,4 +49,29 @@ class Spinach::Features::ProjectFork < Spinach::FeatureSteps
step 'I should see the new merge request page for my namespace' do
current_path.should have_content(/#{current_user.namespace.name}/i)
end
+
+ step 'I visit the forks page of the "Shop" project' do
+ @project = Project.where(name: 'Shop').last
+ visit namespace_project_forks_path(@project.namespace, @project)
+ end
+
+ step 'I should see my fork on the list' do
+ page.within('.projects-list-holder') do
+ project = @user.fork_of(@project)
+ expect(page).to have_content("#{project.namespace.human_name} / #{project.name}")
+ end
+ end
+
+ step 'There is an existent fork of the "Shop" project' do
+ user = create(:user, name: 'Mike')
+ @forked_project = Projects::ForkService.new(@project, user).execute
+ end
+
+ step 'I should not see the other fork listed' do
+ expect(page).not_to have_content("#{@forked_project.namespace.human_name} / #{@forked_project.name}")
+ end
+
+ step 'I should see a private fork notice' do
+ expect(page).to have_content("1 private fork")
+ end
end
diff --git a/features/steps/project/forked_merge_requests.rb b/features/steps/project/forked_merge_requests.rb
index cbdce78dc0c..7e4425ff662 100644
--- a/features/steps/project/forked_merge_requests.rb
+++ b/features/steps/project/forked_merge_requests.rb
@@ -43,7 +43,9 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps
expect(page).to have_css("h3.page-title", text: "New Merge Request")
- fill_in "merge_request_title", with: "Merge Request On Forked Project"
+ page.within 'form#new_merge_request' do
+ fill_in "merge_request_title", with: "Merge Request On Forked Project"
+ end
end
step 'I submit the merge request' do
diff --git a/spec/routing/project_routing_spec.rb b/spec/routing/project_routing_spec.rb
index 22ba25217f0..22937226fce 100644
--- a/spec/routing/project_routing_spec.rb
+++ b/spec/routing/project_routing_spec.rb
@@ -496,11 +496,11 @@ end
describe Projects::ForksController, 'routing' do
it 'to #new' do
- expect(get('/gitlab/gitlabhq/fork/new')).to route_to('projects/forks#new', namespace_id: 'gitlab', project_id: 'gitlabhq')
+ expect(get('/gitlab/gitlabhq/forks/new')).to route_to('projects/forks#new', namespace_id: 'gitlab', project_id: 'gitlabhq')
end
it 'to #create' do
- expect(post('/gitlab/gitlabhq/fork')).to route_to('projects/forks#create', namespace_id: 'gitlab', project_id: 'gitlabhq')
+ expect(post('/gitlab/gitlabhq/forks')).to route_to('projects/forks#create', namespace_id: 'gitlab', project_id: 'gitlabhq')
end
end