diff options
author | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2010-03-13 14:56:49 +0000 |
---|---|---|
committer | Jean-Philippe Lang <jp_lang@yahoo.fr> | 2010-03-13 14:56:49 +0000 |
commit | 8e3d1b694ab47317638b474082cb70e08a8d02e7 (patch) | |
tree | 9997cc24910a029fea3e98ed0765566d9c4bb97e /lib | |
parent | e109c9b6b6f314dea19bf92dffa217d962eaa200 (diff) | |
download | redmine-8e3d1b694ab47317638b474082cb70e08a8d02e7.tar.gz redmine-8e3d1b694ab47317638b474082cb70e08a8d02e7.zip |
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
Diffstat (limited to 'lib')
-rw-r--r-- | lib/redmine.rb | 3 | ||||
-rw-r--r-- | lib/redmine/default_data/loader.rb | 1 | ||||
-rw-r--r-- | lib/redmine/helpers/gantt.rb | 53 |
3 files changed, 55 insertions, 2 deletions
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 |