From 2ec2a906b552d5f4a486130b88a39a4a14e7b28f Mon Sep 17 00:00:00 2001 From: Heinrich Lee Yu Date: Fri, 26 Oct 2018 14:02:20 +0800 Subject: [PATCH 1/7] Add group projects API options for including shared and subgroups --- lib/api/groups.rb | 14 +++++++++++++- spec/requests/api/groups_spec.rb | 26 ++++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/lib/api/groups.rb b/lib/api/groups.rb index 64b998ab455..12227c886b2 100644 --- a/lib/api/groups.rb +++ b/lib/api/groups.rb @@ -60,7 +60,17 @@ module API def find_group_projects(params) group = find_group!(params[:id]) - projects = GroupProjectsFinder.new(group: group, current_user: current_user, params: project_finder_params).execute + options = { + only_owned: !params[:include_shared], + include_subgroups: params[:include_subgroups] + } + + projects = GroupProjectsFinder.new( + group: group, + current_user: current_user, + params: project_finder_params, + options: options + ).execute projects = projects.with_issues_available_for_user(current_user) if params[:with_issues_enabled] projects = projects.with_merge_requests_enabled if params[:with_merge_requests_enabled] projects = reorder_projects(projects) @@ -201,6 +211,8 @@ module API optional :starred, type: Boolean, default: false, desc: 'Limit by starred status' optional :with_issues_enabled, type: Boolean, default: false, desc: 'Limit by enabled issues feature' optional :with_merge_requests_enabled, type: Boolean, default: false, desc: 'Limit by enabled merge requests feature' + optional :include_subgroups, type: Boolean, default: false, desc: 'Includes projects in subgroups of this group' + optional :include_shared, type: Boolean, default: true, desc: 'Include projects shared to this group' use :pagination use :with_custom_attributes diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb index 3802b5c6848..fe47d23ad3c 100644 --- a/spec/requests/api/groups_spec.rb +++ b/spec/requests/api/groups_spec.rb @@ -502,6 +502,32 @@ describe API::Groups do expect(json_response.first['name']).to eq(public_project.name) end + it 'returns projects excluding shared' do + create(:project_group_link, project: create(:project), group: group1) + create(:project_group_link, project: create(:project), group: group1) + create(:project_group_link, project: create(:project), group: group1) + + get api("/groups/#{group1.id}/projects", user1), include_shared: false + + expect(response).to have_gitlab_http_status(200) + expect(response).to include_pagination_headers + expect(json_response).to be_an(Array) + expect(json_response.length).to eq(2) + end + + it 'returns projects including those in subgroups' do + subgroup = create(:group, parent: group1) + create(:project, group: subgroup) + create(:project, group: subgroup) + + get api("/groups/#{group1.id}/projects", user1), include_subgroups: true + + expect(response).to have_gitlab_http_status(200) + expect(response).to include_pagination_headers + expect(json_response).to be_an(Array) + expect(json_response.length).to eq(4) + end + it "does not return a non existing group" do get api("/groups/1328/projects", user1) From fbe91125bed5d8f0ca98833eca3d33f531c79922 Mon Sep 17 00:00:00 2001 From: Heinrich Lee Yu Date: Fri, 26 Oct 2018 14:05:34 +0800 Subject: [PATCH 2/7] Update project selection dropdown API params --- app/assets/javascripts/boards/components/project_select.vue | 6 +++++- app/assets/javascripts/project_select.js | 4 ++++ app/views/groups/issues.html.haml | 2 +- app/views/groups/merge_requests.html.haml | 2 +- app/views/shared/_new_project_item_select.html.haml | 2 +- 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/boards/components/project_select.vue b/app/assets/javascripts/boards/components/project_select.vue index 83e6e237757..151f814af35 100644 --- a/app/assets/javascripts/boards/components/project_select.vue +++ b/app/assets/javascripts/boards/components/project_select.vue @@ -48,7 +48,11 @@ export default { selectable: true, data: (term, callback) => { this.loading = true; - return Api.groupProjects(this.groupId, term, { with_issues_enabled: true }, projects => { + return Api.groupProjects(this.groupId, term, { + with_issues_enabled: true, + include_shared: false, + include_subgroups: true + }, projects => { this.loading = false; callback(projects); }); diff --git a/app/assets/javascripts/project_select.js b/app/assets/javascripts/project_select.js index f1fff173619..ce407c60724 100644 --- a/app/assets/javascripts/project_select.js +++ b/app/assets/javascripts/project_select.js @@ -14,6 +14,8 @@ export default function projectSelect() { this.orderBy = $(select).data('orderBy') || 'id'; this.withIssuesEnabled = $(select).data('withIssuesEnabled'); this.withMergeRequestsEnabled = $(select).data('withMergeRequestsEnabled'); + this.includeShared = $(select).data('includeShared') === undefined ? true : $(select).data('includeShared'); + this.includeProjectsInSubgroups = $(select).data('includeProjectsInSubgroups') || false; this.allowClear = $(select).data('allowClear') || false; placeholder = 'Search for project'; @@ -54,6 +56,8 @@ export default function projectSelect() { { with_issues_enabled: _this.withIssuesEnabled, with_merge_requests_enabled: _this.withMergeRequestsEnabled, + include_shared: _this.includeShared, + include_subgroups: _this.includeProjectsInSubgroups, }, projectsCallback, ); diff --git a/app/views/groups/issues.html.haml b/app/views/groups/issues.html.haml index 5e1ae1dbe38..b0fa7bddf6d 100644 --- a/app/views/groups/issues.html.haml +++ b/app/views/groups/issues.html.haml @@ -9,7 +9,7 @@ = render 'shared/issuable/nav', type: :issues .nav-controls = render 'shared/issuable/feed_buttons' - = render 'shared/new_project_item_select', path: 'issues/new', label: "New issue", type: :issues, with_feature_enabled: 'issues' + = render 'shared/new_project_item_select', path: 'issues/new', label: "New issue", type: :issues, with_feature_enabled: 'issues', include_shared: false, include_projects_in_subgroups: true = render 'shared/issuable/search_bar', type: :issues diff --git a/app/views/groups/merge_requests.html.haml b/app/views/groups/merge_requests.html.haml index e2a317dbf67..da094c96714 100644 --- a/app/views/groups/merge_requests.html.haml +++ b/app/views/groups/merge_requests.html.haml @@ -7,7 +7,7 @@ = render 'shared/issuable/nav', type: :merge_requests - if current_user .nav-controls - = render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request", type: :merge_requests, with_feature_enabled: 'merge_requests' + = render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request", type: :merge_requests, with_feature_enabled: 'merge_requests', include_shared: false, include_projects_in_subgroups: true = render 'shared/issuable/search_bar', type: :merge_requests diff --git a/app/views/shared/_new_project_item_select.html.haml b/app/views/shared/_new_project_item_select.html.haml index 9bc67a7c715..89cedc09fd1 100644 --- a/app/views/shared/_new_project_item_select.html.haml +++ b/app/views/shared/_new_project_item_select.html.haml @@ -2,6 +2,6 @@ .project-item-select-holder.btn-group %a.btn.btn-success.new-project-item-link.qa-new-project-item-link{ href: '', data: { label: local_assigns[:label], type: local_assigns[:type] } } = icon('spinner spin') - = project_select_tag :project_path, class: "project-item-select", data: { include_groups: local_assigns[:include_groups], order_by: 'last_activity_at', relative_path: local_assigns[:path] }, with_feature_enabled: local_assigns[:with_feature_enabled] + = project_select_tag :project_path, class: "project-item-select", data: { include_groups: local_assigns[:include_groups], order_by: 'last_activity_at', relative_path: local_assigns[:path], include_shared: local_assigns[:include_shared], include_projects_in_subgroups: local_assigns[:include_projects_in_subgroups] }, with_feature_enabled: local_assigns[:with_feature_enabled] %button.btn.btn-success.new-project-item-select-button.qa-new-project-item-select-button = icon('caret-down') From e6a021f7b4d9b846cefae7e7a1cee8310cc859ed Mon Sep 17 00:00:00 2001 From: Heinrich Lee Yu Date: Fri, 26 Oct 2018 14:15:23 +0800 Subject: [PATCH 3/7] Add changelog entry --- .../52453-show-subgroups-in-group-create-issue.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 changelogs/unreleased/52453-show-subgroups-in-group-create-issue.yml diff --git a/changelogs/unreleased/52453-show-subgroups-in-group-create-issue.yml b/changelogs/unreleased/52453-show-subgroups-in-group-create-issue.yml new file mode 100644 index 00000000000..d5877e96d07 --- /dev/null +++ b/changelogs/unreleased/52453-show-subgroups-in-group-create-issue.yml @@ -0,0 +1,5 @@ +--- +title: Fix project selector consistency in groups issues / MRs / boards pages +merge_request: 22612 +author: Heinrich Lee Yu +type: fixed From b12456049e4e701b2436beacfc88c74922d7524f Mon Sep 17 00:00:00 2001 From: Heinrich Lee Yu Date: Fri, 26 Oct 2018 14:34:31 +0800 Subject: [PATCH 4/7] Change param name for consistency --- app/assets/javascripts/boards/components/project_select.vue | 2 +- app/assets/javascripts/project_select.js | 4 ++-- app/views/groups/issues.html.haml | 2 +- app/views/groups/merge_requests.html.haml | 2 +- app/views/shared/_new_project_item_select.html.haml | 2 +- lib/api/groups.rb | 4 ++-- spec/requests/api/groups_spec.rb | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/app/assets/javascripts/boards/components/project_select.vue b/app/assets/javascripts/boards/components/project_select.vue index 151f814af35..c8783bf41f1 100644 --- a/app/assets/javascripts/boards/components/project_select.vue +++ b/app/assets/javascripts/boards/components/project_select.vue @@ -50,7 +50,7 @@ export default { this.loading = true; return Api.groupProjects(this.groupId, term, { with_issues_enabled: true, - include_shared: false, + with_shared: false, include_subgroups: true }, projects => { this.loading = false; diff --git a/app/assets/javascripts/project_select.js b/app/assets/javascripts/project_select.js index ce407c60724..6c5f1198d27 100644 --- a/app/assets/javascripts/project_select.js +++ b/app/assets/javascripts/project_select.js @@ -14,7 +14,7 @@ export default function projectSelect() { this.orderBy = $(select).data('orderBy') || 'id'; this.withIssuesEnabled = $(select).data('withIssuesEnabled'); this.withMergeRequestsEnabled = $(select).data('withMergeRequestsEnabled'); - this.includeShared = $(select).data('includeShared') === undefined ? true : $(select).data('includeShared'); + this.withShared = $(select).data('withShared') === undefined ? true : $(select).data('withShared'); this.includeProjectsInSubgroups = $(select).data('includeProjectsInSubgroups') || false; this.allowClear = $(select).data('allowClear') || false; @@ -56,7 +56,7 @@ export default function projectSelect() { { with_issues_enabled: _this.withIssuesEnabled, with_merge_requests_enabled: _this.withMergeRequestsEnabled, - include_shared: _this.includeShared, + with_shared: _this.withShared, include_subgroups: _this.includeProjectsInSubgroups, }, projectsCallback, diff --git a/app/views/groups/issues.html.haml b/app/views/groups/issues.html.haml index b0fa7bddf6d..91d17cfd745 100644 --- a/app/views/groups/issues.html.haml +++ b/app/views/groups/issues.html.haml @@ -9,7 +9,7 @@ = render 'shared/issuable/nav', type: :issues .nav-controls = render 'shared/issuable/feed_buttons' - = render 'shared/new_project_item_select', path: 'issues/new', label: "New issue", type: :issues, with_feature_enabled: 'issues', include_shared: false, include_projects_in_subgroups: true + = render 'shared/new_project_item_select', path: 'issues/new', label: "New issue", type: :issues, with_feature_enabled: 'issues', with_shared: false, include_projects_in_subgroups: true = render 'shared/issuable/search_bar', type: :issues diff --git a/app/views/groups/merge_requests.html.haml b/app/views/groups/merge_requests.html.haml index da094c96714..a9ce2fe5ab0 100644 --- a/app/views/groups/merge_requests.html.haml +++ b/app/views/groups/merge_requests.html.haml @@ -7,7 +7,7 @@ = render 'shared/issuable/nav', type: :merge_requests - if current_user .nav-controls - = render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request", type: :merge_requests, with_feature_enabled: 'merge_requests', include_shared: false, include_projects_in_subgroups: true + = render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request", type: :merge_requests, with_feature_enabled: 'merge_requests', with_shared: false, include_projects_in_subgroups: true = render 'shared/issuable/search_bar', type: :merge_requests diff --git a/app/views/shared/_new_project_item_select.html.haml b/app/views/shared/_new_project_item_select.html.haml index 89cedc09fd1..ffa61c9d1a9 100644 --- a/app/views/shared/_new_project_item_select.html.haml +++ b/app/views/shared/_new_project_item_select.html.haml @@ -2,6 +2,6 @@ .project-item-select-holder.btn-group %a.btn.btn-success.new-project-item-link.qa-new-project-item-link{ href: '', data: { label: local_assigns[:label], type: local_assigns[:type] } } = icon('spinner spin') - = project_select_tag :project_path, class: "project-item-select", data: { include_groups: local_assigns[:include_groups], order_by: 'last_activity_at', relative_path: local_assigns[:path], include_shared: local_assigns[:include_shared], include_projects_in_subgroups: local_assigns[:include_projects_in_subgroups] }, with_feature_enabled: local_assigns[:with_feature_enabled] + = project_select_tag :project_path, class: "project-item-select", data: { include_groups: local_assigns[:include_groups], order_by: 'last_activity_at', relative_path: local_assigns[:path], with_shared: local_assigns[:with_shared], include_projects_in_subgroups: local_assigns[:include_projects_in_subgroups] }, with_feature_enabled: local_assigns[:with_feature_enabled] %button.btn.btn-success.new-project-item-select-button.qa-new-project-item-select-button = icon('caret-down') diff --git a/lib/api/groups.rb b/lib/api/groups.rb index 12227c886b2..b3d10721692 100644 --- a/lib/api/groups.rb +++ b/lib/api/groups.rb @@ -61,7 +61,7 @@ module API def find_group_projects(params) group = find_group!(params[:id]) options = { - only_owned: !params[:include_shared], + only_owned: !params[:with_shared], include_subgroups: params[:include_subgroups] } @@ -211,8 +211,8 @@ module API optional :starred, type: Boolean, default: false, desc: 'Limit by starred status' optional :with_issues_enabled, type: Boolean, default: false, desc: 'Limit by enabled issues feature' optional :with_merge_requests_enabled, type: Boolean, default: false, desc: 'Limit by enabled merge requests feature' + optional :with_shared, type: Boolean, default: true, desc: 'Include projects shared to this group' optional :include_subgroups, type: Boolean, default: false, desc: 'Includes projects in subgroups of this group' - optional :include_shared, type: Boolean, default: true, desc: 'Include projects shared to this group' use :pagination use :with_custom_attributes diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb index fe47d23ad3c..ea5a3c44a9a 100644 --- a/spec/requests/api/groups_spec.rb +++ b/spec/requests/api/groups_spec.rb @@ -507,7 +507,7 @@ describe API::Groups do create(:project_group_link, project: create(:project), group: group1) create(:project_group_link, project: create(:project), group: group1) - get api("/groups/#{group1.id}/projects", user1), include_shared: false + get api("/groups/#{group1.id}/projects", user1), with_shared: false expect(response).to have_gitlab_http_status(200) expect(response).to include_pagination_headers From cc4b215153b5d9fd0ec0d7aff0ba11089a38c5fd Mon Sep 17 00:00:00 2001 From: Heinrich Lee Yu Date: Fri, 26 Oct 2018 18:26:05 +0800 Subject: [PATCH 5/7] Add :nested_groups metadata to tests using subgroups --- spec/requests/api/groups_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/requests/api/groups_spec.rb b/spec/requests/api/groups_spec.rb index ea5a3c44a9a..688d91113ad 100644 --- a/spec/requests/api/groups_spec.rb +++ b/spec/requests/api/groups_spec.rb @@ -490,7 +490,7 @@ describe API::Groups do expect(json_response.first['visibility']).not_to be_present end - it 'filters the groups projects' do + it "filters the groups projects" do public_project = create(:project, :public, path: 'test1', group: group1) get api("/groups/#{group1.id}/projects", user1), visibility: 'public' @@ -502,7 +502,7 @@ describe API::Groups do expect(json_response.first['name']).to eq(public_project.name) end - it 'returns projects excluding shared' do + it "returns projects excluding shared" do create(:project_group_link, project: create(:project), group: group1) create(:project_group_link, project: create(:project), group: group1) create(:project_group_link, project: create(:project), group: group1) @@ -515,7 +515,7 @@ describe API::Groups do expect(json_response.length).to eq(2) end - it 'returns projects including those in subgroups' do + it "returns projects including those in subgroups", :nested_groups do subgroup = create(:group, parent: group1) create(:project, group: subgroup) create(:project, group: subgroup) From 911d835650f2a624dbcbf96a8a9a6d700cf13a86 Mon Sep 17 00:00:00 2001 From: Heinrich Lee Yu Date: Fri, 26 Oct 2018 18:34:47 +0800 Subject: [PATCH 6/7] Add documentation --- doc/api/groups.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/doc/api/groups.md b/doc/api/groups.md index a9462fc413f..59444a98086 100644 --- a/doc/api/groups.md +++ b/doc/api/groups.md @@ -152,8 +152,10 @@ Parameters: | `simple` | boolean | no | Return only the ID, URL, name, and path of each project | | `owned` | boolean | no | Limit by projects owned by the current user | | `starred` | boolean | no | Limit by projects starred by the current user | -| `with_issues_enabled` | boolean | no | Limit by enabled issues feature | -| `with_merge_requests_enabled` | boolean | no | Limit by enabled merge requests feature | +| `with_issues_enabled` | boolean | no | Limit by projects with issues feature enabled. Default is `false` | +| `with_merge_requests_enabled` | boolean | no | Limit by projects with merge requests feature enabled. Default is `false` | +| `with_shared` | boolean | no | Include projects shared to this group. Default is `true` | +| `include_subgroups` | boolean | no | Include projects in subgroups of this group. Default is `false` | | `with_custom_attributes` | boolean | no | Include [custom attributes](custom_attributes.md) in response (admins only) | Example response: From c216b25dfeccfd20de56ea2f0eb467a00f5e4933 Mon Sep 17 00:00:00 2001 From: Heinrich Lee Yu Date: Thu, 1 Nov 2018 08:32:01 +0800 Subject: [PATCH 7/7] Prettify JS --- .../boards/components/project_select.vue | 21 ++++++++++++------- app/assets/javascripts/project_select.js | 3 ++- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/app/assets/javascripts/boards/components/project_select.vue b/app/assets/javascripts/boards/components/project_select.vue index c8783bf41f1..645eda4ae11 100644 --- a/app/assets/javascripts/boards/components/project_select.vue +++ b/app/assets/javascripts/boards/components/project_select.vue @@ -48,14 +48,19 @@ export default { selectable: true, data: (term, callback) => { this.loading = true; - return Api.groupProjects(this.groupId, term, { - with_issues_enabled: true, - with_shared: false, - include_subgroups: true - }, projects => { - this.loading = false; - callback(projects); - }); + return Api.groupProjects( + this.groupId, + term, + { + with_issues_enabled: true, + with_shared: false, + include_subgroups: true, + }, + projects => { + this.loading = false; + callback(projects); + }, + ); }, renderRow(project) { return ` diff --git a/app/assets/javascripts/project_select.js b/app/assets/javascripts/project_select.js index 6c5f1198d27..a33835472bb 100644 --- a/app/assets/javascripts/project_select.js +++ b/app/assets/javascripts/project_select.js @@ -14,7 +14,8 @@ export default function projectSelect() { this.orderBy = $(select).data('orderBy') || 'id'; this.withIssuesEnabled = $(select).data('withIssuesEnabled'); this.withMergeRequestsEnabled = $(select).data('withMergeRequestsEnabled'); - this.withShared = $(select).data('withShared') === undefined ? true : $(select).data('withShared'); + this.withShared = + $(select).data('withShared') === undefined ? true : $(select).data('withShared'); this.includeProjectsInSubgroups = $(select).data('includeProjectsInSubgroups') || false; this.allowClear = $(select).data('allowClear') || false;