Commit 9bdf58b6 authored by Tim Zallmann's avatar Tim Zallmann

Merge branch...

Merge branch '19445-native-group-milestone-page-needs-same-info-as-project-milestones' into 'master'

Add tabs in group milestone page

See merge request gitlab-org/gitlab!18818
parents eab4efd0 414ad018
...@@ -53,12 +53,10 @@ module MilestoneActions ...@@ -53,12 +53,10 @@ module MilestoneActions
# rubocop:disable Gitlab/ModuleWithInstanceVariables # rubocop:disable Gitlab/ModuleWithInstanceVariables
def milestone_redirect_path def milestone_redirect_path
if @project if @milestone.global_milestone?
project_milestone_path(@project, @milestone) url_for(action: :show, title: @milestone.title)
elsif @group
group_milestone_path(@group, @milestone.safe_title, title: @milestone.title)
else else
dashboard_milestone_path(@milestone.safe_title, title: @milestone.title) url_for(action: :show)
end end
end end
# rubocop:enable Gitlab/ModuleWithInstanceVariables # rubocop:enable Gitlab/ModuleWithInstanceVariables
......
...@@ -4,6 +4,18 @@ module MilestonesHelper ...@@ -4,6 +4,18 @@ module MilestonesHelper
include EntityDateHelper include EntityDateHelper
include Gitlab::Utils::StrongMemoize include Gitlab::Utils::StrongMemoize
def milestone_status_string(milestone)
if milestone.closed?
_('Closed')
elsif milestone.expired?
_('Past due')
elsif milestone.upcoming?
_('Upcoming')
else
_('Open')
end
end
def milestones_filter_path(opts = {}) def milestones_filter_path(opts = {})
if @project if @project
project_milestones_path(@project, opts) project_milestones_path(@project, opts)
...@@ -213,33 +225,19 @@ module MilestonesHelper ...@@ -213,33 +225,19 @@ module MilestonesHelper
end end
end end
def milestone_merge_request_tab_path(milestone) def milestone_tab_path(milestone, tab)
if @project if milestone.global_milestone?
merge_requests_project_milestone_path(@project, milestone, format: :json) url_for(action: tab, title: milestone.title, format: :json)
elsif @group
merge_requests_group_milestone_path(@group, milestone.safe_title, title: milestone.title, format: :json)
else else
merge_requests_dashboard_milestone_path(milestone, title: milestone.title, format: :json) url_for(action: tab, format: :json)
end end
end end
def milestone_participants_tab_path(milestone) def update_milestone_path(milestone, params = {})
if @project if milestone.project_milestone?
participants_project_milestone_path(@project, milestone, format: :json) project_milestone_path(milestone.project, milestone, milestone: params)
elsif @group
participants_group_milestone_path(@group, milestone.safe_title, title: milestone.title, format: :json)
else else
participants_dashboard_milestone_path(milestone, title: milestone.title, format: :json) group_milestone_route(milestone, params)
end
end
def milestone_labels_tab_path(milestone)
if @project
labels_project_milestone_path(@project, milestone, format: :json)
elsif @group
labels_group_milestone_path(@group, milestone.safe_title, title: milestone.title, format: :json)
else
labels_dashboard_milestone_path(milestone, title: milestone.title, format: :json)
end end
end end
...@@ -264,6 +262,14 @@ module MilestonesHelper ...@@ -264,6 +262,14 @@ module MilestonesHelper
milestone_path(milestone.milestone, params) milestone_path(milestone.milestone, params)
end end
def edit_milestone_path(milestone)
if milestone.group_milestone?
edit_group_milestone_path(milestone.group, milestone)
elsif milestone.project_milestone?
edit_project_milestone_path(milestone.project, milestone)
end
end
def can_admin_project_milestones? def can_admin_project_milestones?
strong_memoize(:can_admin_project_milestones) do strong_memoize(:can_admin_project_milestones) do
can?(current_user, :admin_milestone, @project) can?(current_user, :admin_milestone, @project)
......
...@@ -101,6 +101,10 @@ module Milestoneish ...@@ -101,6 +101,10 @@ module Milestoneish
false false
end end
def global_milestone?
false
end
def total_issue_time_spent def total_issue_time_spent
@total_issue_time_spent ||= issues.joins(:timelogs).sum(:time_spent) @total_issue_time_spent ||= issues.joins(:timelogs).sum(:time_spent)
end end
......
...@@ -18,4 +18,8 @@ class DashboardGroupMilestone < GlobalMilestone ...@@ -18,4 +18,8 @@ class DashboardGroupMilestone < GlobalMilestone
milestones = milestones.search_title(params[:search_title]) if params[:search_title].present? milestones = milestones.search_title(params[:search_title]) if params[:search_title].present?
Milestone.filter_by_state(milestones, params[:state]).map { |m| new(m) } Milestone.filter_by_state(milestones, params[:state]).map { |m| new(m) }
end end
def dashboard_milestone?
true
end
end end
...@@ -100,4 +100,8 @@ class GlobalMilestone ...@@ -100,4 +100,8 @@ class GlobalMilestone
def labels def labels
@labels ||= GlobalLabel.build_collection(milestone.labels).sort_by!(&:title) @labels ||= GlobalLabel.build_collection(milestone.labels).sort_by!(&:title)
end end
def global_milestone?
true
end
end end
...@@ -330,6 +330,6 @@ class Milestone < ApplicationRecord ...@@ -330,6 +330,6 @@ class Milestone < ApplicationRecord
end end
def issues_finder_params def issues_finder_params
{ project_id: project_id } { project_id: project_id, group_id: group_id }.compact
end end
end end
= render "header_title" = render "header_title"
= render 'shared/milestones/top', milestone: @milestone, group: @group = render 'shared/milestones/top', milestone: @milestone, group: @group
= render 'shared/milestones/tabs', milestone: @milestone, show_project_name: true if @milestone.legacy_group_milestone? = render 'shared/milestones/tabs', milestone: @milestone, show_project_name: true
= render 'shared/milestones/sidebar', milestone: @milestone, affix_offset: 102 = render 'shared/milestones/sidebar', milestone: @milestone, affix_offset: 102
...@@ -3,57 +3,8 @@ ...@@ -3,57 +3,8 @@
- page_title @milestone.title, _('Milestones') - page_title @milestone.title, _('Milestones')
- page_description @milestone.description - page_description @milestone.description
.detail-page-header.milestone-page-header = render 'shared/milestones/header', milestone: @milestone
.status-box{ class: status_box_class(@milestone) } = render 'shared/milestones/description', milestone: @milestone
- if @milestone.closed?
= _('Closed')
- elsif @milestone.expired?
= _('Past due')
- elsif @milestone.upcoming?
= _('Upcoming')
- else
= _('Open')
.header-text-content
%span.identifier
%strong
= _('Milestone')
- if @milestone.due_date || @milestone.start_date
= milestone_date_range(@milestone)
.milestone-buttons
- if can?(current_user, :admin_milestone, @project)
= link_to edit_project_milestone_path(@project, @milestone), class: 'btn btn-grouped btn-nr' do
= _('Edit')
- if @project.group
%button.js-promote-project-milestone-button.btn.btn-grouped{ data: { toggle: 'modal',
target: '#promote-milestone-modal',
milestone_title: @milestone.title,
group_name: @project.group.name,
url: promote_project_milestone_path(@milestone.project, @milestone),
container: 'body' },
disabled: true,
type: 'button' }
= _('Promote')
#promote-milestone-modal
- if @milestone.active?
= link_to _('Close milestone'), project_milestone_path(@project, @milestone, milestone: {state_event: :close }), method: :put, class: 'btn btn-close btn-nr btn-grouped'
- else
= link_to _('Reopen milestone'), project_milestone_path(@project, @milestone, milestone: {state_event: :activate }), method: :put, class: 'btn btn-reopen btn-nr btn-grouped'
= render 'shared/milestones/delete_button'
%a.btn.btn-default.btn-grouped.float-right.d-block.d-sm-none.js-sidebar-toggle{ href: '#' }
= icon('angle-double-left')
.detail-page-description.milestone-detail
%h2.title.qa-milestone-title
= markdown_field(@milestone, :title)
%div
- if @milestone.description.present?
.description.md
= markdown_field(@milestone, :description)
= render_if_exists 'shared/milestones/burndown', milestone: @milestone, project: @project = render_if_exists 'shared/milestones/burndown', milestone: @milestone, project: @project
......
.detail-page-description.milestone-detail
%h2.title
= markdown_field(milestone, :title)
- if milestone.try(:description).present?
%div
.description.md
= markdown_field(milestone, :description)
.detail-page-header.milestone-page-header
.status-box{ class: status_box_class(milestone) }
= milestone_status_string(milestone)
.header-text-content
%span.identifier
%strong
= _('Milestone')
- if milestone.due_date || milestone.start_date
= milestone_date_range(milestone)
.milestone-buttons
- if can?(current_user, :admin_milestone, @group || @project)
- unless milestone.legacy_group_milestone?
= link_to _('Edit'), edit_milestone_path(milestone), class: 'btn btn-grouped'
- if milestone.project_milestone? && milestone.project.group
%button.js-promote-project-milestone-button.btn.btn-grouped{ data: { toggle: 'modal',
target: '#promote-milestone-modal',
milestone_title: milestone.title,
group_name: milestone.project.group.name,
url: promote_project_milestone_path(milestone.project, milestone),
container: 'body' },
disabled: true,
type: 'button' }
= _('Promote')
#promote-milestone-modal
- if milestone.active?
= link_to _('Close milestone'), update_milestone_path(milestone, { state_event: :close }), method: :put, class: 'btn btn-grouped btn-close'
- else
= link_to _('Reopen milestone'), update_milestone_path(milestone, { state_event: :activate }), method: :put, class: 'btn btn-grouped btn-reopen'
- unless milestone.legacy_group_milestone?
= render 'shared/milestones/delete_button'
%button.btn.btn-default.btn-grouped.float-right.d-block.d-sm-none.js-sidebar-toggle{ type: 'button' }
= icon('angle-double-left')
- issues_accessible = milestone.is_a?(GlobalMilestone) || can?(current_user, :read_issue, @project)
.scrolling-tabs-container.inner-page-scroll-tabs.is-smaller .scrolling-tabs-container.inner-page-scroll-tabs.is-smaller
.fade-left= icon('angle-left') .fade-left= icon('angle-left')
.fade-right= icon('angle-right') .fade-right= icon('angle-right')
%ul.nav-links.scrolling-tabs.js-milestone-tabs.nav.nav-tabs %ul.nav-links.scrolling-tabs.js-milestone-tabs.nav.nav-tabs
- if issues_accessible
%li.nav-item
= link_to '#tab-issues', class: 'nav-link active', 'data-toggle' => 'tab', 'data-show' => '.tab-issues-buttons' do
Issues
%span.badge.badge-pill= milestone.issues_visible_to_user(current_user).size
%li.nav-item
= link_to '#tab-merge-requests', class: 'nav-link', 'data-toggle' => 'tab', 'data-endpoint': milestone_merge_request_tab_path(milestone) do
Merge Requests
%span.badge.badge-pill= milestone.merge_requests_visible_to_user(current_user).size
- else
%li.nav-item
= link_to '#tab-merge-requests', class: 'nav-link active', 'data-toggle' => 'tab', 'data-endpoint': milestone_merge_request_tab_path(milestone) do
Merge Requests
%span.badge.badge-pill= milestone.merge_requests.size
%li.nav-item %li.nav-item
= link_to '#tab-participants', class: 'nav-link', 'data-toggle' => 'tab', 'data-endpoint': milestone_participants_tab_path(milestone) do = link_to '#tab-issues', class: 'nav-link active', data: { toggle: 'tab', show: '.tab-issues-buttons' } do
Participants = _('Issues')
%span.badge.badge-pill= milestone.issues_visible_to_user(current_user).size
%li.nav-item
= link_to '#tab-merge-requests', class: 'nav-link', data: { toggle: 'tab', endpoint: milestone_tab_path(milestone, 'merge_requests') } do
= _('Merge Requests')
%span.badge.badge-pill= milestone.merge_requests_visible_to_user(current_user).size
%li.nav-item
= link_to '#tab-participants', class: 'nav-link', data: { toggle: 'tab', endpoint: milestone_tab_path(milestone, 'participants') } do
= _('Participants')
%span.badge.badge-pill= milestone.issue_participants_visible_by_user(current_user).count %span.badge.badge-pill= milestone.issue_participants_visible_by_user(current_user).count
%li.nav-item %li.nav-item
= link_to '#tab-labels', class: 'nav-link', 'data-toggle' => 'tab', 'data-endpoint': milestone_labels_tab_path(milestone) do = link_to '#tab-labels', class: 'nav-link', data: { toggle: 'tab', endpoint: milestone_tab_path(milestone, 'labels') } do
Labels = _('Labels')
%span.badge.badge-pill= milestone.issue_labels_visible_by_user(current_user).count %span.badge.badge-pill= milestone.issue_labels_visible_by_user(current_user).count
- issues = milestone.sorted_issues(current_user) - issues = milestone.sorted_issues(current_user)
...@@ -32,16 +24,11 @@ ...@@ -32,16 +24,11 @@
- show_full_project_name = local_assigns.fetch(:show_full_project_name, false) - show_full_project_name = local_assigns.fetch(:show_full_project_name, false)
.tab-content.milestone-content .tab-content.milestone-content
- if issues_accessible .tab-pane.active#tab-issues{ data: { sort_endpoint: (sort_issues_project_milestone_path(@project, @milestone) if @project && current_user) } }
.tab-pane.active#tab-issues{ data: { sort_endpoint: (sort_issues_project_milestone_path(@project, @milestone) if @project && current_user) } } = render 'shared/milestones/issues_tab', issues: issues, show_project_name: show_project_name, show_full_project_name: show_full_project_name
= render 'shared/milestones/issues_tab', issues: issues, show_project_name: show_project_name, show_full_project_name: show_full_project_name .tab-pane#tab-merge-requests
.tab-pane#tab-merge-requests -# loaded async
-# loaded async = render "shared/milestones/tab_loading"
= render "shared/milestones/tab_loading"
- else
.tab-pane.active#tab-merge-requests
-# loaded async
= render "shared/milestones/tab_loading"
.tab-pane#tab-participants .tab-pane#tab-participants
-# loaded async -# loaded async
= render "shared/milestones/tab_loading" = render "shared/milestones/tab_loading"
......
...@@ -4,54 +4,15 @@ ...@@ -4,54 +4,15 @@
- group = local_assigns[:group] - group = local_assigns[:group]
- is_dynamic_milestone = milestone.legacy_group_milestone? || milestone.dashboard_milestone? - is_dynamic_milestone = milestone.legacy_group_milestone? || milestone.dashboard_milestone?
.detail-page-header.milestone-page-header = render 'shared/milestones/header', milestone: milestone
.status-box{ class: "status-box-#{milestone.closed? ? 'closed' : 'open'}" }
- if milestone.closed?
Closed
- elsif milestone.expired?
Expired
- else
Open
.header-text-content
%span.identifier
Milestone #{milestone.title}
- if milestone.due_date || milestone.start_date
%span.creator
&nbsp;&middot;
= milestone_date_range(milestone)
.milestone-buttons
- if group
- if can?(current_user, :admin_milestone, group)
- if milestone.group_milestone?
= link_to edit_group_milestone_path(group, milestone), class: "btn btn btn-grouped" do
Edit
- if milestone.active?
= link_to 'Close Milestone', group_milestone_route(milestone, {state_event: :close }), method: :put, class: "btn btn-grouped btn-close"
- else
= link_to 'Reopen Milestone', group_milestone_route(milestone, {state_event: :activate }), method: :put, class: "btn btn-grouped btn-reopen"
- unless is_dynamic_milestone
= render 'shared/milestones/delete_button'
%a.btn.btn-default.btn-grouped.float-right.d-block.d-sm-none.js-sidebar-toggle{ href: "#" }
= icon('angle-double-left')
= render 'shared/milestones/deprecation_message' if is_dynamic_milestone = render 'shared/milestones/deprecation_message' if is_dynamic_milestone
= render 'shared/milestones/description', milestone: milestone
.detail-page-description.milestone-detail
%h2.title
= markdown_field(milestone, :title)
- if milestone.group_milestone? && milestone.description.present?
%div
.description.md
= markdown_field(milestone, :description)
- if milestone.complete?(current_user) && milestone.active? - if milestone.complete?(current_user) && milestone.active?
.alert.alert-success.prepend-top-default .alert.alert-success.prepend-top-default
- close_msg = group ? 'You may close the milestone now.' : 'Navigate to the project to close the milestone.' %span
%span All issues for this milestone are closed. #{close_msg} = _('All issues for this milestone are closed.')
= group ? _('You may close the milestone now.') : _('Navigate to the project to close the milestone.')
= render_if_exists 'shared/milestones/burndown', milestone: milestone, project: @project = render_if_exists 'shared/milestones/burndown', milestone: milestone, project: @project
...@@ -77,10 +38,3 @@ ...@@ -77,10 +38,3 @@
Open Open
%td %td
= milestone.expires_at = milestone.expires_at
- elsif milestone.group_milestone?
%br
View
= link_to 'Issues', issues_group_path(@group, milestone_title: milestone.title)
or
= link_to 'Merge Requests', merge_requests_group_path(@group, milestone_title: milestone.title)
in this milestone
---
title: Add issues, MRs, participants, and labels tabs in group milestone page
merge_request: 18818
author:
type: added
...@@ -103,30 +103,18 @@ When filtering by milestone, in addition to choosing a specific project mileston ...@@ -103,30 +103,18 @@ When filtering by milestone, in addition to choosing a specific project mileston
## Milestone view ## Milestone view
Not all features in the project milestone view are available in the group milestone view. This table summarizes the differences:
| Feature | Project milestone view | Group milestone view |
|--------------------------------------|:----------------------:|:--------------------:|
| Title and description | ✓ | ✓ |
| Issues assigned to milestone | ✓ | |
| Merge requests assigned to milestone | ✓ | |
| Participants and labels used | ✓ | |
| Percentage complete | ✓ | ✓ |
| Start date and due date | ✓ | ✓ |
| Total issue time spent | ✓ | ✓ |
| Total issue weight | ✓ | |
| Burndown chart **[STARTER}** | ✓ | ✓ |
The milestone view shows the title and description. The milestone view shows the title and description.
### Project milestone features There are also tabs below these that show the following:
These features are only available for project milestones and not group milestones.
- Issues assigned to the milestone are displayed in three columns: Unstarted issues, ongoing issues, and completed issues. - Issues
- Merge requests assigned to the milestone are displayed in four columns: Work in progress merge requests, waiting for merge, rejected, and closed. Shows all issues assigned to the milestone. These are displayed in three columns: Unstarted issues, ongoing issues, and completed issues.
- Participants and labels that are used in issues and merge requests that have the milestone assigned are displayed. - Merge requests
- [Burndown chart](#project-burndown-charts-starter). Shows all merge requests assigned to the milestone. These are displayed in four columns: Work in progress merge requests, waiting for merge, rejected, and closed.
- Participants
Shows all assignees of issues assigned to the milestone.
- Labels
Shows all labels that are used in issues assigned to the milestone.
### Project Burndown Charts **(STARTER)** ### Project Burndown Charts **(STARTER)**
...@@ -144,9 +132,8 @@ The milestone sidebar on the milestone view shows the following: ...@@ -144,9 +132,8 @@ The milestone sidebar on the milestone view shows the following:
- Percentage complete, which is calculated as number of closed issues divided by total number of issues. - Percentage complete, which is calculated as number of closed issues divided by total number of issues.
- The start date and due date. - The start date and due date.
- The total time spent on all issues that have the milestone assigned. - The total time spent on all issues assigned to the milestone.
- The total issue weight of all issues assigned to the milestone.
For project milestones only, the milestone sidebar shows the total issue weight of all issues that have the milestone assigned.
![Project milestone page](img/milestones_project_milestone_page.png) ![Project milestone page](img/milestones_project_milestone_page.png)
......
...@@ -1396,6 +1396,9 @@ msgstr "" ...@@ -1396,6 +1396,9 @@ msgstr ""
msgid "All groups and projects" msgid "All groups and projects"
msgstr "" msgstr ""
msgid "All issues for this milestone are closed."
msgstr ""
msgid "All issues for this milestone are closed. You may close this milestone now." msgid "All issues for this milestone are closed. You may close this milestone now."
msgstr "" msgstr ""
...@@ -10941,6 +10944,9 @@ msgstr "" ...@@ -10941,6 +10944,9 @@ msgstr ""
msgid "Naming, visibility" msgid "Naming, visibility"
msgstr "" msgstr ""
msgid "Navigate to the project to close the milestone."
msgstr ""
msgid "Nav|Help" msgid "Nav|Help"
msgstr "" msgstr ""
...@@ -11782,6 +11788,9 @@ msgstr "" ...@@ -11782,6 +11788,9 @@ msgstr ""
msgid "Part of merge request changes" msgid "Part of merge request changes"
msgstr "" msgstr ""
msgid "Participants"
msgstr ""
msgid "Passed" msgid "Passed"
msgstr "" msgstr ""
...@@ -19497,6 +19506,9 @@ msgstr "" ...@@ -19497,6 +19506,9 @@ msgstr ""
msgid "You may also add variables that are made available to the running application by prepending the variable key with <code>K8S_SECRET_</code>." msgid "You may also add variables that are made available to the running application by prepending the variable key with <code>K8S_SECRET_</code>."
msgstr "" msgstr ""
msgid "You may close the milestone now."
msgstr ""
msgid "You must accept our Terms of Service and privacy policy in order to register an account" msgid "You must accept our Terms of Service and privacy policy in order to register an account"
msgstr "" msgstr ""
......
...@@ -3,9 +3,9 @@ ...@@ -3,9 +3,9 @@
require 'spec_helper' require 'spec_helper'
describe 'Group milestones' do describe 'Group milestones' do
let(:group) { create(:group) } let_it_be(:group) { create(:group) }
let!(:project) { create(:project_empty_repo, group: group) } let_it_be(:project) { create(:project_empty_repo, group: group) }
let(:user) { create(:group_member, :maintainer, user: create(:user), group: group ).user } let_it_be(:user) { create(:group_member, :maintainer, user: create(:user), group: group ).user }
around do |example| around do |example|
Timecop.freeze { example.run } Timecop.freeze { example.run }
...@@ -71,9 +71,9 @@ describe 'Group milestones' do ...@@ -71,9 +71,9 @@ describe 'Group milestones' do
end end
context 'when milestones exists' do context 'when milestones exists' do
let!(:other_project) { create(:project_empty_repo, group: group) } let_it_be(:other_project) { create(:project_empty_repo, group: group) }
let!(:active_project_milestone1) do let_it_be(:active_project_milestone1) do
create( create(
:milestone, :milestone,
project: project, project: project,
...@@ -83,12 +83,12 @@ describe 'Group milestones' do ...@@ -83,12 +83,12 @@ describe 'Group milestones' do
description: 'Lorem Ipsum is simply dummy text' description: 'Lorem Ipsum is simply dummy text'
) )
end end
let!(:active_project_milestone2) { create(:milestone, project: other_project, state: 'active', title: 'v1.1') } let_it_be(:active_project_milestone2) { create(:milestone, project: other_project, state: 'active', title: 'v1.1') }
let!(:closed_project_milestone1) { create(:milestone, project: project, state: 'closed', title: 'v2.0') } let_it_be(:closed_project_milestone1) { create(:milestone, project: project, state: 'closed', title: 'v2.0') }
let!(:closed_project_milestone2) { create(:milestone, project: other_project, state: 'closed', title: 'v2.0') } let_it_be(:closed_project_milestone2) { create(:milestone, project: other_project, state: 'closed', title: 'v2.0') }
let!(:active_group_milestone) { create(:milestone, group: group, state: 'active', title: 'GL-113') } let_it_be(:active_group_milestone) { create(:milestone, group: group, state: 'active', title: 'GL-113') }
let!(:closed_group_milestone) { create(:milestone, group: group, state: 'closed') } let_it_be(:closed_group_milestone) { create(:milestone, group: group, state: 'closed') }
let!(:issue) do let_it_be(:issue) do
create :issue, project: project, assignees: [user], author: user, milestone: active_project_milestone1 create :issue, project: project, assignees: [user], author: user, milestone: active_project_milestone1
end end
...@@ -143,38 +143,111 @@ describe 'Group milestones' do ...@@ -143,38 +143,111 @@ describe 'Group milestones' do
expect(page).to have_content('Issues 1 Open: 1 Closed: 0') expect(page).to have_content('Issues 1 Open: 1 Closed: 0')
expect(page).to have_link(issue.title, href: project_issue_path(issue.project, issue)) expect(page).to have_link(issue.title, href: project_issue_path(issue.project, issue))
end end
end
end
describe 'milestone tabs', :js do
context 'for a legacy group milestone' do
let_it_be(:milestone) { create(:milestone, project: project) }
let_it_be(:label) { create(:label, project: project) }
let_it_be(:issue) { create(:labeled_issue, project: project, milestone: milestone, labels: [label], assignees: [create(:user)]) }
let_it_be(:mr) { create(:merge_request, source_project: project, milestone: milestone) }
before do
visit group_milestone_path(group, milestone.title, title: milestone.title)
end
it 'renders the issues tab' do
within('#tab-issues') do
expect(page).to have_content issue.title
end
end
it 'renders the merge requests tab' do
within('.js-milestone-tabs') do
click_link('Merge Requests')
end
describe 'labels' do within('#tab-merge-requests') do
before do expect(page).to have_content mr.title
create(:label, project: project, title: 'bug') do |label| end
issue.labels << label end
end
it 'renders the participants tab' do
within('.js-milestone-tabs') do
click_link('Participants')
end
create(:label, project: project, title: 'feature') do |label| within('#tab-participants') do
issue.labels << label expect(page).to have_content issue.assignees.first.name
end
end end
end
it 'renders labels' do it 'renders the labels tab' do
click_link 'v1.0' within('.js-milestone-tabs') do
click_link('Labels')
end
page.within('#tab-issues') do within('#tab-labels') do
expect(page).to have_content 'bug' expect(page).to have_content label.title
expect(page).to have_content 'feature'
end
end end
end
end
context 'for a group milestone' do
let_it_be(:other_project) { create(:project_empty_repo, group: group) }
let_it_be(:milestone) { create(:milestone, group: group) }
it 'renders labels list', :js do let_it_be(:project_label) { create(:label, project: project) }
click_link 'v1.0' let_it_be(:other_project_label) { create(:label, project: other_project) }
page.within('.content .nav-links') do let_it_be(:project_issue) { create(:labeled_issue, project: project, milestone: milestone, labels: [project_label], assignees: [create(:user)]) }
page.find(:xpath, "//a[@href='#tab-labels']").click let_it_be(:other_project_issue) { create(:labeled_issue, project: other_project, milestone: milestone, labels: [other_project_label], assignees: [create(:user)]) }
end
let_it_be(:project_mr) { create(:merge_request, source_project: project, milestone: milestone) }
let_it_be(:other_project_mr) { create(:merge_request, source_project: other_project, milestone: milestone) }
before do
visit group_milestone_path(group, milestone)
end
it 'renders the issues tab' do
within('#tab-issues') do
expect(page).to have_content project_issue.title
expect(page).to have_content other_project_issue.title
end
end
it 'renders the merge requests tab' do
within('.js-milestone-tabs') do
click_link('Merge Requests')
end
within('#tab-merge-requests') do
expect(page).to have_content project_mr.title
expect(page).to have_content other_project_mr.title
end
end
it 'renders the participants tab' do
within('.js-milestone-tabs') do
click_link('Participants')
end
within('#tab-participants') do
expect(page).to have_content project_issue.assignees.first.name
expect(page).to have_content other_project_issue.assignees.first.name
end
end
it 'renders the labels tab' do
within('.js-milestone-tabs') do
click_link('Labels')
end
page.within('#tab-labels') do within('#tab-labels') do
expect(page).to have_content 'bug' expect(page).to have_content project_label.title
expect(page).to have_content 'feature' expect(page).to have_content other_project_label.title
end
end end
end end
end end
......
...@@ -51,15 +51,16 @@ describe 'Project milestone' do ...@@ -51,15 +51,16 @@ describe 'Project milestone' do
context 'when project has disabled issues' do context 'when project has disabled issues' do
before do before do
create(:issue, project: project, milestone: milestone)
project.project_feature.update_attribute(:issues_access_level, ProjectFeature::DISABLED) project.project_feature.update_attribute(:issues_access_level, ProjectFeature::DISABLED)
visit project_milestone_path(project, milestone) visit project_milestone_path(project, milestone)
end end
it 'hides issues tab' do it 'does not show any issues under the issues tab' do
within('#content-body') do within('#content-body') do
expect(page).not_to have_link 'Issues', href: '#tab-issues' expect(find('.nav-links li a.active')).to have_content 'Issues'
expect(page).to have_selector '.nav-links li a.active', count: 1 expect(page).not_to have_selector '.issuable-row'
expect(find('.nav-links li a.active')).to have_content 'Merge Requests'
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment