Index: app/controllers/issue_categories_controller.rb =================================================================== --- app/controllers/issue_categories_controller.rb (revision 20585) +++ app/controllers/issue_categories_controller.rb (working copy) @@ -29,7 +29,7 @@ def index respond_to do |format| format.html {redirect_to_settings_in_projects} - format.api {@categories = @project.issue_categories.to_a} + format.api {@categories = @project.issue_categories.sorted.to_a} end end @@ -85,6 +85,7 @@ flash[:notice] = l(:notice_successful_update) redirect_to_settings_in_projects end + format.js {head 200} format.api {render_api_ok} end else @@ -91,6 +92,7 @@ respond_to do |format| format.html {render :action => 'edit'} format.api {render_validation_errors(@category)} + format.js {head 422} end end end Index: app/models/issue_category.rb =================================================================== --- app/models/issue_category.rb (revision 20585) +++ app/models/issue_category.rb (working copy) @@ -22,13 +22,15 @@ belongs_to :project belongs_to :assigned_to, :class_name => 'Principal' has_many :issues, :foreign_key => 'category_id', :dependent => :nullify + acts_as_positioned validates_presence_of :name validates_uniqueness_of :name, :scope => [:project_id] validates_length_of :name, :maximum => 60 - safe_attributes 'name', 'assigned_to_id' + safe_attributes 'name', 'assigned_to_id', 'position' + scope :sorted, lambda {order(:position)} scope :named, lambda {|arg| where("LOWER(#{table_name}.name) = LOWER(?)", arg.to_s.strip)} alias :destroy_without_reassign :destroy @@ -43,7 +45,7 @@ end def <=>(category) - name <=> category.name + position <=> category.position end def to_s; name end Index: app/models/project.rb =================================================================== --- app/models/project.rb (revision 20585) +++ app/models/project.rb (working copy) @@ -46,7 +46,7 @@ has_many :queries, :dependent => :delete_all has_many :documents, :dependent => :destroy has_many :news, lambda {includes(:author)}, :dependent => :destroy - has_many :issue_categories, lambda {order(:name)}, :dependent => :delete_all + has_many :issue_categories, lambda {order(:position)}, :dependent => :delete_all has_many :boards, lambda {order(:position)}, :inverse_of => :project, :dependent => :destroy has_one :repository, lambda {where(:is_default => true)} has_many :repositories, :dependent => :destroy Index: app/views/projects/settings/_issue_categories.html.erb =================================================================== --- app/views/projects/settings/_issue_categories.html.erb (revision 20585) +++ app/views/projects/settings/_issue_categories.html.erb (working copy) @@ -1,7 +1,7 @@

<%= link_to l(:label_issue_category_new), new_project_issue_category_path(@project), :class => 'icon icon-add' if User.current.allowed_to?(:manage_categories, @project) %>

<% if @project.issue_categories.any? %> - +
@@ -15,6 +15,7 @@
<%= l(:label_issue_category) %> <%= l(:field_assigned_to) %><%= category.assigned_to.name if category.assigned_to %> <% if User.current.allowed_to?(:manage_categories, @project) %> + <%= reorder_handle category %> <%= link_to l(:button_edit), edit_issue_category_path(category), :class => 'icon icon-edit' %> <%= delete_link issue_category_path(category) %> <% end %> @@ -27,3 +28,7 @@ <% else %>

<%= l(:label_no_data) %>

<% end %> + +<%= javascript_tag do %> + $(function() { $("table.issue_categories tbody").positionedItems(); }); +<% end %> Index: config/routes.rb =================================================================== --- config/routes.rb (revision 20585) +++ config/routes.rb (working copy) @@ -127,7 +127,7 @@ end member do - get 'settings(/:tab)', :action => 'settings', :as => 'settings' + match 'settings(/:tab)', action: 'settings', as: 'settings', via: [:get, :put] post 'archive' post 'unarchive' post 'close' Index: db/migrate/20201209122301_add_issue_category_position.rb =================================================================== --- db/migrate/20201209122301_add_issue_category_position.rb (nonexistent) +++ db/migrate/20201209122301_add_issue_category_position.rb (working copy) @@ -0,0 +1,10 @@ +class AddIssueCategoryPosition < ActiveRecord::Migration[5.2] + def self.up + add_column :issue_categories, :position, :integer, default: 1 + IssueCategory.order(:name).each_with_index { |category, i| category.update_attribute(:position, i + 1) } + end + + def self.down + remove_column :issue_categories, :position + end +end Index: test/fixtures/issue_categories.yml =================================================================== --- test/fixtures/issue_categories.yml (revision 20585) +++ test/fixtures/issue_categories.yml (working copy) @@ -3,19 +3,23 @@ name: Printing project_id: 1 assigned_to_id: 2 + position: 1 id: 1 issue_categories_002: name: Recipes project_id: 1 - assigned_to_id: + assigned_to_id: + position: 2 id: 2 issue_categories_003: name: Stock management project_id: 2 - assigned_to_id: + assigned_to_id: + position: 3 id: 3 issue_categories_004: name: Printing project_id: 2 - assigned_to_id: + assigned_to_id: + position: 4 id: 4 Index: test/functional/issue_categories_controller_test.rb =================================================================== --- test/functional/issue_categories_controller_test.rb (revision 20585) +++ test/functional/issue_categories_controller_test.rb (working copy) @@ -137,13 +137,16 @@ :params => { :id => 2, :issue_category => { - :name => 'Testing' + :name => 'Testing', + :position => 3 } } ) end assert_redirected_to '/projects/ecookbook/settings/categories' - assert_equal 'Testing', IssueCategory.find(2).name + issue_category = IssueCategory.find(2) + assert_equal 'Testing', issue_category.name + assert_equal 3, issue_category.position end def test_update_failure Index: test/unit/issue_category_test.rb =================================================================== --- test/unit/issue_category_test.rb (revision 20585) +++ test/unit/issue_category_test.rb (working copy) @@ -31,6 +31,7 @@ assert IssueCategory.new(:project_id => 2, :name => 'New category').save category = IssueCategory.order('id DESC').first assert_equal 'New category', category.name + assert_equal 1, category.position end def test_create_with_group_assignment