Merge branch '23674-simplify-milestone-summary' into 'master'
Resolve "Simplify milestone summary" Closes #23674 See merge request !10096
This commit is contained in:
commit
f7fefe82e5
13 changed files with 207 additions and 109 deletions
|
@ -33,6 +33,8 @@
|
||||||
/* global ProjectShow */
|
/* global ProjectShow */
|
||||||
/* global Labels */
|
/* global Labels */
|
||||||
/* global Shortcuts */
|
/* global Shortcuts */
|
||||||
|
/* global Sidebar */
|
||||||
|
|
||||||
import Issue from './issue';
|
import Issue from './issue';
|
||||||
|
|
||||||
import BindInOut from './behaviors/bind_in_out';
|
import BindInOut from './behaviors/bind_in_out';
|
||||||
|
@ -118,6 +120,7 @@ const ShortcutsBlob = require('./shortcuts_blob');
|
||||||
case 'groups:milestones:show':
|
case 'groups:milestones:show':
|
||||||
case 'dashboard:milestones:show':
|
case 'dashboard:milestones:show':
|
||||||
new Milestone();
|
new Milestone();
|
||||||
|
new Sidebar();
|
||||||
break;
|
break;
|
||||||
case 'dashboard:todos:index':
|
case 'dashboard:todos:index':
|
||||||
new gl.Todos();
|
new gl.Todos();
|
||||||
|
|
|
@ -52,66 +52,62 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.milestone-summary {
|
.milestone-sidebar {
|
||||||
.milestone-stat {
|
.gutter-toggle {
|
||||||
white-space: nowrap;
|
margin-bottom: 10px;
|
||||||
margin-right: 10px;
|
|
||||||
|
|
||||||
&.with-drilldown {
|
|
||||||
margin-right: 2px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.remaining-days {
|
.milestone-progress {
|
||||||
color: $orange-600;
|
.title {
|
||||||
}
|
padding-top: 5px;
|
||||||
|
|
||||||
.milestone-stats-and-buttons {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-start;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
|
|
||||||
@media (min-width: $screen-xs-min) {
|
|
||||||
justify-content: space-between;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.milestone-progress-buttons {
|
|
||||||
order: 1;
|
|
||||||
margin-top: 10px;
|
|
||||||
|
|
||||||
@media (min-width: $screen-xs-min) {
|
|
||||||
order: 2;
|
|
||||||
margin-top: 0;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.btn {
|
|
||||||
float: left;
|
|
||||||
margin-right: $btn-side-margin;
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
margin-right: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.milestone-stats {
|
|
||||||
order: 2;
|
|
||||||
width: 100%;
|
|
||||||
padding: 7px 0;
|
|
||||||
flex-shrink: 1;
|
|
||||||
|
|
||||||
@media (min-width: $screen-xs-min) {
|
|
||||||
// when displayed on one line stats go first, buttons second
|
|
||||||
order: 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.progress {
|
.progress {
|
||||||
width: 100%;
|
height: 6px;
|
||||||
margin: 15px 0;
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapsed-milestone-date {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.milestone-date {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-separator {
|
||||||
|
line-height: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.remaining-days strong {
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
.milestone-stat {
|
||||||
|
float: left;
|
||||||
|
margin-right: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.milestone-stat:last-child {
|
||||||
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.milestone-progress {
|
||||||
|
.sidebar-collapsed-icon {
|
||||||
|
clear: both;
|
||||||
|
padding: 15px 5px 5px;
|
||||||
|
|
||||||
|
.progress {
|
||||||
|
margin: 5px 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.right-sidebar-collapsed & {
|
||||||
|
.reference {
|
||||||
|
border-top: 1px solid $border-gray-normal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,8 +19,8 @@ module MilestonesHelper
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def milestones_browse_issuables_path(milestone, type:)
|
def milestones_browse_issuables_path(milestone, state: nil, type:)
|
||||||
opts = { milestone_title: milestone.title }
|
opts = { milestone_title: milestone.title, state: state }
|
||||||
|
|
||||||
if @project
|
if @project
|
||||||
polymorphic_path([@project.namespace.becomes(Namespace), @project, type], opts)
|
polymorphic_path([@project.namespace.becomes(Namespace), @project, type], opts)
|
||||||
|
|
|
@ -6,7 +6,8 @@ module NavHelper
|
||||||
current_path?('merge_requests#builds') ||
|
current_path?('merge_requests#builds') ||
|
||||||
current_path?('merge_requests#conflicts') ||
|
current_path?('merge_requests#conflicts') ||
|
||||||
current_path?('merge_requests#pipelines') ||
|
current_path?('merge_requests#pipelines') ||
|
||||||
current_path?('issues#show')
|
current_path?('issues#show') ||
|
||||||
|
current_path?('milestones#show')
|
||||||
if cookies[:collapsed_gutter] == 'true'
|
if cookies[:collapsed_gutter] == 'true'
|
||||||
"page-gutter right-sidebar-collapsed"
|
"page-gutter right-sidebar-collapsed"
|
||||||
else
|
else
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
- header_title "Milestones", dashboard_milestones_path
|
- header_title "Milestones", dashboard_milestones_path
|
||||||
|
|
||||||
= render 'shared/milestones/top', milestone: @milestone
|
= render 'shared/milestones/top', milestone: @milestone
|
||||||
= render 'shared/milestones/summary', milestone: @milestone
|
|
||||||
= render 'shared/milestones/tabs', milestone: @milestone, show_full_project_name: true
|
= render 'shared/milestones/tabs', milestone: @milestone, show_full_project_name: true
|
||||||
|
= render 'shared/milestones/sidebar', milestone: @milestone, affix_offset: 51
|
||||||
|
|
|
@ -4,5 +4,5 @@
|
||||||
= page_specific_javascript_bundle_tag('simulate_drag') if Rails.env.test?
|
= page_specific_javascript_bundle_tag('simulate_drag') if Rails.env.test?
|
||||||
|
|
||||||
= render 'shared/milestones/top', milestone: @milestone, group: @group
|
= render 'shared/milestones/top', milestone: @milestone, group: @group
|
||||||
= render 'shared/milestones/summary', milestone: @milestone
|
|
||||||
= render 'shared/milestones/tabs', milestone: @milestone, show_project_name: true
|
= render 'shared/milestones/tabs', milestone: @milestone, show_project_name: true
|
||||||
|
= render 'shared/milestones/sidebar', milestone: @milestone, affix_offset: 102
|
||||||
|
|
|
@ -36,6 +36,9 @@
|
||||||
= link_to namespace_project_milestone_path(@project.namespace, @project, @milestone), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-grouped btn-danger" do
|
= link_to namespace_project_milestone_path(@project.namespace, @project, @milestone), data: { confirm: 'Are you sure?' }, method: :delete, class: "btn btn-grouped btn-danger" do
|
||||||
Delete
|
Delete
|
||||||
|
|
||||||
|
%a.btn.btn-default.btn-grouped.pull-right.visible-xs-block.js-sidebar-toggle{ href: "#" }
|
||||||
|
= icon('angle-double-left')
|
||||||
|
|
||||||
.detail-page-description.milestone-detail{ class: ('hide-bottom-border' unless @milestone.description.present? ) }
|
.detail-page-description.milestone-detail{ class: ('hide-bottom-border' unless @milestone.description.present? ) }
|
||||||
%h2.title
|
%h2.title
|
||||||
= markdown_field(@milestone, :title)
|
= markdown_field(@milestone, :title)
|
||||||
|
@ -53,5 +56,5 @@
|
||||||
.alert.alert-success.prepend-top-default
|
.alert.alert-success.prepend-top-default
|
||||||
%span All issues for this milestone are closed. You may close this milestone now.
|
%span All issues for this milestone are closed. You may close this milestone now.
|
||||||
|
|
||||||
= render 'shared/milestones/summary', milestone: @milestone, project: @project
|
|
||||||
= render 'shared/milestones/tabs', milestone: @milestone
|
= render 'shared/milestones/tabs', milestone: @milestone
|
||||||
|
= render 'shared/milestones/sidebar', milestone: @milestone, project: @project, affix_offset: 153
|
||||||
|
|
131
app/views/shared/milestones/_sidebar.html.haml
Normal file
131
app/views/shared/milestones/_sidebar.html.haml
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
- affix_offset = local_assigns.fetch(:affix_offset, "102")
|
||||||
|
- project = local_assigns[:project]
|
||||||
|
|
||||||
|
%aside.right-sidebar.js-right-sidebar{ data: { "offset-top" => affix_offset, "spy" => "affix" }, class: sidebar_gutter_collapsed_class, 'aria-live' => 'polite' }
|
||||||
|
.issuable-sidebar.milestone-sidebar
|
||||||
|
.block.milestone-progress.issuable-sidebar-header
|
||||||
|
%a.gutter-toggle.pull-right.js-sidebar-toggle{ role: "button", href: "#", "aria-label" => "Toggle sidebar" }
|
||||||
|
= sidebar_gutter_toggle_icon
|
||||||
|
|
||||||
|
.sidebar-collapsed-icon
|
||||||
|
%span== #{milestone.percent_complete(current_user)}%
|
||||||
|
= milestone_progress_bar(milestone)
|
||||||
|
.title.hide-collapsed
|
||||||
|
%strong.bold== #{milestone.percent_complete(current_user)}%
|
||||||
|
%span.hide-collapsed
|
||||||
|
complete
|
||||||
|
.value.hide-collapsed
|
||||||
|
= milestone_progress_bar(milestone)
|
||||||
|
|
||||||
|
.block.start_date.hide-collapsed
|
||||||
|
.title
|
||||||
|
Start date
|
||||||
|
- if @project && can?(current_user, :admin_milestone, @project)
|
||||||
|
= link_to 'Edit', edit_namespace_project_milestone_path(@project.namespace, @project, @milestone), class: 'edit-link pull-right'
|
||||||
|
.value
|
||||||
|
%span.value-content
|
||||||
|
- if milestone.start_date
|
||||||
|
%span.bold= milestone.start_date.to_s(:medium)
|
||||||
|
- else
|
||||||
|
%span.no-value No start date
|
||||||
|
|
||||||
|
.block.due_date
|
||||||
|
.sidebar-collapsed-icon
|
||||||
|
= icon('calendar', 'aria-hidden': 'true')
|
||||||
|
%span.collapsed-milestone-date
|
||||||
|
- if milestone.start_date && milestone.due_date
|
||||||
|
- if milestone.start_date.year == milestone.due_date.year
|
||||||
|
.milestone-date= milestone.start_date.strftime('%b %-d')
|
||||||
|
- else
|
||||||
|
.milestone-date= milestone.start_date.strftime('%b %-d %Y')
|
||||||
|
.date-separator -
|
||||||
|
.due_date= milestone.due_date.strftime('%b %-d %Y')
|
||||||
|
- elsif milestone.start_date
|
||||||
|
From
|
||||||
|
.milestone-date= milestone.start_date.strftime('%b %-d %Y')
|
||||||
|
- elsif milestone.due_date
|
||||||
|
Until
|
||||||
|
.milestone-date= milestone.due_date.strftime('%b %-d %Y')
|
||||||
|
- else
|
||||||
|
None
|
||||||
|
.title.hide-collapsed
|
||||||
|
Due date
|
||||||
|
- if @project && can?(current_user, :admin_milestone, @project)
|
||||||
|
= link_to 'Edit', edit_namespace_project_milestone_path(@project.namespace, @project, @milestone), class: 'edit-link pull-right'
|
||||||
|
.value.hide-collapsed
|
||||||
|
%span.value-content
|
||||||
|
- if milestone.due_date
|
||||||
|
%span.bold= milestone.due_date.to_s(:medium)
|
||||||
|
- else
|
||||||
|
%span.no-value No due date
|
||||||
|
- remaining_days = milestone_remaining_days(milestone)
|
||||||
|
- if remaining_days.present?
|
||||||
|
= surround '(', ')' do
|
||||||
|
%span.remaining-days= remaining_days
|
||||||
|
|
||||||
|
- if !project || can?(current_user, :read_issue, project)
|
||||||
|
.block
|
||||||
|
.sidebar-collapsed-icon
|
||||||
|
%strong
|
||||||
|
= icon('hashtag', 'aria-hidden': 'true')
|
||||||
|
%span= milestone.issues_visible_to_user(current_user).count
|
||||||
|
.title.hide-collapsed
|
||||||
|
Issues
|
||||||
|
%span.badge= milestone.issues_visible_to_user(current_user).count
|
||||||
|
- if project && can?(current_user, :create_issue, project)
|
||||||
|
= link_to new_namespace_project_issue_path(project.namespace, project, issue: { milestone_id: milestone.id }), class: "pull-right", title: "New Issue" do
|
||||||
|
New issue
|
||||||
|
.value.hide-collapsed.bold
|
||||||
|
%span.milestone-stat
|
||||||
|
= link_to milestones_browse_issuables_path(milestone, type: :issues) do
|
||||||
|
Open:
|
||||||
|
= milestone.issues_visible_to_user(current_user).opened.count
|
||||||
|
%span.milestone-stat
|
||||||
|
= link_to milestones_browse_issuables_path(milestone, type: :issues, state: 'closed') do
|
||||||
|
Closed:
|
||||||
|
= milestone.issues_visible_to_user(current_user).closed.count
|
||||||
|
|
||||||
|
.block
|
||||||
|
.sidebar-collapsed-icon
|
||||||
|
%strong
|
||||||
|
= icon('exclamation', 'aria-hidden': 'true')
|
||||||
|
%span= milestone.issues_visible_to_user(current_user).count
|
||||||
|
.title.hide-collapsed
|
||||||
|
Merge requests
|
||||||
|
%span.badge= milestone.merge_requests.count
|
||||||
|
.value.hide-collapsed.bold
|
||||||
|
- if !project || can?(current_user, :read_merge_request, project)
|
||||||
|
%span.milestone-stat
|
||||||
|
= link_to milestones_browse_issuables_path(milestone, type: :merge_requests) do
|
||||||
|
Open:
|
||||||
|
= milestone.merge_requests.opened.count
|
||||||
|
%span.milestone-stat
|
||||||
|
= link_to milestones_browse_issuables_path(milestone, type: :merge_requests, state: 'closed') do
|
||||||
|
Closed:
|
||||||
|
= milestone.merge_requests.closed.count
|
||||||
|
%span.milestone-stat
|
||||||
|
= link_to milestones_browse_issuables_path(milestone, type: :merge_requests, state: 'merged') do
|
||||||
|
Merged:
|
||||||
|
= milestone.merge_requests.merged.count
|
||||||
|
- else
|
||||||
|
%span.milestone-stat
|
||||||
|
Open:
|
||||||
|
= milestone.merge_requests.opened.count
|
||||||
|
%span.milestone-stat
|
||||||
|
Closed:
|
||||||
|
= milestone.merge_requests.closed.count
|
||||||
|
%span.milestone-stat
|
||||||
|
Merged:
|
||||||
|
= milestone.merge_requests.merged.count
|
||||||
|
|
||||||
|
- milestone_ref = milestone.try(:to_reference, full: true)
|
||||||
|
- if milestone_ref.present?
|
||||||
|
.block.reference
|
||||||
|
.sidebar-collapsed-icon.dont-change-state
|
||||||
|
= clipboard_button(clipboard_text: milestone_ref, title: "Copy reference to clipboard", placement: "left")
|
||||||
|
.cross-project-reference.hide-collapsed
|
||||||
|
%span
|
||||||
|
Reference:
|
||||||
|
%cite{ title: milestone_ref }
|
||||||
|
= milestone_ref
|
||||||
|
= clipboard_button(clipboard_text: milestone_ref, title: "Copy reference to clipboard", placement: "left")
|
|
@ -1,45 +0,0 @@
|
||||||
- project = local_assigns[:project]
|
|
||||||
|
|
||||||
.context.prepend-top-default
|
|
||||||
.milestone-summary
|
|
||||||
%h4 Progress
|
|
||||||
|
|
||||||
.milestone-stats-and-buttons
|
|
||||||
.milestone-stats
|
|
||||||
- if !project || can?(current_user, :read_issue, project)
|
|
||||||
%span.milestone-stat.with-drilldown
|
|
||||||
%strong= milestone.issues_visible_to_user(current_user).size
|
|
||||||
issues:
|
|
||||||
%span.milestone-stat
|
|
||||||
%strong= milestone.issues_visible_to_user(current_user).opened.size
|
|
||||||
open and
|
|
||||||
%strong= milestone.issues_visible_to_user(current_user).closed.size
|
|
||||||
closed
|
|
||||||
%span.milestone-stat.with-drilldown
|
|
||||||
%strong= milestone.merge_requests.size
|
|
||||||
merge requests:
|
|
||||||
%span.milestone-stat
|
|
||||||
%strong= milestone.merge_requests.opened.size
|
|
||||||
open and
|
|
||||||
%strong= milestone.merge_requests.merged.size
|
|
||||||
merged
|
|
||||||
%span.milestone-stat
|
|
||||||
%strong== #{milestone.percent_complete(current_user)}%
|
|
||||||
complete
|
|
||||||
- remaining_days = milestone_remaining_days(milestone)
|
|
||||||
- if remaining_days.present?
|
|
||||||
%span.milestone-stat
|
|
||||||
%span.remaining-days= remaining_days
|
|
||||||
|
|
||||||
.milestone-progress-buttons
|
|
||||||
%span.tab-issues-buttons
|
|
||||||
- if project
|
|
||||||
- if can?(current_user, :create_issue, project)
|
|
||||||
= link_to new_namespace_project_issue_path(project.namespace, project, issue: { milestone_id: milestone.id }), class: "btn", title: "New Issue" do
|
|
||||||
New Issue
|
|
||||||
- if can?(current_user, :read_issue, project)
|
|
||||||
= link_to 'Browse Issues', milestones_browse_issuables_path(milestone, type: :issues), class: "btn"
|
|
||||||
%span.tab-merge-requests-buttons.hidden
|
|
||||||
= link_to 'Browse Merge Requests', milestones_browse_issuables_path(milestone, type: :merge_requests), class: "btn"
|
|
||||||
|
|
||||||
= milestone_progress_bar(milestone)
|
|
|
@ -3,6 +3,9 @@
|
||||||
- group = local_assigns[:group]
|
- group = local_assigns[:group]
|
||||||
|
|
||||||
.detail-page-header
|
.detail-page-header
|
||||||
|
%a.btn.btn-default.btn-grouped.pull-right.visible-xs-block.js-sidebar-toggle{ href: "#" }
|
||||||
|
= icon('angle-double-left')
|
||||||
|
|
||||||
.status-box{ class: "status-box-#{milestone.closed? ? 'closed' : 'open'}" }
|
.status-box{ class: "status-box-#{milestone.closed? ? 'closed' : 'open'}" }
|
||||||
- if milestone.closed?
|
- if milestone.closed?
|
||||||
Closed
|
Closed
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
title: Move milestone summary content into the sidebar
|
||||||
|
merge_request: 10096
|
||||||
|
author:
|
|
@ -36,7 +36,7 @@ class Spinach::Features::GroupMilestones < Spinach::FeatureSteps
|
||||||
|
|
||||||
step 'I should see group milestone with all issues and MRs assigned to that milestone' do
|
step 'I should see group milestone with all issues and MRs assigned to that milestone' do
|
||||||
expect(page).to have_content('Milestone GL-113')
|
expect(page).to have_content('Milestone GL-113')
|
||||||
expect(page).to have_content('3 issues: 3 open and 0 closed')
|
expect(page).to have_content('Issues 3 Open: 3 Closed: 0')
|
||||||
issue = Milestone.find_by(name: 'GL-113').issues.first
|
issue = Milestone.find_by(name: 'GL-113').issues.first
|
||||||
expect(page).to have_link(issue.title, href: namespace_project_issue_path(issue.project.namespace, issue.project, issue))
|
expect(page).to have_link(issue.title, href: namespace_project_issue_path(issue.project.namespace, issue.project, issue))
|
||||||
end
|
end
|
||||||
|
|
|
@ -23,12 +23,14 @@ feature 'Project milestone', :feature do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'shows issues stats' do
|
it 'shows issues stats' do
|
||||||
expect(page).to have_content 'issues:'
|
expect(find('.milestone-sidebar')).to have_content 'Issues 0'
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'shows Browse Issues button' do
|
it 'shows link to browse and add issues' do
|
||||||
within('#content-body') do
|
within('.milestone-sidebar') do
|
||||||
expect(page).to have_link 'Browse Issues'
|
expect(page).to have_link 'New issue'
|
||||||
|
expect(page).to have_link 'Open: 0'
|
||||||
|
expect(page).to have_link 'Closed: 0'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -48,12 +50,12 @@ feature 'Project milestone', :feature do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'hides issues stats' do
|
it 'hides issues stats' do
|
||||||
expect(page).to have_no_content 'issues:'
|
expect(find('.milestone-sidebar')).not_to have_content 'Issues 0'
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'hides Browse Issues button' do
|
it 'hides new issue button' do
|
||||||
within('#content-body') do
|
within('.milestone-sidebar') do
|
||||||
expect(page).not_to have_link 'Browse Issues'
|
expect(page).not_to have_link 'New issue'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue