Feature #31581 » issue-burnup-chart-in-the-version-detail.patch
app/helpers/versions_helper.rb | ||
---|---|---|
73 | 73 |
def status_by_options_for_select(value) |
74 | 74 |
options_for_select(STATUS_BY_CRITERIAS.collect {|criteria| [l("field_#{criteria}".to_sym), criteria]}, value) |
75 | 75 |
end |
76 | ||
77 |
def version_burnup_chart_data(version) |
|
78 |
return nil if version.visible_fixed_issues.empty? |
|
79 |
chart_start_date = (version.start_date || version.created_on).to_date |
|
80 |
chart_end_date = [version.due_date, version.visible_fixed_issues.maximum(:due_date), version.visible_fixed_issues.maximum(:updated_on)].compact.max.to_date |
|
81 |
line_end_date = [User.current.today, chart_end_date].min |
|
82 |
step_size = ((chart_start_date..chart_end_date).count.to_f / 90).ceil |
|
83 |
return nil if step_size < 1 |
|
84 |
reported = line_end_date.step(chart_start_date, -step_size).collect{|d| {:t => d.to_s, :y => version.visible_fixed_issues.where("#{Issue.table_name}.created_on<=?", d.end_of_day).count}} |
|
85 |
closed = line_end_date.step(chart_start_date, -step_size).collect{|d| {:t => d.to_s, :y => version.visible_fixed_issues.open(false).where("#{Issue.table_name}.closed_on<=?", d.end_of_day).count}} |
|
86 |
chart_data = { |
|
87 |
:labels => chart_end_date.step(chart_start_date, -step_size).collect{|d|d.to_s}, |
|
88 |
:datasets => [ |
|
89 |
{:label => l(:label_reported_issues), :data => reported, |
|
90 |
:borderColor => "rgba(128, 128, 128, 1)", :backgroundColor => "rgba(128, 128, 128, 0.1)", :pointBackgroundColor => "rgba(128, 128, 128, 1)", |
|
91 |
:lineTension => 0, :borderWidth => 2}, |
|
92 |
{:label => l(:label_closed_issues), :data => closed, |
|
93 |
:borderColor => "rgba(186, 224, 186, 1)", :backgroundColor => "rgba(186, 224, 186, 0.1)", :pointBackgroundColor => "rgba(186, 224, 186, 1)", |
|
94 |
:lineTension => 0, :borderWidth => 2} |
|
95 |
] |
|
96 |
} |
|
97 |
return chart_data |
|
98 |
end |
|
76 | 99 |
end |
app/views/versions/show.html.erb | ||
---|---|---|
51 | 51 |
<% end %> |
52 | 52 |
</table> |
53 | 53 |
<% end %> |
54 |
<div class="version-report-graph"> |
|
55 |
<canvas id="version_chart"></canvas> |
|
56 |
</div> |
|
54 | 57 |
<%= context_menu %> |
55 | 58 |
<% end %> |
56 | 59 |
</div> |
... | ... | |
58 | 61 |
<%= call_hook :view_versions_show_bottom, :version => @version %> |
59 | 62 | |
60 | 63 |
<% html_title @version.name %> |
64 |
<% if chart_data = version_burnup_chart_data(@version) %> |
|
65 |
<%= javascript_tag do %> |
|
66 |
function renderChart(canvas_id, title, chartData){ |
|
67 |
new Chart($(canvas_id), { |
|
68 |
type: 'line', |
|
69 |
data: chartData, |
|
70 |
options: { |
|
71 |
responsive: true, |
|
72 |
legend: { |
|
73 |
position: 'right', |
|
74 |
labels: { boxWidth: 20, fontSize: 10, padding: 10 } |
|
75 |
}, |
|
76 |
title: { display: true, text: title }, |
|
77 |
tooltips: { |
|
78 |
callbacks: { |
|
79 |
title: function(tooltipItem, data) { return '' } |
|
80 |
} |
|
81 |
}, |
|
82 |
scales: { |
|
83 |
xAxes: [{ |
|
84 |
type: "time", |
|
85 |
time: { unit: "day", displayFormats: { day: 'YYYY-MM-DD' } }, |
|
86 |
gridLines: { borderDash: [6, 4] }, |
|
87 |
ticks: { source: 'labels', autoSkip: true } |
|
88 |
}], |
|
89 |
yAxes: [{ |
|
90 |
gridLines: { borderDash: [6, 4] }, |
|
91 |
ticks: { min: 0, max: <%= @version.fixed_issues.count + 1 %>, stepSize: 1 } |
|
92 |
}] |
|
93 |
} |
|
94 |
} |
|
95 |
}); |
|
96 |
} |
|
97 |
$(document).ready(function(){ |
|
98 |
var chartData = <%= chart_data.to_json.html_safe %>; |
|
99 |
renderChart("#version_chart", "Issues burnup", chartData); |
|
100 |
}); |
|
101 |
<% end %> |
|
102 |
<% content_for :header_tags do %> |
|
103 |
<%= javascript_include_tag "Chart.bundle.min" %> |
|
104 |
<% end %> |
|
105 |
<% end %> |
public/stylesheets/application.css | ||
---|---|---|
585 | 585 |
div#roadmap .wiki h2 { font-size: 110%; } |
586 | 586 |
div#roadmap h2, div#roadmap h3 { display: inline; padding-right: 0;} |
587 | 587 |
body.controller-versions.action-show div#roadmap .related-issues {width:70%;} |
588 |
body.controller-versions.action-show div#roadmap .version-report-graph { width: 70%; margin: 2em 0 } |
|
588 | 589 | |
589 | 590 |
div#version-summary { float:right; width:28%; margin-left: 16px; margin-bottom: 16px; background-color: #fff; } |
590 | 591 |
div#version-summary fieldset { margin-bottom: 1em; } |
public/stylesheets/responsive.css | ||
---|---|---|
679 | 679 |
.version-overview table.progress {width:75%;} |
680 | 680 |
div#version-summary {float:none; width:100%; margin-left:0;} |
681 | 681 |
body.controller-versions.action-show div#roadmap .related-issues {width:100%;} |
682 |
body.controller-versions.action-show div#roadmap .version-report-graph {width:100%;} |
|
682 | 683 | |
683 | 684 |
/* History and Changeset */ |
684 | 685 |
div#issue-changesets { |
test/helpers/version_helper_test.rb | ||
---|---|---|
53 | 53 |
version.project = Project.find(5) |
54 | 54 |
assert_match /^\/issues\?/, version_filtered_issues_path(version) |
55 | 55 |
end |
56 | ||
57 |
def test_version_burnup_chart_data_should_return_chart_data |
|
58 |
User.any_instance.stubs(:today).returns(3.days.after.to_date) |
|
59 |
version = Version.create!(:project => Project.find(1), :name => 'test', :due_date => 5.days.after) |
|
60 |
issue = Issue.create!(:project => version.project, :fixed_version => version, |
|
61 |
:tracker => version.project.trackers.first, :subject => 'text', :author => User.current, |
|
62 |
:start_date => 1.days.after) |
|
63 |
chart_data = { |
|
64 |
:labels => [5.days.after.to_date.to_s, 4.days.after.to_date.to_s, 3.days.after.to_date.to_s, 2.days.after.to_date.to_s, 1.days.after.to_date.to_s], |
|
65 |
:datasets => [ |
|
66 |
{:label => l(:label_reported_issues), |
|
67 |
:data => [{:t => 3.days.after.to_date.to_s, :y => 1}, {:t => 2.days.after.to_date.to_s, :y => 1}, {:t => 1.days.after.to_date.to_s, :y => 1}], |
|
68 |
:borderColor => "rgba(128, 128, 128, 1)", :backgroundColor => "rgba(128, 128, 128, 0.1)", :pointBackgroundColor => "rgba(128, 128, 128, 1)", |
|
69 |
:lineTension => 0, :borderWidth => 2}, |
|
70 |
{:label => l(:label_closed_issues), |
|
71 |
:data => [{:t => 3.days.after.to_date.to_s, :y => 0}, {:t => 2.days.after.to_date.to_s, :y => 0}, {:t => 1.days.after.to_date.to_s, :y => 0}], |
|
72 |
:borderColor => "rgba(186, 224, 186, 1)", :backgroundColor => "rgba(186, 224, 186, 0.1)", :pointBackgroundColor => "rgba(186, 224, 186, 1)", |
|
73 |
:lineTension => 0, :borderWidth => 2} |
|
74 |
] |
|
75 |
} |
|
76 |
assert_equal chart_data, version_burnup_chart_data(version) |
|
77 |
end |
|
78 | ||
79 |
def test_version_burnup_chart_data_should_return_nil_when_visible_fixed_issues_empty |
|
80 |
version = Version.create!(:project => Project.find(1), :name => 'test') |
|
81 |
version.visible_fixed_issues.destroy_all |
|
82 |
assert_empty version.visible_fixed_issues |
|
83 |
assert_nil version_burnup_chart_data(version) |
|
84 |
end |
|
85 | ||
86 |
def test_version_burnup_chart_data_should_return_nil_when_order_of_start_date_and_due_date_is_reversed |
|
87 |
version = Version.create!(:project => Project.find(1), :name => 'test', :due_date => 10.days.after) |
|
88 |
issue = Issue.create!(:project => version.project, :fixed_version => version, |
|
89 |
:tracker => version.project.trackers.first, :subject => 'text', :author => User.current, |
|
90 |
:start_date => 11.days.after) |
|
91 |
assert_nil version_burnup_chart_data(version) |
|
92 |
end |
|
56 | 93 |
end |