From fa4c0f1f9148ca94022b38a26971afe7814692f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Codru=C8=9B=20Constantin=20Gu=C8=99oi?= Date: Wed, 15 Jun 2022 18:09:14 +0100 Subject: [PATCH 1/2] Add the posibility to set/change the position of an issue in a version https://www.redmine.org/issues/22802 --- app/controllers/enumerations_controller.rb | 2 +- app/controllers/issues_controller.rb | 2 ++ app/controllers/versions_controller.rb | 14 +++++++-- app/models/issue.rb | 8 ++++- app/models/issue_query.rb | 2 ++ app/views/settings/_issues.html.erb | 2 ++ app/views/versions/index.html.erb | 27 ++++++++++++----- app/views/versions/show.html.erb | 29 +++++++++++++------ config/locales/en.yml | 2 ++ config/locales/fr.yml | 2 ++ config/settings.yml | 2 ++ .../20200315154300_add_issue_position.rb | 9 ++++++ lib/redmine.rb | 1 + public/stylesheets/application.css | 1 + 14 files changed, 82 insertions(+), 21 deletions(-) create mode 100644 db/migrate/20200315154300_add_issue_position.rb diff --git a/app/controllers/enumerations_controller.rb b/app/controllers/enumerations_controller.rb index 405e34401..4d450c589 100644 --- a/app/controllers/enumerations_controller.rb +++ b/app/controllers/enumerations_controller.rb @@ -25,7 +25,7 @@ class EnumerationsController < ApplicationController before_action :require_admin_or_api_request, :only => :index before_action :build_new_enumeration, :only => [:new, :create] before_action :find_enumeration, :only => [:edit, :update, :destroy] - accept_api_auth :index + accept_api_auth :index, :update helper :custom_fields diff --git a/app/controllers/issues_controller.rb b/app/controllers/issues_controller.rb index f45d9bf06..96718f47a 100644 --- a/app/controllers/issues_controller.rb +++ b/app/controllers/issues_controller.rb @@ -209,11 +209,13 @@ class IssuesController < ApplicationController issue_path(@issue, previous_and_next_issue_ids_params) ) end + format.js { head 200 } format.api {render_api_ok} end else respond_to do |format| format.html {render :action => 'edit'} + format.js { head 422 } format.api {render_validation_errors(@issue)} end end diff --git a/app/controllers/versions_controller.rb b/app/controllers/versions_controller.rb index a4e84ae33..072c4ce6f 100644 --- a/app/controllers/versions_controller.rb +++ b/app/controllers/versions_controller.rb @@ -52,7 +52,8 @@ class VersionsController < ApplicationController includes(:project, :tracker). preload(:status, :priority, :fixed_version). where(:tracker_id => @selected_tracker_ids, :project_id => project_ids, :fixed_version_id => @versions.map(&:id)). - order("#{Project.table_name}.lft, #{Tracker.table_name}.position, #{Issue.table_name}.id") + #order("#{Project.table_name}.lft, #{Tracker.table_name}.position, #{Issue.table_name}.id") + order(order_issues_by) @issues_by_version = issues.group_by(&:fixed_version) end @versions.reject! {|version| !project_ids.include?(version.project_id) && @issues_by_version[version].blank?} @@ -69,7 +70,8 @@ class VersionsController < ApplicationController @issues = @version.fixed_issues.visible. includes(:status, :tracker, :priority). preload(:project). - reorder("#{Tracker.table_name}.position, #{Issue.table_name}.id"). + #reorder("#{Tracker.table_name}.position, #{Issue.table_name}.id"). + reorder(order_issues_by). to_a end format.api @@ -173,6 +175,14 @@ class VersionsController < ApplicationController end end + def order_issues_by + if Setting.manual_issue_position_in_versions == '1' + return "COALESCE(#{Issue.table_name}.position, 999999), #{Issue.table_name}.id" + else + return "#{Tracker.table_name}.position, #{Issue.table_name}.id" + end + end + private def retrieve_selected_tracker_ids(selectable_trackers, default_trackers=nil) diff --git a/app/models/issue.rb b/app/models/issue.rb index e5bb30e25..69af75172 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -54,6 +54,8 @@ class Issue < ActiveRecord::Base acts_as_activity_provider :scope => proc {preload(:project, :author, :tracker, :status)}, :author_key => :author_id + acts_as_positioned :scope => [:fixed_version_id] + DONE_RATIO_OPTIONS = %w(issue_field issue_status) attr_reader :transition_warning @@ -510,6 +512,10 @@ class Issue < ActiveRecord::Base (issue.new_record? || issue.attributes_editable?(user)) && user.allowed_to?(:manage_subtasks, issue.project) end) + safe_attributes( + 'position', + :if => lambda {|issue, user| user.allowed_to?(:change_issue_position_in_version, issue.project)} + ) safe_attributes( 'deleted_attachment_ids', :if => lambda {|issue, user| issue.attachments_deletable?(user)}) @@ -861,7 +867,7 @@ class Issue < ActiveRecord::Base # Returns the names of attributes that are journalized when updating the issue def journalized_attribute_names - names = Issue.column_names - %w(id root_id lft rgt lock_version created_on updated_on closed_on) + names = Issue.column_names - %w(id root_id lft rgt lock_version position created_on updated_on closed_on) if tracker names -= tracker.disabled_core_fields end diff --git a/app/models/issue_query.rb b/app/models/issue_query.rb index 5ff0e5530..766276720 100644 --- a/app/models/issue_query.rb +++ b/app/models/issue_query.rb @@ -49,6 +49,7 @@ class IssueQuery < Query QueryColumn.new(:due_date, :sortable => "#{Issue.table_name}.due_date", :groupable => true), QueryColumn.new(:estimated_hours, :sortable => "#{Issue.table_name}.estimated_hours", :totalable => true), + QueryColumn.new(:position, :sortable => "#{Issue.table_name}.position"), QueryColumn.new( :total_estimated_hours, :sortable => @@ -182,6 +183,7 @@ class IssueQuery < Query add_available_filter "start_date", :type => :date add_available_filter "due_date", :type => :date add_available_filter "estimated_hours", :type => :float + add_available_filter "position", :type => :integer if User.current.allowed_to?(:view_time_entries, project, :global => true) add_available_filter "spent_time", :type => :float, :label => :label_spent_time diff --git a/app/views/settings/_issues.html.erb b/app/views/settings/_issues.html.erb index b4e50d8e3..e363c18bc 100644 --- a/app/views/settings/_issues.html.erb +++ b/app/views/settings/_issues.html.erb @@ -15,6 +15,8 @@

<%= setting_check_box :display_subprojects_issues %>

+

<%= setting_check_box :manual_issue_position_in_versions %>

+

<%= setting_select :issue_done_ratio, Issue::DONE_RATIO_OPTIONS.collect {|i| [l("setting_issue_done_ratio_#{i}"), i]} %>

<%= setting_multiselect :non_working_week_days, (1..7).map {|d| [day_name(d), d.to_s]}, :inline => true %>

diff --git a/app/views/versions/index.html.erb b/app/views/versions/index.html.erb index 61fbe05ab..3069bce0b 100644 --- a/app/views/versions/index.html.erb +++ b/app/views/versions/index.html.erb @@ -32,14 +32,19 @@ <%= form_tag({}, :data => {:cm_url => issues_context_menu_path}) do -%> - <% issues.each do |issue| -%> - - - - - - - <% end -%> + + <% issues.each do |issue| -%> + + + + + + <% if Setting.manual_issue_position_in_versions == '1' && User.current.allowed_to?(:change_issue_position_in_version, version.project) %> + + <% end%> + + <% end -%> + <% end %> <% end %> @@ -108,3 +113,9 @@ <% html_title(l(:label_roadmap)) %> <%= context_menu %> + +<% if Setting.manual_issue_position_in_versions == '1' && User.current.allowed_to?(:change_issue_position_in_version, @project) %> + <%= javascript_tag do %> + $(function() { $("table.related-issues tbody").positionedItems(); }); + <% end %> +<% end %> diff --git a/app/views/versions/show.html.erb b/app/views/versions/show.html.erb index 0527eae9c..abd856aa3 100644 --- a/app/views/versions/show.html.erb +++ b/app/views/versions/show.html.erb @@ -41,15 +41,20 @@ <% if @issues.present? %> <%= form_tag({}, :data => {:cm_url => issues_context_menu_path}) do -%> - - <%- @issues.each do |issue| -%> - - - - - - - <% end %> + + + <%- @issues.each do |issue| -%> + + + + + + <% if Setting.manual_issue_position_in_versions == '1' && !@version.closed? && User.current.allowed_to?(:change_issue_position_in_version, @version.project) %> + + <% end%> + + <% end %> + <% end %> <%= context_menu %> @@ -59,3 +64,9 @@ <%= call_hook :view_versions_show_bottom, :version => @version %> <% html_title @version.name %> + +<% if Setting.manual_issue_position_in_versions == '1' && !@version.closed? && User.current.allowed_to?(:change_issue_position_in_version, @version.project) %> + <%= javascript_tag do %> + $(function() { $("table.related-issues tbody").positionedItems(); }); + <% end %> +<% end %> diff --git a/config/locales/en.yml b/config/locales/en.yml index 9d779a2fe..2a68b0827 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -506,6 +506,7 @@ en: setting_timelog_accept_future_dates: Accept time logs on future dates setting_show_status_changes_in_mail_subject: Show status changes in issue mail notifications subject setting_project_list_defaults: Projects list defaults + setting_manual_issue_position_in_versions: Enable manually set issue position in versions setting_twofa: Two-factor authentication permission_add_project: Create project @@ -579,6 +580,7 @@ en: permission_manage_related_issues: Manage related issues permission_import_issues: Import issues permission_log_time_for_other_users: Log spent time for other users + permission_change_issue_position_in_version: Change issue position in version project_module_issue_tracking: Issue tracking project_module_time_tracking: Time tracking diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 6df58ee71..96075e17c 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -481,6 +481,7 @@ fr: setting_time_entry_list_defaults: Affichage par défaut de la liste des temps passés setting_timelog_accept_0_hours: Autoriser la saisie de temps avec 0 heure setting_timelog_max_hours_per_day: Maximum d'heures pouvant être saisies par un utilisateur sur un jour + setting_manual_issue_position_in_versions: Activer le positionnement manuel des tickets dans les versions permission_add_project: Créer un projet permission_add_subprojects: Créer des sous-projets @@ -547,6 +548,7 @@ fr: permission_manage_subtasks: Gérer les sous-tâches permission_manage_related_issues: Gérer les demandes associées permission_import_issues: Importer des demandes + permission_change_issue_position_in_version: Changer la position d'un ticket dans une version project_module_issue_tracking: Suivi des demandes project_module_time_tracking: Suivi du temps passé diff --git a/config/settings.yml b/config/settings.yml index 9d7a3ad94..118c6dd20 100644 --- a/config/settings.yml +++ b/config/settings.yml @@ -187,6 +187,8 @@ parent_issue_done_ratio: default: 'derived' link_copied_issue: default: 'ask' +manual_issue_position_in_versions: + default: 1 close_duplicate_issues: default: 1 issue_group_assignment: diff --git a/db/migrate/20200315154300_add_issue_position.rb b/db/migrate/20200315154300_add_issue_position.rb new file mode 100644 index 000000000..ee0abec43 --- /dev/null +++ b/db/migrate/20200315154300_add_issue_position.rb @@ -0,0 +1,9 @@ +class AddIssuePosition < ActiveRecord::Migration[5.2] + def self.up + add_column :issues, :position, :integer + end + + def self.down + remove_column :issues, :position + end +end diff --git a/lib/redmine.rb b/lib/redmine.rb index 465e7dded..ad01cdb44 100644 --- a/lib/redmine.rb +++ b/lib/redmine.rb @@ -118,6 +118,7 @@ Redmine::AccessControl.map do |map| map.permission :view_private_notes, {}, :read => true, :require => :member map.permission :set_notes_private, {}, :require => :member map.permission :delete_issues, {:issues => :destroy}, :require => :member + map.permission :change_issue_position_in_version, {} # Watchers map.permission :view_issue_watchers, {}, :read => true map.permission :add_issue_watchers, {:watchers => [:new, :create, :append, :autocomplete_for_user]} diff --git a/public/stylesheets/application.css b/public/stylesheets/application.css index fca5f5647..4ae9fa37c 100644 --- a/public/stylesheets/application.css +++ b/public/stylesheets/application.css @@ -633,6 +633,7 @@ div#roadmap .related-issues { margin-bottom: 1em; } div#roadmap .related-issues td.checkbox { display: none; } div#roadmap .related-issues td.assigned_to { width:1px; white-space:nowrap; padding: 0; } div#roadmap .related-issues td.assigned_to img { padding-left: 4px; padding-right: 4px;} +div#roadmap .related-issues td.sortable { text-align: right; } div#roadmap .wiki h1:first-child { display: none; } div#roadmap .wiki h1 { font-size: 120%; } div#roadmap .wiki h2 { font-size: 110%; } -- 2.36.1