summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorJean-Philippe Lang <jp_lang@yahoo.fr>2010-03-13 14:56:49 +0000
committerJean-Philippe Lang <jp_lang@yahoo.fr>2010-03-13 14:56:49 +0000
commit8e3d1b694ab47317638b474082cb70e08a8d02e7 (patch)
tree9997cc24910a029fea3e98ed0765566d9c4bb97e /lib
parente109c9b6b6f314dea19bf92dffa217d962eaa200 (diff)
downloadredmine-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.rb3
-rw-r--r--lib/redmine/default_data/loader.rb1
-rw-r--r--lib/redmine/helpers/gantt.rb53
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