Project

General

Profile

Feature #22802 » 0002-Fixes-on-top-of-issue-ordering.patch

Codruț Gușoi, 2022-06-27 18:27

View differences:

app/controllers/versions_controller.rb
177 177

  
178 178
  def order_issues_by
179 179
    if Setting.manual_issue_position_in_versions == '1'
180
      return "COALESCE(#{Issue.table_name}.position, 999999), #{Issue.table_name}.id"
180
      return "COALESCE(#{Issue.table_name}.fixed_version_position, 999999), #{Issue.table_name}.id"
181 181
    else
182 182
      return "#{Tracker.table_name}.position, #{Issue.table_name}.id"
183 183
    end
app/models/issue.rb
54 54
  acts_as_activity_provider :scope => proc {preload(:project, :author, :tracker, :status)},
55 55
                            :author_key => :author_id
56 56

  
57
  acts_as_positioned :scope => [:fixed_version_id]
57
  acts_as_positioned :scope => [:fixed_version_id], :column => :fixed_version_position
58 58

  
59 59
  DONE_RATIO_OPTIONS = %w(issue_field issue_status)
60 60

  
......
513 513
        user.allowed_to?(:manage_subtasks, issue.project)
514 514
    end)
515 515
  safe_attributes(
516
    'position',
516
    'fixed_version_position',
517 517
    :if => lambda {|issue, user| user.allowed_to?(:change_issue_position_in_version, issue.project)}
518 518
  )
519 519
  safe_attributes(
......
867 867

  
868 868
  # Returns the names of attributes that are journalized when updating the issue
869 869
  def journalized_attribute_names
870
    names = Issue.column_names - %w(id root_id lft rgt lock_version position created_on updated_on closed_on)
870
    names = Issue.column_names - %w(id root_id lft rgt lock_version fixed_version_position created_on updated_on closed_on)
871 871
    if tracker
872 872
      names -= tracker.disabled_core_fields
873 873
    end
app/models/issue_query.rb
49 49
    QueryColumn.new(:due_date, :sortable => "#{Issue.table_name}.due_date", :groupable => true),
50 50
    QueryColumn.new(:estimated_hours, :sortable => "#{Issue.table_name}.estimated_hours",
51 51
                    :totalable => true),
52
    QueryColumn.new(:position, :sortable => "#{Issue.table_name}.position"),
52
    QueryColumn.new(:fixed_version_position, :sortable => "#{Issue.table_name}.fixed_version_position"),
53 53
    QueryColumn.new(
54 54
      :total_estimated_hours,
55 55
      :sortable =>
......
183 183
    add_available_filter "start_date", :type => :date
184 184
    add_available_filter "due_date", :type => :date
185 185
    add_available_filter "estimated_hours", :type => :float
186
    add_available_filter "position", :type => :integer
186
    add_available_filter "fixed_version_position", :type => :integer
187 187

  
188 188
    if User.current.allowed_to?(:view_time_entries, project, :global => true)
189 189
      add_available_filter "spent_time", :type => :float, :label => :label_spent_time
db/migrate/20200315154300_add_issue_position.rb
1 1
class AddIssuePosition < ActiveRecord::Migration[5.2]
2 2
  def self.up
3
    add_column :issues, :position, :integer
3
    add_column :issues, :fixed_version_position, :integer
4 4
  end
5 5

  
6 6
  def self.down
7
    remove_column :issues, :position
7
    remove_column :issues, :fixed_version_position
8 8
  end
9 9
end
lib/redmine/acts/positioned.rb
34 34
        # or an array of symbols
35 35
        def acts_as_positioned(options = {})
36 36
          class_attribute :positioned_options
37
          self.positioned_options = {:scope => Array(options[:scope])}
37
          self.positioned_options = {:scope => Array(options[:scope]), :column => options[:colunm] || :position }
38 38

  
39 39
          send :include, Redmine::Acts::Positioned::InstanceMethods
40 40

  
......
70 70
        end
71 71

  
72 72
        def set_default_position
73
          if position.nil?
74
            self.position = position_scope.maximum(:position).to_i + (new_record? ? 1 : 0)
73
          column = self.positioned_options[:column]
74

  
75
          if send(column).nil?
76
            self.send(column + '=', position_scope.maximum(column).to_i + (new_record? ? 1 : 0))
75 77
          end
76 78
        end
77 79

  
......
89 91
        end
90 92

  
91 93
        def insert_position
92
          position_scope.where("position >= ? AND id <> ?", position, id).update_all("position = position + 1")
94
          column = self.positioned_options[:column]
95

  
96
          position_scope.where("#{column} >= ? AND id <> ?", position, id).update_all("#{column} = #{column} + 1")
93 97
        end
94 98

  
95 99
        def remove_position
96 100
          # this can be called in after_update or after_destroy callbacks
97 101
          # with different methods in Rails 5 for retrieving the previous value
102
          column = self.positioned_options[:column]
103

  
98 104
          previous = destroyed? ? position_was : position_before_last_save
99
          position_scope_was.where("position >= ? AND id <> ?", previous, id).update_all("position = position - 1")
105
          position_scope_was.where("#{column} >= ? AND id <> ?", previous, id).update_all("#{column} = #{column} - 1")
100 106
        end
101 107

  
102 108
        def position_scope_changed?
......
104 110
        end
105 111

  
106 112
        def shift_positions
113
          column = self.positioned_options[:column]
114

  
107 115
          offset = position_before_last_save <=> position
108 116
          min, max = [position, position_before_last_save].sort
109
          r = position_scope.where("id <> ? AND position BETWEEN ? AND ?", id, min, max).update_all("position = position + #{offset}")
117
          r = position_scope.where("id <> ? AND #{column} BETWEEN ? AND ?", id, min, max).update_all("#{column} = #{column} + #{offset}")
110 118
          if r != max - min
111 119
            reset_positions_in_list
112 120
          end
113 121
        end
114 122

  
115 123
        def reset_positions_in_list
116
          position_scope.reorder(:position, :id).pluck(:id).each_with_index do |record_id, p|
117
            self.class.where(:id => record_id).update_all(:position => p+1)
124
          column = self.positioned_options[:column]
125

  
126
          position_scope.reorder(column, :id).pluck(:id).each_with_index do |record_id, p|
127
            self.class.where(:id => record_id).update_all(column => p+1)
118 128
          end
119 129
        end
120 130
      end
(8-8/9)