Feature #34830 » issues-burndown-in-version-detail.patch
app/helpers/versions_helper.rb | ||
---|---|---|
104 | 104 |
end |
105 | 105 |
end |
106 | 106 |
end |
107 | ||
108 |
def issues_burndown_chart_data(version) |
|
109 |
return nil if version.visible_fixed_issues.empty? |
|
110 |
chart_start_date = (version.start_date || version.created_on).to_date |
|
111 |
chart_end_date = [version.due_date, version.visible_fixed_issues.maximum(:due_date), version.visible_fixed_issues.maximum(:updated_on)].compact.max.to_date |
|
112 |
line_end_date = [User.current.today, chart_end_date].min |
|
113 |
step_size = ((chart_start_date..chart_end_date).count.to_f / 90).ceil |
|
114 |
issues = version.visible_fixed_issues |
|
115 |
return nil if step_size < 1 |
|
116 |
total_closed = chart_start_date.step(line_end_date, step_size).collect{|d| {:t => d.to_s, :y => issues.where("#{Issue.table_name}.closed_on IS NULL OR #{Issue.table_name}.closed_on>=?", d.end_of_day).count}} |
|
117 |
open = chart_start_date.step(line_end_date, step_size).collect{|d| {:t => d.to_s, :y => issues.where("#{Issue.table_name}.created_on<=?", d.end_of_day).count - issues.open(false).where("#{Issue.table_name}.closed_on<=?", d.end_of_day).count}} |
|
118 |
chart_data = { |
|
119 |
:labels => chart_start_date.step(chart_end_date, step_size).collect{|d|d.to_s}, |
|
120 |
:datasets => [ |
|
121 |
{:label => l(:label_ideal), :data => [{:t => chart_start_date.to_s, :y => total_closed.first[:y]}, {:t => chart_end_date.to_s, :y => 0}], |
|
122 |
:backgroundColor => "rgba(0, 0, 0, 0)", |
|
123 |
:lineTension => 0, :borderWidth => 2, :borderDash => [5, 2], :spanGaps => true}, |
|
124 |
{:label => l(:label_total_substract_closed), :data => total_closed, |
|
125 |
:borderColor => "rgba(186, 224, 186, 1)", :backgroundColor => "rgba(0, 0, 0, 0)", :pointBackgroundColor => "rgba(186, 224, 186, 1)", |
|
126 |
:lineTension => 0, :borderWidth => 2, :borderDash => [5, 2]}, |
|
127 |
{:label => l(:label_open), :data => open, |
|
128 |
:borderColor => "rgba(186, 224, 186, 1)", :backgroundColor => "rgba(186, 224, 186, 0.1)", :pointBackgroundColor => "rgba(186, 224, 186, 1)", |
|
129 |
:lineTension => 0, :borderWidth => 2} |
|
130 |
] |
|
131 |
} |
|
132 |
return chart_data |
|
133 |
end |
|
107 | 134 |
end |
app/views/versions/show.html.erb | ||
---|---|---|
52 | 52 |
<% end %> |
53 | 53 |
</table> |
54 | 54 |
<% end %> |
55 |
<div class="version-report-graph"> |
|
56 |
<canvas id="version_chart"></canvas> |
|
57 |
</div> |
|
55 | 58 |
<%= context_menu %> |
56 | 59 |
<% end %> |
57 | 60 |
</div> |
... | ... | |
59 | 62 |
<%= call_hook :view_versions_show_bottom, :version => @version %> |
60 | 63 | |
61 | 64 |
<% html_title @version.name %> |
65 |
<% if chart_data = issues_burndown_chart_data(@version) %> |
|
66 |
<%= javascript_tag do %> |
|
67 |
function renderChart(canvas_id, title, y_label, chartData){ |
|
68 |
new Chart($(canvas_id), { |
|
69 |
type: 'line', |
|
70 |
data: chartData, |
|
71 |
options: { |
|
72 |
responsive: true, |
|
73 |
legend: { |
|
74 |
position: 'right', |
|
75 |
labels: { boxWidth: 20, fontSize: 10, padding: 10 } |
|
76 |
}, |
|
77 |
title: { display: true, text: title }, |
|
78 |
tooltips: { |
|
79 |
callbacks: { |
|
80 |
title: function(tooltipItem, data) { return '' } |
|
81 |
} |
|
82 |
}, |
|
83 |
scales: { |
|
84 |
xAxes: [{ |
|
85 |
type: "time", |
|
86 |
time: { unit: "day", displayFormats: { day: 'YYYY-MM-DD' } }, |
|
87 |
gridLines: { borderDash: [6, 4] }, |
|
88 |
ticks: { source: 'labels', autoSkip: true } |
|
89 |
}], |
|
90 |
yAxes: [{ |
|
91 |
scaleLabel: { display: true, labelString: y_label }, |
|
92 |
gridLines: { borderDash: [6, 4] }, |
|
93 |
ticks: { min: 0, max: <%= @version.fixed_issues.count %>, stepSize: 1 } |
|
94 |
}] |
|
95 |
} |
|
96 |
} |
|
97 |
}); |
|
98 |
} |
|
99 |
$(document).ready(function(){ |
|
100 |
var title = "<%= l(:label_issues_burndown) %>"; |
|
101 |
var y_label = "<%= l(:label_issues_burndown_y_label) %>"; |
|
102 |
var chartData = <%= chart_data.to_json.html_safe %>; |
|
103 |
renderChart("#version_chart", title, y_label, chartData); |
|
104 |
}); |
|
105 |
<% end %> |
|
106 |
<% content_for :header_tags do %> |
|
107 |
<%= javascript_include_tag "Chart.bundle.min" %> |
|
108 |
<% end %> |
|
109 |
<% end %> |
config/locales/en.yml | ||
---|---|---|
731 | 731 |
label_total: Total |
732 | 732 |
label_total_plural: Totals |
733 | 733 |
label_total_time: Total time |
734 |
label_issues_burndown: burndown |
|
735 |
label_issues_burndown_y_label: Number of Issues |
|
736 |
label_ideal: Ideal |
|
737 |
label_total_substract_closed: Total - Closed |
|
738 |
label_open: Open |
|
734 | 739 |
label_permissions: Permissions |
735 | 740 |
label_current_status: Current status |
736 | 741 |
label_new_statuses_allowed: New statuses allowed |
public/stylesheets/application.css | ||
---|---|---|
630 | 630 |
div#roadmap .wiki h2 { font-size: 110%; } |
631 | 631 |
div#roadmap h2, div#roadmap h3 {padding-right: 0;} |
632 | 632 |
body.controller-versions.action-show div#roadmap .related-issues {width:70%;} |
633 |
body.controller-versions.action-show div#roadmap .version-report-graph { width: 70%; margin: 2em 0 } |
|
633 | 634 | |
634 | 635 |
div#version-summary { float:right; width:28%; margin-left: 16px; margin-bottom: 16px; background-color: #fff; } |
635 | 636 |
div#version-summary fieldset { margin-bottom: 1em; } |
public/stylesheets/responsive.css | ||
---|---|---|
666 | 666 |
.version-overview table.progress {width:75%;} |
667 | 667 |
div#version-summary {float:none; width:100%; margin-left:0;} |
668 | 668 |
body.controller-versions.action-show div#roadmap .related-issues {width:100%;} |
669 |
body.controller-versions.action-show div#roadmap .version-report-graph {width:100%;} |
|
669 | 670 | |
670 | 671 |
/* History and Changeset */ |
671 | 672 |
div#issue-changesets { |
test/helpers/version_helper_test.rb | ||
---|---|---|
25 | 25 |
fixtures :projects, :versions, :enabled_modules, |
26 | 26 |
:users, :members, :roles, :member_roles, |
27 | 27 |
:trackers, :projects_trackers, |
28 |
:enumerations, |
|
28 | 29 |
:issue_statuses |
29 | 30 | |
30 | 31 |
def test_version_filtered_issues_path_sharing_none |
... | ... | |
120 | 121 |
# href should contain param tracker_id=2 because for tracker_id 1, user has only readonly permissions on fixed_version_id |
121 | 122 |
assert_select_in link_to_new_issue(version, project), '[href=?]', '/projects/ecookbook/issues/new?back_url=%2Fversions%2F3&issue%5Bfixed_version_id%5D=3&issue%5Btracker_id%5D=2' |
122 | 123 |
end |
124 | ||
125 |
def test_issues_burndown_chart_data_should_return_chart_data |
|
126 |
User.any_instance.stubs(:today).returns(3.days.after.to_date) |
|
127 |
version = Version.create!(:project => Project.find(1), :name => 'test', :due_date => 5.days.after.to_date) |
|
128 |
issue = Issue.create!(:project => version.project, :fixed_version => version, |
|
129 |
:priority => IssuePriority.find_by_name('Normal'), |
|
130 |
:tracker => version.project.trackers.first, :subject => 'text', :author => User.current, |
|
131 |
:start_date => 1.days.after.to_date) |
|
132 |
chart_data = { |
|
133 |
:labels => (1.days.after.to_date..5.days.after.to_date).map { |d| d.to_s }, |
|
134 |
:datasets => [ |
|
135 |
{:label => l(:label_ideal), :data => [{:t => 1.days.after.to_date.to_s, :y => 1}, {:t => 5.days.after.to_date.to_s, :y => 0}], |
|
136 |
:backgroundColor => "rgba(0, 0, 0, 0)", |
|
137 |
:lineTension => 0, :borderWidth => 2, :borderDash => [5, 2], :spanGaps => true}, |
|
138 |
{:label => l(:label_total_substract_closed), :data => [{:t => 1.days.after.to_date.to_s, :y => 1}, {:t => 2.days.after.to_date.to_s, :y => 1}, {:t => 3.days.after.to_date.to_s, :y => 1}], |
|
139 |
:borderColor => "rgba(186, 224, 186, 1)", :backgroundColor => "rgba(0, 0, 0, 0)", :pointBackgroundColor => "rgba(186, 224, 186, 1)", |
|
140 |
:lineTension => 0, :borderWidth => 2, :borderDash => [5, 2]}, |
|
141 |
{:label => l(:label_open), :data => [{:t => 1.days.after.to_date.to_s, :y => 1}, {:t => 2.days.after.to_date.to_s, :y => 1}, {:t => 3.days.after.to_date.to_s, :y => 1}], |
|
142 |
:borderColor => "rgba(186, 224, 186, 1)", :backgroundColor => "rgba(186, 224, 186, 0.1)", :pointBackgroundColor => "rgba(186, 224, 186, 1)", |
|
143 |
:lineTension => 0, :borderWidth => 2} |
|
144 |
] |
|
145 |
} |
|
146 |
assert_equal chart_data, issues_burndown_chart_data(version) |
|
147 |
end |
|
148 | ||
149 |
def test_issues_burndown_chart_data_should_return_nil_when_visible_fixed_issues_empty |
|
150 |
version = Version.create!(:project => Project.find(1), :name => 'test') |
|
151 |
version.visible_fixed_issues.destroy_all |
|
152 |
assert_empty version.visible_fixed_issues |
|
153 |
assert_nil issues_burndown_chart_data(version) |
|
154 |
end |
|
155 | ||
156 |
def test_issues_burndown_chart_data_should_return_nil_when_order_of_start_date_and_due_date_is_reversed |
|
157 |
version = Version.create!(:project => Project.find(1), :name => 'test', :due_date => 10.days.after) |
|
158 |
issue = Issue.create!(:project => version.project, :fixed_version => version, |
|
159 |
:priority => IssuePriority.find_by_name('Normal'), |
|
160 |
:tracker => version.project.trackers.first, :subject => 'text', :author => User.current, |
|
161 |
:start_date => 11.days.after) |
|
162 |
assert_nil issues_burndown_chart_data(version) |
|
163 |
end |
|
123 | 164 |
end |
- « Previous
- 1
- 2
- Next »