From 8e3d1b694ab47317638b474082cb70e08a8d02e7 Mon Sep 17 00:00:00 2001 From: Jean-Philippe Lang Date: Sat, 13 Mar 2010 14:56:49 +0000 Subject: Adds subtasking (#443) including: * priority, start/due dates, progress, estimate, spent time roll-up to parent issues * descendant issues tree displayed on the issue view with context menu support * issue tree display on the gantt chart * issue tree copy on project copy * unlimited nesting Defining subtasks requires the new permission 'Manage subtasks'. Subtasks can not belong to a different project than the parent task. Implementation is based on scoped nested sets for fast reads and updates. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@3573 e93f8b46-1217-0410-a6f0-8f06a7374b81 --- lib/redmine.rb | 3 ++- lib/redmine/default_data/loader.rb | 1 + lib/redmine/helpers/gantt.rb | 53 +++++++++++++++++++++++++++++++++++++- 3 files changed, 55 insertions(+), 2 deletions(-) (limited to 'lib') diff --git a/lib/redmine.rb b/lib/redmine.rb index 1205f6fa4..df57b08dc 100644 --- a/lib/redmine.rb +++ b/lib/redmine.rb @@ -47,13 +47,14 @@ Redmine::AccessControl.map do |map| map.permission :manage_categories, {:projects => :settings, :issue_categories => [:new, :edit, :destroy]}, :require => :member # Issues map.permission :view_issues, {:projects => :roadmap, - :issues => [:index, :changes, :show, :context_menu], + :issues => [:index, :changes, :show, :context_menu, :auto_complete], :versions => [:show, :status_by], :queries => :index, :reports => [:issue_report, :issue_report_details]} map.permission :add_issues, {:issues => [:new, :update_form]} map.permission :edit_issues, {:issues => [:edit, :update, :reply, :bulk_edit, :update_form]} map.permission :manage_issue_relations, {:issue_relations => [:new, :destroy]} + map.permission :manage_subtasks, {} map.permission :add_issue_notes, {:issues => [:edit, :update, :reply]} map.permission :edit_issue_notes, {:journals => :edit}, :require => :loggedin map.permission :edit_own_issue_notes, {:journals => :edit}, :require => :loggedin diff --git a/lib/redmine/default_data/loader.rb b/lib/redmine/default_data/loader.rb index 7baeb976c..5eed3d9b0 100644 --- a/lib/redmine/default_data/loader.rb +++ b/lib/redmine/default_data/loader.rb @@ -53,6 +53,7 @@ module Redmine :add_issues, :edit_issues, :manage_issue_relations, + :manage_subtasks, :add_issue_notes, :save_queries, :view_gantt, diff --git a/lib/redmine/helpers/gantt.rb b/lib/redmine/helpers/gantt.rb index e24be1cae..330b58ee7 100644 --- a/lib/redmine/helpers/gantt.rb +++ b/lib/redmine/helpers/gantt.rb @@ -52,8 +52,29 @@ module Redmine @date_to = (@date_from >> @months) - 1 end + def events=(e) - @events = e.sort {|x,y| x.start_date <=> y.start_date } + @events = e + # Adds all ancestors + root_ids = e.select {|i| i.is_a?(Issue) && i.parent_id? }.collect(&:root_id).uniq + if root_ids.any? + # Retrieves all nodes + parents = Issue.find_all_by_root_id(root_ids, :conditions => ["rgt - lft > 1"]) + # Only add ancestors + @events += parents.select {|p| @events.detect {|i| i.is_a?(Issue) && p.is_ancestor_of?(i)}} + end + @events.uniq! + # Sort issues by hierarchy and start dates + @events.sort! {|x,y| + if x.is_a?(Issue) && y.is_a?(Issue) + gantt_issue_compare(x, y, @events) + else + gantt_start_compare(x, y) + end + } + # Removes issues that have no start or end date + @events.reject! {|i| i.is_a?(Issue) && (i.start_date.nil? || i.due_before.nil?) } + @events end def params @@ -218,6 +239,36 @@ module Redmine imgl.format = format imgl.to_blob end if Object.const_defined?(:Magick) + + private + + def gantt_issue_compare(x, y, issues) + if x.parent_id == y.parent_id + gantt_start_compare(x, y) + elsif x.is_ancestor_of?(y) + -1 + elsif y.is_ancestor_of?(x) + 1 + else + ax = issues.select {|i| i.is_a?(Issue) && i.is_ancestor_of?(x) && !i.is_ancestor_of?(y) }.sort_by(&:lft).first + ay = issues.select {|i| i.is_a?(Issue) && i.is_ancestor_of?(y) && !i.is_ancestor_of?(x) }.sort_by(&:lft).first + if ax.nil? && ay.nil? + gantt_start_compare(x, y) + else + gantt_issue_compare(ax || x, ay || y, issues) + end + end + end + + def gantt_start_compare(x, y) + if x.start_date.nil? + -1 + elsif y.start_date.nil? + 1 + else + x.start_date <=> y.start_date + end + end end end end -- cgit v1.2.3