diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index e7e455081a..a4349a16a5 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -374,28 +374,28 @@ function observeProjectIdentifier() { } function observeParentIssueField(url) { - new Ajax.Autocompleter('issue_parent_issue_id', + new Ajax.Autocompleter('issue_parent_id', 'parent_issue_candidates', url, { minChars: 1, frequency: 0.5, paramName: 'q', updateElement: function(value) { - document.getElementById('issue_parent_issue_id').value = value.id; + document.getElementById('issue_parent_id').value = value.id; }, parameters: 'scope=all' }); } function observeWorkPackageParentField(url) { - new Ajax.Autocompleter('work_package_parent_issue_id', + new Ajax.Autocompleter('work_package_parent_id', 'parent_issue_candidates', url, { minChars: 1, frequency: 0.5, paramName: 'q', updateElement: function(value) { - document.getElementById('work_package_parent_issue_id').value = value.id; + document.getElementById('work_package_parent_id').value = value.id; }, parameters: 'scope=all' }); diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index accf4d0427..ce26b5ee70 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -145,7 +145,7 @@ class IssuesController < ApplicationController call_hook(:controller_issues_new_after_save, { :params => params, :issue => @issue}) respond_to do |format| format.html { - redirect_to(params[:continue] ? { :action => 'new', :project_id => @project, :issue => {:type_id => @issue.type, :parent_issue_id => @issue.parent_issue_id}.reject {|k,v| v.nil?} } : + redirect_to(params[:continue] ? { :action => 'new', :project_id => @project, :issue => {:type_id => @issue.type, :parent_id => @issue.parent_id}.reject {|k,v| v.nil?} } : { :action => 'show', :id => @issue }) } end diff --git a/app/helpers/work_packages_helper.rb b/app/helpers/work_packages_helper.rb index 57155a8a79..ed38e4c2f0 100644 --- a/app/helpers/work_packages_helper.rb +++ b/app/helpers/work_packages_helper.rb @@ -269,7 +269,7 @@ module WorkPackagesHelper def work_package_form_parent_attribute(form, work_package, locals = {}) if User.current.allowed_to?(:manage_subtasks, locals[:project]) field = if work_package.is_a?(Issue) - form.text_field :parent_issue_id, :size => 10, :title => l(:description_autocomplete) + form.text_field :parent_id, :size => 10, :title => l(:description_autocomplete) else form.text_field :parent_id, :size => 10, :title => l(:description_autocomplete) end diff --git a/app/models/issue.rb b/app/models/issue.rb index 08d9cec480..0c2783e574 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -33,7 +33,6 @@ class Issue < WorkPackage validate :validate_fixed_version_is_assignable validate :validate_fixed_version_is_still_open validate :validate_enabled_type - validate :validate_correct_parent scope :open, :conditions => ["#{IssueStatus.table_name}.is_closed = ?", false], :include => :status @@ -66,30 +65,8 @@ class Issue < WorkPackage title << ')' end - # find all issues - # * having set a parent_id where the root_id - # 1) points to self - # 2) points to an issue with a parent - # 3) points to an issue having a different root_id - # * having not set a parent_id but a root_id - # This unfortunately does not find the issue with the id 3 in the following example - # | id | parent_id | root_id | - # | 1 | | 1 | - # | 2 | 1 | 2 | - # | 3 | 2 | 2 | - # This would only be possible using recursive statements - #scope :invalid_root_ids, { :conditions => "(issues.parent_id IS NOT NULL AND " + - # "(issues.root_id = issues.id OR " + - # "(issues.root_id = parent_issues.id AND parent_issues.parent_id IS NOT NULL) OR " + - # "(issues.root_id != parent_issues.root_id))" + - # ") OR " + - # "(issues.parent_id IS NULL AND issues.root_id != issues.id)", - # :joins => "LEFT OUTER JOIN issues parent_issues ON parent_issues.id = issues.parent_id" } - before_create :default_assign before_save :close_duplicates, :update_done_ratio_from_issue_status - after_save :reschedule_following_issues, :update_nested_set_attributes, :update_parent_attributes - after_destroy :update_parent_attributes before_destroy :remove_attachments after_initialize :set_default_values @@ -109,7 +86,7 @@ class Issue < WorkPackage # Moves/copies an issue to a new project and type # Returns the moved/copied issue on success, false on failure def move_to_project(*args) - ret = Issue.transaction do + Issue.transaction do move_to_project_without_transaction(*args) || raise(ActiveRecord::Rollback) end || false end @@ -132,7 +109,7 @@ class Issue < WorkPackage if !Setting.cross_project_issue_relations? && parent && parent.project_id != project_id - self.parent_issue_id = nil + self.parent_id = nil end end if new_type @@ -206,7 +183,7 @@ class Issue < WorkPackage safe_attributes 'type_id', 'status_id', - 'parent_issue_id', + 'parent_id', 'category_id', 'assigned_to_id', 'priority_id', @@ -251,15 +228,15 @@ class Issue < WorkPackage end end - if @parent_issue.present? + if parent.present? attrs.reject! {|k,v| %w(priority_id done_ratio start_date due_date estimated_hours).include?(k)} end - if attrs.has_key?('parent_issue_id') + if attrs.has_key?('parent_id') if !user.allowed_to?(:manage_subtasks, project) - attrs.delete('parent_issue_id') - elsif !attrs['parent_issue_id'].blank? - attrs.delete('parent_issue_id') unless Issue.visible(user).exists?(attrs['parent_issue_id'].to_i) + attrs.delete('parent_id') + elsif !attrs['parent_id'].blank? + attrs.delete('parent_id') unless WorkPackage.visible(user).exists?(attrs['parent_id'].to_i) end end @@ -322,24 +299,6 @@ class Issue < WorkPackage end end - def validate_correct_parent - # Checks parent issue assignment - if @parent_issue - if !Setting.cross_project_issue_relations? && @parent_issue.project_id != self.project_id - errors.add :parent_issue_id, :not_a_valid_parent - elsif !new_record? - # moving an existing issue - if @parent_issue.root_id != root_id - # we can always move to another tree - elsif move_possible?(@parent_issue) - # move accepted inside tree - else - errors.add :parent_issue_id, :not_a_valid_parent - end - end - end - end - # Set the done_ratio using the status if that setting is set. This will keep the done_ratios # even if the user turns off the setting later def update_done_ratio_from_issue_status @@ -379,12 +338,6 @@ class Issue < WorkPackage return done_date <= Date.today end - # Does this issue have children? - def children? - !leaf? - end - - # Returns an array of status that user is able to apply def new_statuses_allowed_to(user, include_default=false) return [] if status.nil? @@ -447,23 +400,6 @@ class Issue < WorkPackage end end - # The number of "items" this issue spans in it's nested set - # - # A parent issue would span all of it's children + 1 left + 1 right (3) - # - # | parent | - # || child || - # - # A child would span only itself (1) - # - # |child| - def nested_set_span - rgt - lft - end - - # TODO: remove. This is left here to avoid regression - # but the code was duplicated to work_packages_helper - # and thus should be removed as soon as possible. # Returns a string of css classes that apply to the issue def css_classes s = "issue status-#{status.position} priority-#{priority.position}" @@ -536,26 +472,6 @@ class Issue < WorkPackage Issue.update_versions(["#{Version.table_name}.project_id IN (?) OR #{Issue.table_name}.project_id IN (?)", moved_project_ids, moved_project_ids]) end - def parent_issue_id=(arg) - parent_issue_id = arg.blank? ? nil : arg.to_i - if parent_issue_id && @parent_issue = Issue.find_by_id(parent_issue_id) - journal_changes["parent_id"] = [self.parent_id, @parent_issue.id] - @parent_issue.id - else - @parent_issue = nil - journal_changes["parent_id"] = [self.parent_id, nil] - nil - end - end - - def parent_issue_id - if instance_variable_defined? :@parent_issue - @parent_issue.nil? ? nil : @parent_issue.id - else - parent_id - end - end - # Extracted from the ReportsController. def self.by_type(project) count_and_group_by(:project => project, @@ -623,110 +539,9 @@ class Issue < WorkPackage projects end - # method from acts_as_nested_set - def self.valid? - super && invalid_root_ids.empty? - end - - def self.all_invalid - (super + invalid_root_ids).uniq - end - - def self.rebuild_silently!(roots = nil) - - invalid_root_ids_to_fix = if roots.is_a? Array - roots - elsif roots.present? - [roots] - else - [] - end - - known_issue_parents = Hash.new do |hash, ancestor_id| - hash[ancestor_id] = Issue.find_by_id(ancestor_id) - end - - fix_known_invalid_root_ids = lambda do - issues = invalid_root_ids - - issues_roots = [] - - issues.each do |issue| - # At this point we can not trust nested set methods as the root_id is invalid. - # Therefore we trust the parent_issue_id to fetch all ancestors until we find the root - ancestor = issue - - while ancestor.parent_issue_id do - ancestor = known_issue_parents[ancestor.parent_issue_id] - end - - issues_roots << ancestor - - if invalid_root_ids_to_fix.empty? || invalid_root_ids_to_fix.map(&:id).include?(ancestor.id) - Issue.update_all({ :root_id => ancestor.id }, - { :id => issue.id }) - end - end - - fix_known_invalid_root_ids.call unless (issues_roots.map(&:id) & invalid_root_ids_to_fix.map(&:id)).empty? - end - - fix_known_invalid_root_ids.call - - super - end private - def update_nested_set_attributes - if root_id.nil? - # issue was just created - self.root_id = (@parent_issue.nil? ? id : @parent_issue.root_id) - set_default_left_and_right - Issue.update_all("root_id = #{root_id}, lft = #{lft}, rgt = #{rgt}", ["id = ?", id]) - if @parent_issue - move_to_child_of(@parent_issue) - end - reload - elsif parent_issue_id != parent_id - former_parent_id = parent_id - # moving an existing issue - if @parent_issue && @parent_issue.root_id == root_id - # inside the same tree - move_to_child_of(@parent_issue) - else - # to another tree - unless root? - move_to_right_of(root) - reload - end - old_root_id = root_id - self.root_id = (@parent_issue.nil? ? id : @parent_issue.root_id ) - target_maxright = nested_set_scope.maximum(right_column_name) || 0 - offset = target_maxright + 1 - lft - Issue.update_all("root_id = #{root_id}, lft = lft + #{offset}, rgt = rgt + #{offset}", - ["root_id = ? AND lft >= ? AND rgt <= ? ", old_root_id, lft, rgt]) - self[left_column_name] = lft + offset - self[right_column_name] = rgt + offset - if @parent_issue - move_to_child_of(@parent_issue) - end - end - reload - - # delete invalid relations of all descendants - self_and_descendants.each do |issue| - issue.relations.each do |relation| - relation.destroy unless relation.valid? - end - end - - # update former parent - recalculate_attributes_for(former_parent_id) if former_parent_id - end - remove_instance_variable(:@parent_issue) if instance_variable_defined?(:@parent_issue) - end - # this removes all attachments separately before destroying the issue # avoids getting a ActiveRecord::StaleObjectError when deleting an issue def remove_attachments @@ -735,9 +550,6 @@ class Issue < WorkPackage reload # important end - def update_parent_attributes - recalculate_attributes_for(parent_id) if parent_id - end # Update issues so their versions are not pointing to a # fixed_version that is not shared with the issue's project diff --git a/app/models/permitted_params.rb b/app/models/permitted_params.rb index 45a8247d64..a7dc23f3bb 100644 --- a/app/models/permitted_params.rb +++ b/app/models/permitted_params.rb @@ -147,7 +147,7 @@ class PermittedParams < Struct.new(:params, :user) :due_date, :planning_element_type_id, :parent_id, - :parent_issue_id, + :parent_id, :assigned_to_id, :responsible_id, :type_id, diff --git a/app/models/planning_element.rb b/app/models/planning_element.rb index 27e959f61d..b904151035 100644 --- a/app/models/planning_element.rb +++ b/app/models/planning_element.rb @@ -61,9 +61,6 @@ class PlanningElement < WorkPackage } - scope :visible, lambda {|*args| { :include => :project, - :conditions => PlanningElement.visible_condition(args.first || User.current) } } - scope :at_time, lambda { |time| {:select => SQL_FOR_AT[:select], :conditions => ["(#{PlanningElement.quoted_table_name}.deleted_at IS NULL @@ -119,9 +116,6 @@ class PlanningElement < WorkPackage before_save :append_scenario_dates_to_journal - after_save :update_parent_attributes - after_save :create_alternate_date - validates_presence_of :subject, :project validates_length_of :subject, :maximum => 255, :unless => lambda { |e| e.subject.blank? } @@ -134,10 +128,6 @@ class PlanningElement < WorkPackage end end - def is_milestone? - planning_element_type && planning_element_type.is_milestone? - end - validate do if self.due_date and self.start_date and self.due_date < self.start_date errors.add :due_date, :greater_than_start_date @@ -159,10 +149,6 @@ class PlanningElement < WorkPackage end - def leaf? - self.children.count == 0 - end - def all_scenarios project.scenarios.sort_by(&:id).map do |scenario| alternate_date = alternate_dates.to_a.find { |a| a.scenario_id.to_s == scenario.id.to_s } @@ -216,75 +202,4 @@ class PlanningElement < WorkPackage end end end - - def note - @journal_notes - end - - def note=(text) - @journal_notes = text - end - - def trash - unless new_record? or self.deleted_at - self.children.each{|child| child.trash} - - self.reload - self.deleted_at = Time.now - self.save! - end - freeze - end - - def restore! - unless parent && parent.deleted? - self.deleted_at = nil - self.save - else - raise "You cannot restore an element whose parent is deleted. Restore the parent first!" - end - end - - def deleted? - !!read_attribute(:deleted_at) - end - - # Aliasing the parent_issue_id methods here in order - # to improve compatibility between - # planning elments and issues - alias_method :parent_issue_id, :parent_id - - # I am not sure why it is not possible to - # alias_method :parent_issue_id=, :parent_id= - def parent_issue_id=(arg) - parent_id = arg - end - - protected - - def update_parent_attributes - if parent.present? - parent.reload - - unless parent.children.without_deleted.empty? - children = parent.children.without_deleted - - parent.start_date = [children.minimum(:start_date), children.minimum(:due_date)].reject(&:nil?).min - parent.due_date = [children.maximum(:start_date), children.maximum(:due_date)].reject(&:nil?).max - - if parent.changes.present? - parent.note = I18n.t('timelines.planning_element_updated_automatically_by_child_changes', :child => "*#{id}") - - # Ancestors will be updated by parent's after_save hook. - parent.save(:validate => false) - end - end - end - end - - def create_alternate_date - if start_date_changed? or due_date_changed? - alternate_dates.create(:start_date => start_date, :due_date => due_date) - end - end end diff --git a/app/models/project.rb b/app/models/project.rb index 11ec70fdcf..0c57d6d34f 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -976,7 +976,7 @@ class Project < ActiveRecord::Base # Parent issue if issue.parent_id if copied_parent = work_packages_map[issue.parent_id] - new_issue.parent_issue_id = copied_parent.id + new_issue.parent_id = copied_parent.id end end diff --git a/app/models/setting.rb b/app/models/setting.rb index eb6c41b48d..4c4d3f3a53 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -129,7 +129,7 @@ class Setting < ActiveRecord::Base def self.[]=(name, v) setting = find_or_default(name) setting.value = (v ? v : "") - Rails.cache.delete_matched(Regexp.compile(base_cache_key(name, '.+'))) + Rails.cache.delete(cache_key(name)) setting.save setting.value end diff --git a/app/models/work_package.rb b/app/models/work_package.rb index 6fe457145e..f6e1730a88 100644 --- a/app/models/work_package.rb +++ b/app/models/work_package.rb @@ -53,7 +53,17 @@ class WorkPackage < ActiveRecord::Base acts_as_watchable - acts_as_nested_set :scope => 'root_id', :dependent => :destroy + before_save :store_former_parent_id + include OpenProject::NestedSet::WithRootIdScope + after_save :reschedule_following_issues, + :update_parent_attributes, + :create_alternate_date + + after_move :remove_invalid_relations, + :recalculate_attributes_for_former_parent + + after_destroy :update_parent_attributes + acts_as_customizable acts_as_searchable :columns => ['subject', "#{table_name}.description", "#{Journal.table_name}.notes"], @@ -111,6 +121,17 @@ class WorkPackage < ActiveRecord::Base :responsible_id register_on_journal_formatter :scenario_date, /^scenario_(\d+)_(start|due)_date$/ + # acts_as_journalized will create an initial journal on wp creation + # and touch the journaled object: + # journal.rb:47 + # + # This will result in optimistic locking increasing the lock_version attribute to 1. + # In order to avoid stale object errors we reload the attributes in question + # after the wp is created. + # As after_create is run before after_save, and journal creation is triggered by an + # after_save hook, we rely on after_save and a specific version, here. + after_save :reload_lock_and_timestamps, :if => Proc.new { |wp| wp.lock_version == 0 } + # Returns a SQL conditions string used to find all work units visible by the specified user def self.visible_condition(user, options={}) Project.allowed_to_condition(user, :view_work_packages, options) @@ -153,7 +174,7 @@ class WorkPackage < ActiveRecord::Base # attributes don't come from form, so it's save to force assign self.force_attributes = work_package.attributes.dup.except(*merged_options[:exclude]) - self.parent_issue_id = work_package.parent_id if work_package.parent_id + self.parent_id = work_package.parent_id if work_package.parent_id self.custom_field_values = work_package.custom_field_values.inject({}) {|h,v| h[v.custom_field_id] = v.value; h} self.status = work_package.status self @@ -243,6 +264,30 @@ class WorkPackage < ActiveRecord::Base end end + def trash + unless new_record? or self.deleted_at + self.children.each{|child| child.trash} + + self.reload + self.deleted_at = Time.now + self.save! + end + freeze + end + + def restore! + unless parent && parent.deleted? + self.deleted_at = nil + self.save + else + raise "You cannot restore an element whose parent is deleted. Restore the parent first!" + end + end + + def deleted? + !!read_attribute(:deleted_at) + end + # Users the work_package can be assigned to delegate :assignable_users, :to => :project @@ -290,47 +335,8 @@ class WorkPackage < ActiveRecord::Base end end - def recalculate_attributes_for(work_package_id) - if work_package_id.is_a? WorkPackage - p = work_package_id - else - p = WorkPackage.find_by_id(work_package_id) - end - - if p - # priority = highest priority of children - if priority_position = p.children.joins(:priority).maximum("#{IssuePriority.table_name}.position") - p.priority = IssuePriority.find_by_position(priority_position) - end - - # start/due dates = lowest/highest dates of children - p.start_date = p.children.minimum(:start_date) - p.due_date = p.children.maximum(:due_date) - if p.start_date && p.due_date && p.due_date < p.start_date - p.start_date, p.due_date = p.due_date, p.start_date - end - - # done ratio = weighted average ratio of leaves - unless WorkPackage.use_status_for_done_ratio? && p.status && p.status.default_done_ratio - leaves_count = p.leaves.count - if leaves_count > 0 - average = p.leaves.average(:estimated_hours).to_f - if average == 0 - average = 1 - end - done = p.leaves.joins(:status).sum("COALESCE(estimated_hours, #{average}) * (CASE WHEN is_closed = #{connection.quoted_true} THEN 100 ELSE COALESCE(done_ratio, 0) END)").to_f - progress = done / (average * leaves_count) - p.done_ratio = progress.round - end - end - - # estimate = sum of leaves estimates - p.estimated_hours = p.leaves.sum(:estimated_hours).to_f - p.estimated_hours = nil if p.estimated_hours == 0.0 - - # ancestors will be recursively updated - p.save(:validate => false) if p.changed? - end + def is_milestone? + planning_element_type && planning_element_type.is_milestone? end # This is a dummy implementation that is currently overwritten @@ -354,6 +360,99 @@ class WorkPackage < ActiveRecord::Base .sum("#{TimeEntry.table_name}.hours").to_f || 0.0 end + protected + + def recalculate_attributes_for(work_package_id) + p = if work_package_id.is_a? WorkPackage + work_package_id + else + WorkPackage.find_by_id(work_package_id) + end + + return unless p + + p.inherit_priority_from_children + + p.inherit_dates_from_children + + p.inherit_done_ratio_from_leaves + + p.inherit_estimated_hours_from_leaves + + # ancestors will be recursively updated + if p.changed? + p.journal_notes = I18n.t('timelines.planning_element_updated_automatically_by_child_changes', :child => "*#{id}") + + # Ancestors will be updated by parent's after_save hook. + p.save(:validate => false) + end + end + + def update_parent_attributes + recalculate_attributes_for(parent_id) if parent_id.present? + end + + def inherit_priority_from_children + # priority = highest priority of children + if priority_position = children.joins(:priority).maximum("#{IssuePriority.table_name}.position") + self.priority = IssuePriority.find_by_position(priority_position) + end + end + + def inherit_dates_from_children + active_children = children.without_deleted + + unless active_children.empty? + self.start_date = [active_children.minimum(:start_date), active_children.minimum(:due_date)].compact.min + self.due_date = [active_children.maximum(:start_date), active_children.maximum(:due_date)].compact.max + end + end + + def inherit_done_ratio_from_leaves + # done ratio = weighted average ratio of leaves + unless WorkPackage.use_status_for_done_ratio? && status && status.default_done_ratio + leaves_count = leaves.count + if leaves_count > 0 + average = leaves.average(:estimated_hours).to_f + if average == 0 + average = 1 + end + done = leaves.joins(:status).sum("COALESCE(estimated_hours, #{average}) * (CASE WHEN is_closed = #{connection.quoted_true} THEN 100 ELSE COALESCE(done_ratio, 0) END)").to_f + progress = done / (average * leaves_count) + + self.done_ratio = progress.round + end + end + end + + def inherit_estimated_hours_from_leaves + # estimate = sum of leaves estimates + self.estimated_hours = leaves.sum(:estimated_hours).to_f + self.estimated_hours = nil if estimated_hours == 0.0 + end + + def store_former_parent_id + @former_parent_id = parent_id_changed? ? parent_id_was : false + true # force callback to return true + end + + def remove_invalid_relations + # delete invalid relations of all descendants + self_and_descendants.each do |issue| + issue.relations.each do |relation| + relation.destroy unless relation.valid? + end + end + end + + def recalculate_attributes_for_former_parent + recalculate_attributes_for(@former_parent_id) if @former_parent_id + end + + def reload_lock_and_timestamps + reload(:select => [:lock_version, :created_at, :updated_at]) + end + private def add_time_entry_for(user, attributes) @@ -364,4 +463,16 @@ class WorkPackage < ActiveRecord::Base time_entries.build(attributes) end + + def create_alternate_date + # This is a hack. + # It is required as long as alternate dates exist/are not moved up to work_packages. + # Its purpose is to allow for setting the after_save filter in the correct order + # before acts as journalized and the cleanup method reload_lock_and_timestamps. + return true unless respond_to?(:alternate_dates) + + if start_date_changed? or due_date_changed? + alternate_dates.create(:start_date => start_date, :due_date => due_date) + end + end end diff --git a/app/views/issues/_form.html.erb b/app/views/issues/_form.html.erb index ea3503031c..445ef11e64 100644 --- a/app/views/issues/_form.html.erb +++ b/app/views/issues/_form.html.erb @@ -22,7 +22,7 @@ See doc/COPYRIGHT.rdoc for more details.

<%= f.text_field :subject, :size => 80, :required => true %>

<% if User.current.allowed_to?(:manage_subtasks, @project) %> -

<%= f.text_field :parent_issue_id, :size => 10, :title => l(:description_autocomplete) %>

+

<%= f.text_field :parent_id, :size => 10, :title => l(:description_autocomplete) %>

<%= javascript_tag "observeParentIssueField('#{issues_auto_complete_path(:id => @issue, :project_id => @project, :escape => false) }')" %> <% end %> diff --git a/app/views/issues/_list.html.erb b/app/views/issues/_list.html.erb index 826500a6c2..7b363609cc 100644 --- a/app/views/issues/_list.html.erb +++ b/app/views/issues/_list.html.erb @@ -45,7 +45,7 @@ See doc/COPYRIGHT.rdoc for more details. <%= check_box_tag("ids[]", issue.id, false, :id => "issue#{issue.id}") %> - <% if parent_issue = issue.parent_issue_id %> + <% if parent_issue = issue.parent_id %> <%=l(:description_subissue) + ' ' + l(:label_issue) + ' #' + parent_issue.to_s %> <% end -%> <%= link_to issue.id, :controller => '/issues', :action => 'show', :id => issue %> diff --git a/app/views/issues/_subissues_paragraph.html.erb b/app/views/issues/_subissues_paragraph.html.erb index de5e59d145..b714a11317 100644 --- a/app/views/issues/_subissues_paragraph.html.erb +++ b/app/views/issues/_subissues_paragraph.html.erb @@ -11,7 +11,7 @@ See doc/COPYRIGHT.rdoc for more details. ++#%> <%= l(:label_issue_hierarchy) %> -(<%= link_to(l(:label_add_subtask), {:controller => '/issues', :action => 'new', :project_id => @project, :issue => {:parent_issue_id => @issue}}) if User.current.allowed_to?(:manage_subtasks, @project) %>) +(<%= link_to(l(:label_add_subtask), {:controller => '/issues', :action => 'new', :project_id => @project, :issue => {:parent_id => @issue}}) if User.current.allowed_to?(:manage_subtasks, @project) %>) <% if !@issue.leaf? || @issue.parent %> <% indent = 0 %> diff --git a/app/views/issues/bulk_edit.html.erb b/app/views/issues/bulk_edit.html.erb index cdf1ce767e..dc223d8e65 100644 --- a/app/views/issues/bulk_edit.html.erb +++ b/app/views/issues/bulk_edit.html.erb @@ -72,8 +72,8 @@ See doc/COPYRIGHT.rdoc for more details.
<% if @project && User.current.allowed_to?(:manage_subtasks, @project) %>

- - <%= text_field_tag 'issue[parent_issue_id]', '', :size => 10 %> + + <%= text_field_tag 'issue[parent_id]', '', :size => 10 %>

<%= javascript_tag "observeParentIssueField('#{issues_auto_complete_path }')" %> diff --git a/app/views/planning_elements/_form.html.erb b/app/views/planning_elements/_form.html.erb index abdb187277..2dfcf1fb50 100644 --- a/app/views/planning_elements/_form.html.erb +++ b/app/views/planning_elements/_form.html.erb @@ -146,11 +146,11 @@ See doc/COPYRIGHT.rdoc for more details. <% unless planning_element.new_record? %>

<%= l(:field_notes) %>

-