Roadmap: more accurate completion percentage calculation (done ratio of open issues is now taken into account).

Issues and issues list: 'done ratio' field now displayed as a progress bar.


git-svn-id: http://redmine.rubyforge.org/svn/trunk@908 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
Jean-Philippe Lang 2007-11-17 15:34:10 +00:00
parent 1469a4c8df
commit 9ad79612fe
7 changed files with 73 additions and 49 deletions

View File

@ -313,6 +313,17 @@ module ApplicationHelper
link_to_function(l(:button_uncheck_all), "checkAll('#{form_name}', false)")
end
def progress_bar(pct, options={})
width = options[:width] || '100px;'
legend = options[:legend] || ''
content_tag('table',
content_tag('tr',
(pct > 0 ? content_tag('td', '', :width => "#{pct.floor}%;", :class => 'closed') : '') +
(pct < 100 ? content_tag('td', '', :width => "#{100-pct.floor}%;", :class => 'open') : '')
), :class => 'progress', :style => "width: #{width};") +
content_tag('p', legend, :class => 'pourcent')
end
def context_menu_link(name, url, options={})
options[:class] ||= ''
if options.delete(:selected)

View File

@ -35,11 +35,16 @@ module QueriesHelper
format_date(value)
elsif value.is_a?(Time)
format_time(value)
elsif column.name == :subject
else
case column.name
when :subject
((@project.nil? || @project != issue.project) ? "#{issue.project.name} - " : '') +
link_to(h(value), :controller => 'issues', :action => 'show', :id => issue)
else
h(value)
when :done_ratio
progress_bar(value, :width => '80px')
else
h(value)
end
end
end
end

View File

@ -39,6 +39,16 @@ class Version < ActiveRecord::Base
effective_date && (effective_date <= Date.today) && (open_issues_count == 0)
end
def completed_pourcent
if fixed_issues.count == 0
0
elsif open_issues_count == 0
100
else
(closed_issues_count * 100 + Issue.sum('done_ratio', :include => 'status', :conditions => ["fixed_version_id = ? AND is_closed = ?", id, false]).to_f) / fixed_issues.count
end
end
# Returns true if the version is overdue: due date reached and some open issues
def overdue?
effective_date && (effective_date < Date.today) && (open_issues_count > 0)

View File

@ -28,7 +28,7 @@
</tr>
<tr>
<td><b><%=l(:field_assigned_to)%> :</b></td><td><%= @issue.assigned_to ? link_to_user(@issue.assigned_to) : "-" %></td>
<td><b><%=l(:field_done_ratio)%> :</b></td><td><%= @issue.done_ratio %> %</td>
<td><b><%=l(:field_done_ratio)%> :</b></td><td><%= progress_bar @issue.done_ratio, :width => '80px', :legend => "#{@issue.done_ratio}%" %></td>
</tr>
<tr>
<td><b><%=l(:field_category)%> :</b></td><td><%=h @issue.category ? @issue.category.name : "-" %></td>

View File

@ -14,44 +14,39 @@
<p><strong><%=l(:label_roadmap_due_in)%> <%= distance_of_time_in_words Time.now, version.effective_date %> (<%= format_date(version.effective_date) %>)</strong></p>
<% end %>
<p><%=h version.description %></p>
<% issues = version.fixed_issues.find(:all,
:include => [:status, :tracker],
:conditions => ["tracker_id in (#{@selected_tracker_ids.join(',')})"],
:order => "#{Tracker.table_name}.position") unless @selected_tracker_ids.empty?
issues ||= []
total = issues.size
complete = issues.inject(0) {|c,i| i.status.is_closed? ? c + 1 : c }
percentComplete = total == 0 ? 100 : (100.0 / total * complete).floor
percentIncomplete = 100 - percentComplete
%>
<table class="progress">
<tr>
<% if percentComplete > 0 %>
<td class="closed" style="width: <%= percentComplete %>%"></td>
<% end; if percentIncomplete > 0 %>
<td class="open" style="width: <%= percentIncomplete %>%"></td>
<% end %>
</tr>
</table>
<em><%= link_to(complete, :controller => 'issues', :action => 'index', :project_id => @project, :status_id => 'c', :fixed_version_id => version, :set_filter => 1) %> <%= lwr(:label_closed_issues, complete) %> (<%= percentComplete %>%) &#160;
<%= link_to((total - complete), :controller => 'issues', :action => 'index', :project_id => @project, :status_id => 'o', :fixed_version_id => version, :set_filter => 1) %> <%= lwr(:label_open_issues, total - complete)%> (<%= percentIncomplete %>%)</em>
<br />
<br />
<%= render(:partial => "wiki/content", :locals => {:content => version.wiki_page.content}) if version.wiki_page %>
<ul>
<% if total == 0 %>
<li><%=l(:label_roadmap_no_issues)%></li>
<% else %>
<% issues.each do |issue| %>
<li>
<%= link = link_to_issue(issue)
issue.status.is_closed? ? content_tag("del", link) : link %>: <%=h issue.subject %>
<%= content_tag "em", "(#{l(:label_closed_issues)})" if issue.status.is_closed? %>
</li>
<% end %>
<% end %>
</ul>
<% if version.fixed_issues.count > 0 %>
<%= progress_bar(version.completed_pourcent, :width => '40em', :legend => ('%0.0f%' % version.completed_pourcent)) %>
<p class="progress-info">
<%= link_to(version.closed_issues_count, :controller => 'issues', :action => 'index', :project_id => @project, :status_id => 'c', :fixed_version_id => version, :set_filter => 1) %>
<%= lwr(:label_closed_issues, version.closed_issues_count) %>
(<%= '%0.0f' % (version.closed_issues_count.to_f / version.fixed_issues.count * 100) %>%)
&#160;
<%= link_to(version.open_issues_count, :controller => 'issues', :action => 'index', :project_id => @project, :status_id => 'o', :fixed_version_id => version, :set_filter => 1) %>
<%= lwr(:label_open_issues, version.open_issues_count)%>
(<%= '%0.0f' % (version.open_issues_count.to_f / version.fixed_issues.count * 100) %>%)
</p>
<%= render(:partial => "wiki/content", :locals => {:content => version.wiki_page.content}) if version.wiki_page %>
<% issues = version.fixed_issues.find(:all,
:include => [:status, :tracker],
:conditions => ["tracker_id in (#{@selected_tracker_ids.join(',')})"],
:order => "#{Tracker.table_name}.position") unless @selected_tracker_ids.empty?
issues ||= []
%>
<ul>
<% if issues.size > 0 %>
<% issues.each do |issue| %>
<li>
<%= link = link_to_issue(issue)
issue.status.is_closed? ? content_tag("del", link) : link %>: <%=h issue.subject %>
<%= content_tag "em", "(#{l(:label_closed_issues)})" if issue.status.is_closed? %>
</li>
<% end %>
<% end %>
</ul>
<% else %>
<p><em><%= l(:label_roadmap_no_issues) %></em></p>
<% end %>
<% end %>
<% content_for :sidebar do %>

View File

@ -75,6 +75,7 @@ table.list td.checkbox { width: 15px; padding: 0px;}
tr.issue { text-align: center; white-space: nowrap; }
tr.issue td.subject, tr.issue td.category { white-space: normal; }
tr.issue td.subject { text-align: left; }
tr.issue td.done_ratio table.progress { margin-left:auto; margin-right: auto;}
table.list tbody tr:hover { background-color:#ffffdd; }
table td {padding:2px;}
@ -242,19 +243,21 @@ color:#505050;
}
/***** Progress bar *****/
.progress {
table.progress {
border: 1px solid #D7D7D7;
border-collapse: collapse;
border-spacing: 0pt;
empty-cells: show;
padding: 3px;
width: 40em;
text-align: center;
float:left;
margin: 1px 6px 1px 0px;
}
.progress td { height: 1em; }
.progress .closed { background: #BAE0BA none repeat scroll 0%; }
.progress .open { background: #FFF none repeat scroll 0%; }
table.progress td { height: 0.9em; }
table.progress td.closed { background: #BAE0BA none repeat scroll 0%; }
table.progress td.open { background: #FFF none repeat scroll 0%; }
p.pourcent {font-size: 80%;}
p.progress-info {clear: left; font-style: italic; font-size: 80%;}
/***** Tabs *****/
#content .tabs{height: 2.6em;}

View File

@ -1,4 +1,4 @@
#context-menu { position: absolute; }
#context-menu { position: absolute; z-index: 10;}
#context-menu ul, #context-menu li, #context-menu a {
display:block;