Project

General

Profile

Feature #1244 ยป version-dependency.patch

Kenneth Hoxworth, 2008-09-23 16:20

View differences:

app/helpers/versions_helper.rb (working copy)
26 26
    h = Hash.new {|k,v| k[v] = [0, 0]}
27 27
    begin
28 28
      # Total issue count
29
      Issue.count(:group => criteria,
30
                  :conditions => ["#{Issue.table_name}.fixed_version_id = ?", version.id]).each {|c,s| h[c][0] = s}
31
      # Open issues count
32
      Issue.count(:group => criteria,
33
                  :include => :status,
34
                  :conditions => ["#{Issue.table_name}.fixed_version_id = ? AND #{IssueStatus.table_name}.is_closed = ?", version.id, false]).each {|c,s| h[c][1] = s}
29
      if version.children.count > 0
30
        Issue.count(:group => criteria,
31
                    :conditions => ["#{Issue.table_name}.fixed_version_id = ? OR #{Issue.table_name}.fixed_version_id IN (#{version.children.collect{|p| p.id}.join(',')})", version.id]).each {|c,s| h[c][0] = s}
32
        # Open issues count
33
        Issue.count(:group => criteria,
34
                    :include => :status,
35
                    :conditions => ["(#{Issue.table_name}.fixed_version_id = ? OR #{Issue.table_name}.fixed_version_id IN (#{version.children.collect{|p| p.id}.join(',')})) AND #{IssueStatus.table_name}.is_closed = ?", version.id, false]).each {|c,s| h[c][1] = s}
36
      else
37
        Issue.count(:group => criteria,
38
                    :conditions => ["#{Issue.table_name}.fixed_version_id = ?", version.id]).each {|c,s| h[c][0] = s}
39
        # Open issues count
40
        Issue.count(:group => criteria,
41
                    :include => :status,
42
                    :conditions => ["#{Issue.table_name}.fixed_version_id = ? AND #{IssueStatus.table_name}.is_closed = ?", version.id, false]).each {|c,s| h[c][1] = s}
43
      end
35 44
    rescue ActiveRecord::RecordNotFound
36 45
    # When grouping by an association, Rails throws this exception if there's no result (bug)
37 46
    end
app/models/version.rb (working copy)
18 18
class Version < ActiveRecord::Base
19 19
  before_destroy :check_integrity
20 20
  belongs_to :project
21
  has_many :fixed_issues, :class_name => 'Issue', :foreign_key => 'fixed_version_id'
21
  belongs_to :parent, :class_name => "Version", :foreign_key => "parent_version_id"
22
  has_many :children, :class_name => "Version", :foreign_key => "parent_version_id"
23
  has_many :fixed_issues, :class_name => 'Issue', :finder_sql => 'select distinct i.* from issues i,versions v WHERE i.fixed_version_id = #{id} OR (i.fixed_version_id = v.id AND v.parent_version_id = #{id})', :counter_sql => 'select count(distinct i.id) from issues i,versions v WHERE i.fixed_version_id = #{id} OR (i.fixed_version_id = v.id AND v.parent_version_id = #{id})'
22 24
  has_many :attachments, :as => :container, :dependent => :destroy
23 25

  
24 26
  validates_presence_of :name
......
36 38
  
37 39
  # Returns the total estimated time for this version
38 40
  def estimated_hours
39
    @estimated_hours ||= fixed_issues.sum(:estimated_hours).to_f
41
    hours = 0
42
    fixed_issues.each {|i| hours += i.estimated_hours.to_f}
43
    @estimated_hours ||= hours
40 44
  end
41 45
  
42 46
  # Returns the total reported time for this version
43 47
  def spent_hours
44
    @spent_hours ||= TimeEntry.sum(:hours, :include => :issue, :conditions => ["#{Issue.table_name}.fixed_version_id = ?", id]).to_f
48
    if self.children.count > 0
49
      @spent_hours ||= TimeEntry.sum(:hours, :include => :issue, :conditions => ["#{Issue.table_name}.fixed_version_id = ? OR #{Issue.table_name}.fixed_version_id IN (#{self.children.collect{|p| p.id}.join(',')})", id]).to_f
50
    else 
51
      @spent_hours ||= TimeEntry.sum(:hours, :include => :issue, :conditions => ["#{Issue.table_name}.fixed_version_id = ?", id]).to_f
52
    end
45 53
  end
46 54
  
47 55
  # Returns true if the version is completed: due date reached and no open issues
......
54 62
      0
55 63
    elsif open_issues_count == 0
56 64
      100
57
    else
58
      (closed_issues_count * 100 + Issue.sum('done_ratio', :include => 'status', :conditions => ["fixed_version_id = ? AND is_closed = ?", id, false]).to_f) / fixed_issues.count
65
    elsif self.children.count > 0
66
      (closed_issues_count * 100 + Issue.sum('done_ratio', :include => 'status', :conditions => ["(fixed_version_id = ? OR fixed_version_id IN (#{self.children.collect{|p| p.id}.join(',')})) AND is_closed = ?", id, false]).to_f) / fixed_issues.count
67
    else 
68
      (closed_issues_count * 100 + Issue.sum('done_ratio', :include => 'status', :conditions => ["(fixed_version_id = ?) AND is_closed = ?", id, false]).to_f) / fixed_issues.count
59 69
    end
60 70
  end
61 71
  
......
73 83
  end
74 84
  
75 85
  def open_issues_count
76
    @open_issues_count ||= Issue.count(:all, :conditions => ["fixed_version_id = ? AND is_closed = ?", self.id, false], :include => :status)
86
    if self.children.count > 0
87
      @open_issues_count ||= Issue.count(:all, :conditions => ["(fixed_version_id = ? OR fixed_version_id IN (#{self.children.collect{|p| p.id}.join(',')})) AND is_closed = ?", self.id, false], :include => :status)
88
    else
89
      @open_issues_count ||= Issue.count(:all, :conditions => ["(fixed_version_id = ?) AND is_closed = ?", self.id, false], :include => :status)
90
    end
77 91
  end
78 92

  
79 93
  def closed_issues_count
80
    @closed_issues_count ||= Issue.count(:all, :conditions => ["fixed_version_id = ? AND is_closed = ?", self.id, true], :include => :status)
94
    if self.children.count > 0
95
      @closed_issues_count ||= Issue.count(:all, :conditions => ["(fixed_version_id = ? OR fixed_version_id IN (#{self.children.collect{|p| p.id}.join(',')})) AND is_closed = ?", self.id, true], :include => :status)
96
    else
97
      @closed_issues_count ||= Issue.count(:all, :conditions => ["(fixed_version_id = ?) AND is_closed = ?", self.id, true], :include => :status) 
98
    end
81 99
  end
82 100
  
83 101
  def wiki_page
app/controllers/versions_controller.rb (working copy)
23 23
  end
24 24
  
25 25
  def edit
26
    @versions = Version.find(:all, :conditions => ["id <> ? AND parent_version_id IS NULL", params[:id]]).collect{|p| [ p.name, p.id ] }
26 27
    if request.post? and @version.update_attributes(params[:version])
27 28
      flash[:notice] = l(:notice_successful_update)
28 29
      redirect_to :controller => 'projects', :action => 'settings', :tab => 'versions', :id => @project
app/controllers/projects_controller.rb (working copy)
180 180
  # Add a new version to @project
181 181
  def add_version
182 182
  	@version = @project.versions.build(params[:version])
183
  	@versions = Version.find(:all, :conditions => ["parent_version_id IS NULL"]).collect{|p| [ p.name, p.id ] }
183 184
  	if request.post? and @version.save
184 185
  	  flash[:notice] = l(:notice_successful_create)
185 186
      redirect_to :action => 'settings', :tab => 'versions', :id => @project
......
213 214
  def roadmap
214 215
    @trackers = @project.trackers.find(:all, :conditions => ["is_in_roadmap=?", true])
215 216
    retrieve_selected_tracker_ids(@trackers)
216
    @versions = @project.versions.sort
217
    @versions = (@project.versions.delete_if {|x| x.parent_version_id }).sort
217 218
    @versions = @versions.select {|v| !v.completed? } unless params[:completed]
218 219
  end
219 220
  
app/views/versions/show.rhtml (working copy)
2 2
<%= link_to_if_authorized l(:button_edit), {:controller => 'versions', :action => 'edit', :id => @version}, :class => 'icon icon-edit' %>
3 3
</div>
4 4

  
5
<h2><%= h(@version.name) %></h2>
5
<h2><%= h(@version.name) %> <% if @version.parent_version_id %>
6
(<%= l(:label_child_of)%> <%= link_to @version.parent.name, :controller => 'versions', :action => 'show', :id => @version.parent.id %>)
7
<% end %></h2>
6 8

  
7 9
<div id="version-summary">
8 10
<% if @version.estimated_hours > 0 || User.current.allowed_to?(:view_time_entries, @project) %>
......
25 27
<div id="status_by">
26 28
<%= render_issue_status_by(@version, params[:status_by]) if @version.fixed_issues.count > 0 %>
27 29
</div>
30

  
31
<% if @version.children.count > 0 %>
32
<div id="child_versions">
33
	<fieldset>
34
		<legend><%= l(:label_child_versions)%></legend>
35
		<ul>
36
		<% @version.children.each do |v| %>
37
		<li><%= link_to v.name, :controller => 'versions', :action => 'show', :id => v.id %></li>
38
		<% end %>
39
		</ul>
40
	</fieldset>
28 41
</div>
42
<% end %>
29 43

  
44
</div>
45

  
30 46
<div id="roadmap">
31 47
<%= render :partial => 'versions/overview', :locals => {:version => @version} %>
32 48
<%= render(:partial => "wiki/content", :locals => {:content => @version.wiki_page.content}) if @version.wiki_page %>
......
34 50
<% issues = @version.fixed_issues.find(:all,
35 51
                                       :include => [:status, :tracker],
36 52
                                       :order => "#{Tracker.table_name}.position, #{Issue.table_name}.id") %>
37
<% if issues.size > 0 %>
53
<% if issues && issues.size > 0 %>
38 54
<fieldset class="related-issues"><legend><%= l(:label_related_issues) %></legend>
39 55
<ul>
40 56
<% issues.each do |issue| -%>
app/views/versions/_form.rhtml (working copy)
5 5
<p><%= f.text_field :description, :size => 60 %></p>
6 6
<p><%= f.text_field :wiki_page_title, :label => :label_wiki_page, :size => 60, :disabled => @project.wiki.nil? %></p>
7 7
<p><%= f.text_field :effective_date, :size => 10 %><%= calendar_for('version_effective_date') %></p>
8
<p><%= f.select :parent_version_id, @versions, {:include_blank => true} %></p>
8 9
</div>
app/views/versions/_issue_counts.rhtml (working copy)
15 15
    <% counts.each do |count| %>
16 16
    <tr>
17 17
        <td width="130px" align="right" >
18
            <%= link_to count[:group], {:controller => 'issues', 
19
                                        :action => 'index',
20
                                        :project_id => version.project,
21
                                        :set_filter => 1,
22
                                        :fixed_version_id => version,
23
                                        "#{criteria}_id" => count[:group]} %>
18
			<% puts "BOO " + (version.fixed_issues.collect {|p| p.fixed_version_id} ).uniq.to_s %>
19
			<%= link_to count[:group], {:controller => 'issues', 
20
										:action => 'index', 
21
										:project_id => version.project, 
22
										:set_filter => 1, 
23
										:fields => ["#{criteria}_id", "fixed_version_id"], 
24
										:operators => { :start_date => "<t+", 
25
														:created_on => ">t-", 
26
														:estimated_hours => "=", 
27
														:updated_on => ">t-", 
28
														:priority_id => "=", 
29
														:subject => "~", 
30
														:fixed_version_id => "=", 
31
														:category_id =>"=", 
32
														:tracker_id => "=", 
33
														:done_ratio =>"=", 
34
														:due_date => "<t+", 
35
														:assigned_to_id => "=", 
36
														:author_id => "=", 
37
														:status_id => "o" },
38
										:values => {:fixed_version_id => (version.fixed_issues.collect {|p| p.fixed_version_id} ).uniq, 
39
													"#{criteria}_id".to_sym => [count[:group]]} } %>
24 40
        </td>
25 41
        <td width="240px">
26 42
            <%= progress_bar((count[:closed].to_f / count[:total])*100, 
app/views/versions/_overview.rhtml (working copy)
9 9
<% if version.fixed_issues.count > 0 %>
10 10
    <%= progress_bar([version.closed_pourcent, version.completed_pourcent], :width => '40em', :legend => ('%0.0f%' % version.completed_pourcent)) %>
11 11
    <p class="progress-info">
12
        <%= link_to(version.closed_issues_count, :controller => 'issues', :action => 'index', :project_id => version.project, :status_id => 'c', :fixed_version_id => version, :set_filter => 1) %>
12
        <%= link_to(version.closed_issues_count, :controller => 'issues', :action => 'index', :project_id => version.project, :set_filter => 1, :fields => ["status_id", "fixed_version_id"], :operators => {:fixed_version_id => "=",:status_id => "c"}, :values => {:fixed_version_id => (version.fixed_issues.collect {|p| p.fixed_version_id} ).uniq, :status_id =>["1"]}) %>
13 13
        <%= lwr(:label_closed_issues, version.closed_issues_count) %>
14 14
        (<%= '%0.0f' % (version.closed_issues_count.to_f / version.fixed_issues.count * 100) %>%)
15 15
        &#160;
16
        <%= link_to(version.open_issues_count, :controller => 'issues', :action => 'index', :project_id => version.project, :status_id => 'o', :fixed_version_id => version, :set_filter => 1) %>
16
        <%= link_to(version.open_issues_count, :controller => 'issues', :action => 'index', :project_id => version.project, :set_filter => 1, :fields => ["status_id", "fixed_version_id"], :operators => {:fixed_version_id => "=",:status_id => "o"}, :values => {:fixed_version_id => (version.fixed_issues.collect {|p| p.fixed_version_id} ).uniq, :status_id =>["1"]}) %>
17 17
        <%= lwr(:label_open_issues, version.open_issues_count)%>
18 18
        (<%= '%0.0f' % (version.open_issues_count.to_f / version.fixed_issues.count * 100) %>%)
19 19
    </p>
app/views/projects/roadmap.rhtml (working copy)
5 5
<% else %>
6 6
<div id="roadmap">
7 7
<% @versions.each do |version| %>   
8
	<div class="top-level-version">
8 9
    <%= tag 'a', :name => version.name %>
9 10
    <h3 class="icon22 icon22-package"><%= link_to h(version.name), :controller => 'versions', :action => 'show', :id => version %></h3>
10 11
    <%= render :partial => 'versions/overview', :locals => {:version => version} %>
11 12
    <%= render(:partial => "wiki/content", :locals => {:content => version.wiki_page.content}) if version.wiki_page %>
12 13

  
13
    <% issues = version.fixed_issues.find(:all,
14
                                          :include => [:status, :tracker],
15
                                          :conditions => ["tracker_id in (#{@selected_tracker_ids.join(',')})"],
16
                                          :order => "#{Tracker.table_name}.position, #{Issue.table_name}.id") unless @selected_tracker_ids.empty?
17
       issues ||= []
18
    %>
14
    <% 
15
	   issues = version.fixed_issues.delete_if {|i| !@selected_tracker_ids.include? i.tracker_id.to_s }
16
	%>
19 17
    <% if issues.size > 0 %>
20 18
    <fieldset class="related-issues"><legend><%= l(:label_related_issues) %></legend>
21 19
    <ul>
......
25 23
    </ul>
26 24
    </fieldset>
27 25
    <% end %>
26
	<% if version.children.count > 0 %>
27
	<div class="child-versions">
28
		<h3><%= l(:label_child_versions) %></h3>
29
		<% version.children.each do |v| %>
30
		<div class="child-version">
31
		<%= tag 'a', :name => v.name %>
32
	    <h3 class="icon22 icon22-package"><%= link_to h(v.name), :controller => 'versions', :action => 'show', :id => v %></h3>
33
	    <%= render :partial => 'versions/overview', :locals => {:version => v} %>
34
		<% 
35
		issues = v.fixed_issues.delete_if {|i| !@selected_tracker_ids.include? i.tracker_id.to_s }
36
		if issues.size > 0 %>
37
	    <fieldset class="related-issues"><legend><%= l(:label_related_issues) %></legend>
38
	    <ul>
39
	    <%- issues.each do |issue| -%>
40
	        <li><%= link_to_issue(issue) %>: <%=h issue.subject %></li>
41
	    <%- end -%>
42
	    </ul>
43
	    </fieldset>
44
	    <% end %>
45
		</div>
46
		<% end %>
47
		
48
	</div>
49
	<% end %>
50
	</div>
28 51
<% end %>
29 52
</div>
30 53
<% end %>
lang/en.yml (working copy)
184 184
field_default_value: Default value
185 185
field_comments_sorting: Display comments
186 186
field_parent_title: Parent page
187
field_parent_version: Parent version
187 188

  
188 189
setting_app_title: Application title
189 190
setting_app_subtitle: Application subtitle
......
429 430
label_wiki_edit_plural: Wiki edits
430 431
label_wiki_page: Wiki page
431 432
label_wiki_page_plural: Wiki pages
433
label_parent_version: Parent version
432 434
label_index_by_title: Index by title
433 435
label_index_by_date: Index by date
434 436
label_current_version: Current version
......
527 529
label_incoming_emails: Incoming emails
528 530
label_generate_key: Generate a key
529 531
label_issue_watchers: Watchers
532
label_child_versions: Child Versions
533
label_child_of: child of
530 534

  
531 535
button_login: Login
532 536
button_submit: Submit
db/migrate/099_add_version_dependency.rb (revision 0)
1
class AddVersionDependency < ActiveRecord::Migration
2
  def self.up
3
    add_column :versions, :parent_version_id, :integer
4
  end
5

  
6
  def self.down
7
    remove_column :versions, :parent_version_id
8
  end
9
end
public/stylesheets/application.css (working copy)
209 209
div#roadmap .wiki h1:first-child { display: none; }
210 210
div#roadmap .wiki h1 { font-size: 120%; }
211 211
div#roadmap .wiki h2 { font-size: 110%; }
212
div#roadmap .top-level-version { padding: 8px; margin-bottom: 10px; border: 4px solid #e0e0e0;}
213
div#roadmap .child-version { margin-left: 20px;}
212 214

  
213 215
div#version-summary { float:right; width:380px; margin-left: 16px; margin-bottom: 16px; background-color: #fff; }
214 216
div#version-summary fieldset { margin-bottom: 1em; }
    (1-1/1)