diff options
18 files changed, 62 insertions, 45 deletions
diff --git a/app/assets/javascripts/boards/components/board_sidebar.js b/app/assets/javascripts/boards/components/board_sidebar.js index a44969272a1..c4ee4f6c855 100644 --- a/app/assets/javascripts/boards/components/board_sidebar.js +++ b/app/assets/javascripts/boards/components/board_sidebar.js @@ -60,10 +60,6 @@ gl.issueBoards.BoardSidebar = Vue.extend({ this.issue = this.detail.issue; this.list = this.detail.list; - - this.$nextTick(() => { - this.endpoint = this.$refs.assigneeDropdown.dataset.issueUpdate; - }); }, deep: true }, @@ -91,7 +87,7 @@ gl.issueBoards.BoardSidebar = Vue.extend({ saveAssignees () { this.loadingAssignees = true; - gl.issueBoards.BoardsStore.detail.issue.update(this.endpoint) + gl.issueBoards.BoardsStore.detail.issue.update() .then(() => { this.loadingAssignees = false; }) diff --git a/app/assets/javascripts/boards/components/issue_card_inner.js b/app/assets/javascripts/boards/components/issue_card_inner.js index 8aee5b23c76..84fe9b1288a 100644 --- a/app/assets/javascripts/boards/components/issue_card_inner.js +++ b/app/assets/javascripts/boards/components/issue_card_inner.js @@ -68,15 +68,6 @@ gl.issueBoards.IssueCardInner = Vue.extend({ return this.issue.assignees.length > this.numberOverLimit; }, - cardUrl() { - let baseUrl = this.issueLinkBase; - - if (this.groupId && this.issue.project) { - baseUrl = this.issueLinkBase.replace(':project_path', this.issue.project.path); - } - - return `${baseUrl}/${this.issue.iid}`; - }, issueId() { if (this.issue.iid) { return `#${this.issue.iid}`; @@ -153,13 +144,13 @@ gl.issueBoards.IssueCardInner = Vue.extend({ /> <a class="js-no-trigger" - :href="cardUrl" + :href="issue.path" :title="issue.title">{{ issue.title }}</a> <span class="card-number" v-if="issueId" > - <template v-if="groupId && issue.project">{{issue.project.path}}</template>{{ issueId }} + {{ issue.referencePath }} </span> </h4> <div class="card-assignee"> diff --git a/app/assets/javascripts/boards/components/sidebar/remove_issue.js b/app/assets/javascripts/boards/components/sidebar/remove_issue.js index 09c683ff621..0a0820ec5fd 100644 --- a/app/assets/javascripts/boards/components/sidebar/remove_issue.js +++ b/app/assets/javascripts/boards/components/sidebar/remove_issue.js @@ -17,14 +17,10 @@ gl.issueBoards.RemoveIssueBtn = Vue.extend({ type: Object, required: true, }, - issueUpdate: { - type: String, - required: true, - }, }, computed: { updateUrl() { - return this.issueUpdate.replace(':project_path', this.issue.project.path); + return this.issue.path; }, }, methods: { diff --git a/app/assets/javascripts/boards/filtered_search_boards.js b/app/assets/javascripts/boards/filtered_search_boards.js index fb40b9f5565..70367c4f711 100644 --- a/app/assets/javascripts/boards/filtered_search_boards.js +++ b/app/assets/javascripts/boards/filtered_search_boards.js @@ -6,6 +6,7 @@ export default class FilteredSearchBoards extends FilteredSearchManager { constructor(store, updateUrl = false, cantEdit = []) { super({ page: 'boards', + isGroupDecendent: true, stateFiltersSelector: '.issues-state-filters', }); diff --git a/app/assets/javascripts/boards/models/issue.js b/app/assets/javascripts/boards/models/issue.js index 4c5079efc8b..85f98615cf4 100644 --- a/app/assets/javascripts/boards/models/issue.js +++ b/app/assets/javascripts/boards/models/issue.js @@ -23,6 +23,8 @@ class ListIssue { }; this.isLoading = {}; this.sidebarInfoEndpoint = obj.issue_sidebar_endpoint; + this.referencePath = obj.reference_path; + this.path = obj.real_path; this.toggleSubscriptionEndpoint = obj.toggle_subscription_endpoint; this.milestone_id = obj.milestone_id; this.project_id = obj.project_id; @@ -98,7 +100,7 @@ class ListIssue { this.isLoading[key] = value; } - update (url) { + update () { const data = { issue: { milestone_id: this.milestone ? this.milestone.id : null, @@ -113,7 +115,7 @@ class ListIssue { } const projectPath = this.project ? this.project.path : ''; - return Vue.http.patch(url.replace(':project_path', projectPath), data); + return Vue.http.patch(this.path + '.json', data); } } diff --git a/app/controllers/boards/issues_controller.rb b/app/controllers/boards/issues_controller.rb index 19dbee84c11..7d7ff217e5d 100644 --- a/app/controllers/boards/issues_controller.rb +++ b/app/controllers/boards/issues_controller.rb @@ -96,7 +96,8 @@ module Boards resource.as_json( only: [:id, :iid, :project_id, :title, :confidential, :due_date, :relative_position], labels: true, - sidebar_endpoints: true, + issue_endpoints: true, + include_full_project_path: board.group_board?, include: { project: { only: [:id, :path] }, assignees: { only: [:id, :name, :username], methods: [:avatar_url] }, diff --git a/app/controllers/groups/milestones_controller.rb b/app/controllers/groups/milestones_controller.rb index acf6aaf57f4..5903689dc62 100644 --- a/app/controllers/groups/milestones_controller.rb +++ b/app/controllers/groups/milestones_controller.rb @@ -12,7 +12,7 @@ class Groups::MilestonesController < Groups::ApplicationController @milestones = Kaminari.paginate_array(milestones).page(params[:page]) end format.json do - render json: milestones.map { |m| m.for_display.slice(:title, :name) } + render json: milestones.map { |m| m.for_display.slice(:id, :title, :name) } end end end diff --git a/app/models/issue.rb b/app/models/issue.rb index 13abc6c1a0d..13d9e42bcc8 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -272,11 +272,17 @@ class Issue < ActiveRecord::Base def as_json(options = {}) super(options).tap do |json| - if options.key?(:sidebar_endpoints) && project + if options.key?(:issue_endpoints) && project url_helper = Gitlab::Routing.url_helpers - json.merge!(issue_sidebar_endpoint: url_helper.project_issue_path(project, self, format: :json, serializer: 'sidebar'), - toggle_subscription_endpoint: url_helper.toggle_subscription_project_issue_path(project, self)) + issue_reference = options[:include_full_project_path] ? to_reference(full: true) : to_reference + + json.merge!( + reference_path: issue_reference, + real_path: url_helper.project_issue_path(project, self), + issue_sidebar_endpoint: url_helper.project_issue_path(project, self, format: :json, serializer: 'sidebar'), + toggle_subscription_endpoint: url_helper.toggle_subscription_project_issue_path(project, self) + ) end if options.key?(:labels) diff --git a/app/services/boards/issues/list_service.rb b/app/services/boards/issues/list_service.rb index ecd74b74f8a..8a1796a1096 100644 --- a/app/services/boards/issues/list_service.rb +++ b/app/services/boards/issues/list_service.rb @@ -35,6 +35,7 @@ module Boards def filter_params set_parent set_state + set_scope params end @@ -51,6 +52,10 @@ module Boards params[:state] = list && list.closed? ? 'closed' : 'opened' end + def set_scope + params[:include_subgroups] = true if board.group_board? + end + def board_label_ids @board_label_ids ||= board.lists.movable.pluck(:label_id) end diff --git a/app/services/issuable_base_service.rb b/app/services/issuable_base_service.rb index 91ec702fbc6..1f67e3ecf9d 100644 --- a/app/services/issuable_base_service.rb +++ b/app/services/issuable_base_service.rb @@ -51,9 +51,10 @@ class IssuableBaseService < BaseService return unless milestone_id params[:milestone_id] = '' if milestone_id == IssuableFinder::NONE + group_ids = project.group&.self_and_ancestors&.pluck(:id) milestone = - Milestone.for_projects_and_groups([project.id], [project.group&.id]).find_by_id(milestone_id) + Milestone.for_projects_and_groups([project.id], group_ids).find_by_id(milestone_id) params[:milestone_id] = '' unless milestone end diff --git a/app/views/shared/boards/components/_sidebar.html.haml b/app/views/shared/boards/components/_sidebar.html.haml index 8e5e32e9f16..b385cc3f962 100644 --- a/app/views/shared/boards/components/_sidebar.html.haml +++ b/app/views/shared/boards/components/_sidebar.html.haml @@ -22,6 +22,6 @@ = render "shared/boards/components/sidebar/labels" = render "shared/boards/components/sidebar/notifications" %remove-btn{ ":issue" => "issue", - ":issue-update" => "'#{build_issue_link_base}/' + issue.iid + '.json'", + ":issue-update" => "issue.sidebarInfoEndpoint", ":list" => "list", "v-if" => "canRemove" } diff --git a/app/views/shared/boards/components/sidebar/_assignee.html.haml b/app/views/shared/boards/components/sidebar/_assignee.html.haml index 3d2e8471a60..1374da9d82c 100644 --- a/app/views/shared/boards/components/sidebar/_assignee.html.haml +++ b/app/views/shared/boards/components/sidebar/_assignee.html.haml @@ -21,8 +21,7 @@ .dropdown - dropdown_options = issue_assignees_dropdown_options %button.dropdown-menu-toggle.js-user-search.js-author-search.js-multiselect.js-save-user-data.js-issue-board-sidebar{ type: 'button', ref: 'assigneeDropdown', data: board_sidebar_user_data, - ":data-issuable-id" => "issue.iid", - ":data-issue-update" => "'#{build_issue_link_base}/' + issue.iid + '.json'" } + ":data-issuable-id" => "issue.iid" } = dropdown_options[:title] = icon("chevron-down") .dropdown-menu.dropdown-select.dropdown-menu-user.dropdown-menu-selectable.dropdown-menu-author diff --git a/app/views/shared/boards/components/sidebar/_due_date.html.haml b/app/views/shared/boards/components/sidebar/_due_date.html.haml index db794d6f855..c1a97269954 100644 --- a/app/views/shared/boards/components/sidebar/_due_date.html.haml +++ b/app/views/shared/boards/components/sidebar/_due_date.html.haml @@ -22,8 +22,7 @@ ":value" => "issue.dueDate" } .dropdown %button.dropdown-menu-toggle.js-due-date-select.js-issue-boards-due-date{ type: 'button', - data: { toggle: 'dropdown', field_name: "issue[due_date]", ability_name: "issue" }, - ":data-issue-update" => "'#{build_issue_link_base}/' + issue.iid + '.json'" } + data: { toggle: 'dropdown', field_name: "issue[due_date]", ability_name: "issue" }} %span.dropdown-toggle-text Due date = icon('chevron-down') .dropdown-menu.dropdown-menu-due-date diff --git a/app/views/shared/boards/components/sidebar/_labels.html.haml b/app/views/shared/boards/components/sidebar/_labels.html.haml index dfc0f9be321..3c514ededc5 100644 --- a/app/views/shared/boards/components/sidebar/_labels.html.haml +++ b/app/views/shared/boards/components/sidebar/_labels.html.haml @@ -26,8 +26,7 @@ project_id: @project&.try(:id), labels: labels_filter_path(false), namespace_path: @namespace_path, - project_path: @project.try(:path) }, - ":data-issue-update" => "'#{build_issue_link_base}/' + issue.iid + '.json'" } + project_path: @project.try(:path) }} %span.dropdown-toggle-text Label = icon('chevron-down') diff --git a/app/views/shared/boards/components/sidebar/_milestone.html.haml b/app/views/shared/boards/components/sidebar/_milestone.html.haml index d09c7c218e0..f51c4a97f2b 100644 --- a/app/views/shared/boards/components/sidebar/_milestone.html.haml +++ b/app/views/shared/boards/components/sidebar/_milestone.html.haml @@ -18,8 +18,7 @@ .dropdown %button.dropdown-menu-toggle.js-milestone-select.js-issue-board-sidebar{ type: "button", data: { toggle: "dropdown", show_no: "true", field_name: "issue[milestone_id]", milestones: milestones_filter_path(format: :json), ability_name: "issue", use_id: "true", default_no: "true" }, ":data-selected" => "milestoneTitle", - ":data-issuable-id" => "issue.iid", - ":data-issue-update" => "'#{build_issue_link_base}/' + issue.iid + '.json'" } + ":data-issuable-id" => "issue.iid" } Milestone = icon("chevron-down") .dropdown-menu.dropdown-select.dropdown-menu-selectable diff --git a/changelogs/unreleased/issue_44270.yml b/changelogs/unreleased/issue_44270.yml new file mode 100644 index 00000000000..6234162be30 --- /dev/null +++ b/changelogs/unreleased/issue_44270.yml @@ -0,0 +1,5 @@ +--- +title: Show issues of subgroups in group-level issue board +merge_request: +author: +type: changed diff --git a/spec/features/labels_hierarchy_spec.rb b/spec/features/labels_hierarchy_spec.rb index 99e1fb30d5b..d4a49a1cbf4 100644 --- a/spec/features/labels_hierarchy_spec.rb +++ b/spec/features/labels_hierarchy_spec.rb @@ -116,11 +116,13 @@ feature 'Labels Hierarchy', :js, :nested_groups do wait_for_requests if board - pending("Waiting for https://gitlab.com/gitlab-org/gitlab-ce/issues/44270") - select_label_on_dropdown(group_label_3.title) expect(page).to have_selector('.card-title') do |card| + expect(card).not_to have_selector('a', text: labeled_issue_2.title) + end + + expect(page).to have_selector('.card-title') do |card| expect(card).to have_selector('a', text: labeled_issue_3.title) end else diff --git a/spec/services/boards/issues/list_service_spec.rb b/spec/services/boards/issues/list_service_spec.rb index b4efa3e44b6..8d67bf67747 100644 --- a/spec/services/boards/issues/list_service_spec.rb +++ b/spec/services/boards/issues/list_service_spec.rb @@ -48,10 +48,8 @@ describe Boards::Issues::ListService do context 'when parent is a group' do let(:user) { create(:user) } - let(:group) { create(:group) } let(:project) { create(:project, :empty_repo, namespace: group) } let(:project1) { create(:project, :empty_repo, namespace: group) } - let(:board) { create(:board, group: group) } let(:m1) { create(:milestone, group: group) } let(:m2) { create(:milestone, group: group) } @@ -92,13 +90,30 @@ describe Boards::Issues::ListService do let!(:closed_issue4) { create(:labeled_issue, :closed, project: project1, labels: [p1, p1_project1]) } let!(:closed_issue5) { create(:labeled_issue, :closed, project: project1, labels: [development]) } - let(:parent) { group } - before do group.add_developer(user) end - it_behaves_like 'issues list service' + context 'and group has no parent' do + let(:parent) { group } + let(:group) { create(:group) } + let(:board) { create(:board, group: group) } + + it_behaves_like 'issues list service' + end + + context 'and group is an ancestor' do + let(:parent) { create(:group) } + let(:group) { create(:group, parent: parent) } + let!(:backlog) { create(:backlog_list, board: board) } + let(:board) { create(:board, group: parent) } + + before do + parent.add_developer(user) + end + + it_behaves_like 'issues list service' + end end end end |