Show issues of subgroups in group-level issue board
This commit is contained in:
parent
6b3585d8ea
commit
22423d2847
|
@ -60,10 +60,6 @@ gl.issueBoards.BoardSidebar = Vue.extend({
|
||||||
|
|
||||||
this.issue = this.detail.issue;
|
this.issue = this.detail.issue;
|
||||||
this.list = this.detail.list;
|
this.list = this.detail.list;
|
||||||
|
|
||||||
this.$nextTick(() => {
|
|
||||||
this.endpoint = this.$refs.assigneeDropdown.dataset.issueUpdate;
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
deep: true
|
deep: true
|
||||||
},
|
},
|
||||||
|
@ -91,7 +87,7 @@ gl.issueBoards.BoardSidebar = Vue.extend({
|
||||||
saveAssignees () {
|
saveAssignees () {
|
||||||
this.loadingAssignees = true;
|
this.loadingAssignees = true;
|
||||||
|
|
||||||
gl.issueBoards.BoardsStore.detail.issue.update(this.endpoint)
|
gl.issueBoards.BoardsStore.detail.issue.update()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.loadingAssignees = false;
|
this.loadingAssignees = false;
|
||||||
})
|
})
|
||||||
|
|
|
@ -68,15 +68,6 @@ gl.issueBoards.IssueCardInner = Vue.extend({
|
||||||
|
|
||||||
return this.issue.assignees.length > this.numberOverLimit;
|
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() {
|
issueId() {
|
||||||
if (this.issue.iid) {
|
if (this.issue.iid) {
|
||||||
return `#${this.issue.iid}`;
|
return `#${this.issue.iid}`;
|
||||||
|
@ -153,13 +144,13 @@ gl.issueBoards.IssueCardInner = Vue.extend({
|
||||||
/>
|
/>
|
||||||
<a
|
<a
|
||||||
class="js-no-trigger"
|
class="js-no-trigger"
|
||||||
:href="cardUrl"
|
:href="issue.path"
|
||||||
:title="issue.title">{{ issue.title }}</a>
|
:title="issue.title">{{ issue.title }}</a>
|
||||||
<span
|
<span
|
||||||
class="card-number"
|
class="card-number"
|
||||||
v-if="issueId"
|
v-if="issueId"
|
||||||
>
|
>
|
||||||
<template v-if="groupId && issue.project">{{issue.project.path}}</template>{{ issueId }}
|
{{ issue.referencePath }}
|
||||||
</span>
|
</span>
|
||||||
</h4>
|
</h4>
|
||||||
<div class="card-assignee">
|
<div class="card-assignee">
|
||||||
|
|
|
@ -17,14 +17,10 @@ gl.issueBoards.RemoveIssueBtn = Vue.extend({
|
||||||
type: Object,
|
type: Object,
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
issueUpdate: {
|
|
||||||
type: String,
|
|
||||||
required: true,
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
updateUrl() {
|
updateUrl() {
|
||||||
return this.issueUpdate.replace(':project_path', this.issue.project.path);
|
return this.issue.path;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
|
|
@ -6,6 +6,7 @@ export default class FilteredSearchBoards extends FilteredSearchManager {
|
||||||
constructor(store, updateUrl = false, cantEdit = []) {
|
constructor(store, updateUrl = false, cantEdit = []) {
|
||||||
super({
|
super({
|
||||||
page: 'boards',
|
page: 'boards',
|
||||||
|
isGroupDecendent: true,
|
||||||
stateFiltersSelector: '.issues-state-filters',
|
stateFiltersSelector: '.issues-state-filters',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,8 @@ class ListIssue {
|
||||||
};
|
};
|
||||||
this.isLoading = {};
|
this.isLoading = {};
|
||||||
this.sidebarInfoEndpoint = obj.issue_sidebar_endpoint;
|
this.sidebarInfoEndpoint = obj.issue_sidebar_endpoint;
|
||||||
|
this.referencePath = obj.reference_path;
|
||||||
|
this.path = obj.real_path;
|
||||||
this.toggleSubscriptionEndpoint = obj.toggle_subscription_endpoint;
|
this.toggleSubscriptionEndpoint = obj.toggle_subscription_endpoint;
|
||||||
this.milestone_id = obj.milestone_id;
|
this.milestone_id = obj.milestone_id;
|
||||||
this.project_id = obj.project_id;
|
this.project_id = obj.project_id;
|
||||||
|
@ -98,7 +100,7 @@ class ListIssue {
|
||||||
this.isLoading[key] = value;
|
this.isLoading[key] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
update (url) {
|
update () {
|
||||||
const data = {
|
const data = {
|
||||||
issue: {
|
issue: {
|
||||||
milestone_id: this.milestone ? this.milestone.id : null,
|
milestone_id: this.milestone ? this.milestone.id : null,
|
||||||
|
@ -113,7 +115,7 @@ class ListIssue {
|
||||||
}
|
}
|
||||||
|
|
||||||
const projectPath = this.project ? this.project.path : '';
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -96,7 +96,8 @@ module Boards
|
||||||
resource.as_json(
|
resource.as_json(
|
||||||
only: [:id, :iid, :project_id, :title, :confidential, :due_date, :relative_position],
|
only: [:id, :iid, :project_id, :title, :confidential, :due_date, :relative_position],
|
||||||
labels: true,
|
labels: true,
|
||||||
sidebar_endpoints: true,
|
issue_endpoints: true,
|
||||||
|
include_full_project_path: board.group_board?,
|
||||||
include: {
|
include: {
|
||||||
project: { only: [:id, :path] },
|
project: { only: [:id, :path] },
|
||||||
assignees: { only: [:id, :name, :username], methods: [:avatar_url] },
|
assignees: { only: [:id, :name, :username], methods: [:avatar_url] },
|
||||||
|
|
|
@ -12,7 +12,7 @@ class Groups::MilestonesController < Groups::ApplicationController
|
||||||
@milestones = Kaminari.paginate_array(milestones).page(params[:page])
|
@milestones = Kaminari.paginate_array(milestones).page(params[:page])
|
||||||
end
|
end
|
||||||
format.json do
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -272,11 +272,17 @@ class Issue < ActiveRecord::Base
|
||||||
|
|
||||||
def as_json(options = {})
|
def as_json(options = {})
|
||||||
super(options).tap do |json|
|
super(options).tap do |json|
|
||||||
if options.key?(:sidebar_endpoints) && project
|
if options.key?(:issue_endpoints) && project
|
||||||
url_helper = Gitlab::Routing.url_helpers
|
url_helper = Gitlab::Routing.url_helpers
|
||||||
|
|
||||||
json.merge!(issue_sidebar_endpoint: url_helper.project_issue_path(project, self, format: :json, serializer: 'sidebar'),
|
issue_reference = options[:include_full_project_path] ? to_reference(full: true) : to_reference
|
||||||
toggle_subscription_endpoint: url_helper.toggle_subscription_project_issue_path(project, self))
|
|
||||||
|
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
|
end
|
||||||
|
|
||||||
if options.key?(:labels)
|
if options.key?(:labels)
|
||||||
|
|
|
@ -35,6 +35,7 @@ module Boards
|
||||||
def filter_params
|
def filter_params
|
||||||
set_parent
|
set_parent
|
||||||
set_state
|
set_state
|
||||||
|
set_scope
|
||||||
|
|
||||||
params
|
params
|
||||||
end
|
end
|
||||||
|
@ -51,6 +52,10 @@ module Boards
|
||||||
params[:state] = list && list.closed? ? 'closed' : 'opened'
|
params[:state] = list && list.closed? ? 'closed' : 'opened'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def set_scope
|
||||||
|
params[:include_subgroups] = true if board.group_board?
|
||||||
|
end
|
||||||
|
|
||||||
def board_label_ids
|
def board_label_ids
|
||||||
@board_label_ids ||= board.lists.movable.pluck(:label_id)
|
@board_label_ids ||= board.lists.movable.pluck(:label_id)
|
||||||
end
|
end
|
||||||
|
|
|
@ -51,9 +51,10 @@ class IssuableBaseService < BaseService
|
||||||
return unless milestone_id
|
return unless milestone_id
|
||||||
|
|
||||||
params[:milestone_id] = '' if milestone_id == IssuableFinder::NONE
|
params[:milestone_id] = '' if milestone_id == IssuableFinder::NONE
|
||||||
|
group_ids = project.group&.self_and_ancestors&.pluck(:id)
|
||||||
|
|
||||||
milestone =
|
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
|
params[:milestone_id] = '' unless milestone
|
||||||
end
|
end
|
||||||
|
|
|
@ -22,6 +22,6 @@
|
||||||
= render "shared/boards/components/sidebar/labels"
|
= render "shared/boards/components/sidebar/labels"
|
||||||
= render "shared/boards/components/sidebar/notifications"
|
= render "shared/boards/components/sidebar/notifications"
|
||||||
%remove-btn{ ":issue" => "issue",
|
%remove-btn{ ":issue" => "issue",
|
||||||
":issue-update" => "'#{build_issue_link_base}/' + issue.iid + '.json'",
|
":issue-update" => "issue.sidebarInfoEndpoint",
|
||||||
":list" => "list",
|
":list" => "list",
|
||||||
"v-if" => "canRemove" }
|
"v-if" => "canRemove" }
|
||||||
|
|
|
@ -21,8 +21,7 @@
|
||||||
.dropdown
|
.dropdown
|
||||||
- dropdown_options = issue_assignees_dropdown_options
|
- 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,
|
%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-issuable-id" => "issue.iid" }
|
||||||
":data-issue-update" => "'#{build_issue_link_base}/' + issue.iid + '.json'" }
|
|
||||||
= dropdown_options[:title]
|
= dropdown_options[:title]
|
||||||
= icon("chevron-down")
|
= icon("chevron-down")
|
||||||
.dropdown-menu.dropdown-select.dropdown-menu-user.dropdown-menu-selectable.dropdown-menu-author
|
.dropdown-menu.dropdown-select.dropdown-menu-user.dropdown-menu-selectable.dropdown-menu-author
|
||||||
|
|
|
@ -22,8 +22,7 @@
|
||||||
":value" => "issue.dueDate" }
|
":value" => "issue.dueDate" }
|
||||||
.dropdown
|
.dropdown
|
||||||
%button.dropdown-menu-toggle.js-due-date-select.js-issue-boards-due-date{ type: 'button',
|
%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: { toggle: 'dropdown', field_name: "issue[due_date]", ability_name: "issue" }}
|
||||||
":data-issue-update" => "'#{build_issue_link_base}/' + issue.iid + '.json'" }
|
|
||||||
%span.dropdown-toggle-text Due date
|
%span.dropdown-toggle-text Due date
|
||||||
= icon('chevron-down')
|
= icon('chevron-down')
|
||||||
.dropdown-menu.dropdown-menu-due-date
|
.dropdown-menu.dropdown-menu-due-date
|
||||||
|
|
|
@ -26,8 +26,7 @@
|
||||||
project_id: @project&.try(:id),
|
project_id: @project&.try(:id),
|
||||||
labels: labels_filter_path(false),
|
labels: labels_filter_path(false),
|
||||||
namespace_path: @namespace_path,
|
namespace_path: @namespace_path,
|
||||||
project_path: @project.try(:path) },
|
project_path: @project.try(:path) }}
|
||||||
":data-issue-update" => "'#{build_issue_link_base}/' + issue.iid + '.json'" }
|
|
||||||
%span.dropdown-toggle-text
|
%span.dropdown-toggle-text
|
||||||
Label
|
Label
|
||||||
= icon('chevron-down')
|
= icon('chevron-down')
|
||||||
|
|
|
@ -18,8 +18,7 @@
|
||||||
.dropdown
|
.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" },
|
%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-selected" => "milestoneTitle",
|
||||||
":data-issuable-id" => "issue.iid",
|
":data-issuable-id" => "issue.iid" }
|
||||||
":data-issue-update" => "'#{build_issue_link_base}/' + issue.iid + '.json'" }
|
|
||||||
Milestone
|
Milestone
|
||||||
= icon("chevron-down")
|
= icon("chevron-down")
|
||||||
.dropdown-menu.dropdown-select.dropdown-menu-selectable
|
.dropdown-menu.dropdown-select.dropdown-menu-selectable
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
---
|
||||||
|
title: Show issues of subgroups in group-level issue board
|
||||||
|
merge_request:
|
||||||
|
author:
|
||||||
|
type: changed
|
|
@ -116,10 +116,12 @@ feature 'Labels Hierarchy', :js, :nested_groups do
|
||||||
wait_for_requests
|
wait_for_requests
|
||||||
|
|
||||||
if board
|
if board
|
||||||
pending("Waiting for https://gitlab.com/gitlab-org/gitlab-ce/issues/44270")
|
|
||||||
|
|
||||||
select_label_on_dropdown(group_label_3.title)
|
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(page).to have_selector('.card-title') do |card|
|
||||||
expect(card).to have_selector('a', text: labeled_issue_3.title)
|
expect(card).to have_selector('a', text: labeled_issue_3.title)
|
||||||
end
|
end
|
||||||
|
|
|
@ -48,10 +48,8 @@ describe Boards::Issues::ListService do
|
||||||
|
|
||||||
context 'when parent is a group' do
|
context 'when parent is a group' do
|
||||||
let(:user) { create(:user) }
|
let(:user) { create(:user) }
|
||||||
let(:group) { create(:group) }
|
|
||||||
let(:project) { create(:project, :empty_repo, namespace: group) }
|
let(:project) { create(:project, :empty_repo, namespace: group) }
|
||||||
let(:project1) { 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(:m1) { create(:milestone, group: group) }
|
||||||
let(:m2) { 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_issue4) { create(:labeled_issue, :closed, project: project1, labels: [p1, p1_project1]) }
|
||||||
let!(:closed_issue5) { create(:labeled_issue, :closed, project: project1, labels: [development]) }
|
let!(:closed_issue5) { create(:labeled_issue, :closed, project: project1, labels: [development]) }
|
||||||
|
|
||||||
let(:parent) { group }
|
|
||||||
|
|
||||||
before do
|
before do
|
||||||
group.add_developer(user)
|
group.add_developer(user)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
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'
|
it_behaves_like 'issues list service'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue