From 1269d537f6f0e49eaaf7fdb5658be79cff476a5c Mon Sep 17 00:00:00 2001 From: Vincent Date: Wed, 30 Oct 2024 16:57:42 +0100 Subject: [PATCH] Load previous and next issue links asynchronously --- app/overrides/issues/_action_menu_edit.rb | 48 ++--------------- .../_load_issue_show_asynchronously.html.erb | 54 +++++++++++++++++++ .../_previous_and_next_issue_ids.html.erb | 24 +++++++++ config/routes.rb | 7 +-- .../issues_controller_patch.rb | 19 ++++++- spec/controllers/issues_controller_spec.rb | 31 +++++++++++ spec/requests/issues_spec.rb | 26 +++++++++ 7 files changed, 161 insertions(+), 48 deletions(-) create mode 100644 app/views/issues/_load_issue_show_asynchronously.html.erb create mode 100644 app/views/issues/_previous_and_next_issue_ids.html.erb create mode 100644 spec/requests/issues_spec.rb diff --git a/app/overrides/issues/_action_menu_edit.rb b/app/overrides/issues/_action_menu_edit.rb index 03282d4..e6b910a 100644 --- a/app/overrides/issues/_action_menu_edit.rb +++ b/app/overrides/issues/_action_menu_edit.rb @@ -1,44 +1,4 @@ -Deface::Override.new :virtual_path => 'issues/_action_menu_edit', - :name => 'prevents-render-edit-partial-render-it-only-on-edit-button-click', - :replace => "erb[loud]:contains(\"render :partial => 'edit'\")", - :text => <<-RENDER_PARTIAL -<% unless Setting.plugin_redmine_tiny_features.key?('load_issue_edit_form_asynchronously') %> - <%= render :partial => 'edit' %> -<% else %> - <%# These header tags are not included if the partial is not preloaded %> - <% content_for :header_tags do %> - <%= javascript_include_tag 'attachments' %> - <% end %> - -<% end %> -RENDER_PARTIAL +Deface::Override.new :virtual_path => 'issues/_action_menu_edit', + :name => 'load-edit-partial-asynchronously', + :replace => "erb[loud]:contains(\"render :partial => 'edit'\")", + :partial => 'issues/load_issue_show_asynchronously' \ No newline at end of file diff --git a/app/views/issues/_load_issue_show_asynchronously.html.erb b/app/views/issues/_load_issue_show_asynchronously.html.erb new file mode 100644 index 0000000..a86de45 --- /dev/null +++ b/app/views/issues/_load_issue_show_asynchronously.html.erb @@ -0,0 +1,54 @@ +<% if Setting.plugin_redmine_tiny_features.key?('load_issue_edit_form_asynchronously') == false %> + <%= render :partial => 'edit' %> +<% else %> + <%# These header tags are not included if the partial is not preloaded %> + <% content_for :header_tags do %> + <%= javascript_include_tag 'attachments' %> + <% end %> + +<% end %> diff --git a/app/views/issues/_previous_and_next_issue_ids.html.erb b/app/views/issues/_previous_and_next_issue_ids.html.erb new file mode 100644 index 0000000..5e93a82 --- /dev/null +++ b/app/views/issues/_previous_and_next_issue_ids.html.erb @@ -0,0 +1,24 @@ +<%# Standard Redmine code copied from issues/show.html.erb %> +<%# Must be updated if standard code is updated %> + +<% if @prev_issue_id || @next_issue_id %> + +<% end %> diff --git a/config/routes.rb b/config/routes.rb index 09788f9..5c690de 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,8 +1,9 @@ resources :projects do put :custom_field_enumerations, :controller => 'project_custom_field_enumerations', action: 'update', as: 'update_custom_field_enumerations' end -match 'issues/render_form_by_ajax/:id', :controller => 'issues', :action => 'render_form_by_ajax', :via => :get, :as => 'render_form_by_ajax' -match 'queries/author_values_pagination', :controller => 'queries', :action => 'author_values_pagination' , :via => :get, :as => 'author_values_pagination' -match 'queries/assigned_to_values_pagination', :controller => 'queries', :action => 'assigned_to_values_pagination' , :via => :get, :as => 'assigned_to_values_pagination' +get 'issues/render_form_by_ajax/:id', :controller => 'issues', :action => 'render_form_by_ajax', :as => 'render_form_by_ajax' +get 'issues/load_previous_and_next_issue_ids/:id', to: 'issues#load_previous_and_next_issue_ids', as: :load_previous_and_next_issue_ids +get 'queries/author_values_pagination', :controller => 'queries', :action => 'author_values_pagination', :as => 'author_values_pagination' +get 'queries/assigned_to_values_pagination', :controller => 'queries', :action => 'assigned_to_values_pagination', :as => 'assigned_to_values_pagination' post 'issues/switch', to: 'issues#switch_display_mode', as: :switch_display_mode diff --git a/lib/redmine_tiny_features/issues_controller_patch.rb b/lib/redmine_tiny_features/issues_controller_patch.rb index 841f446..bc0e30b 100644 --- a/lib/redmine_tiny_features/issues_controller_patch.rb +++ b/lib/redmine_tiny_features/issues_controller_patch.rb @@ -2,12 +2,23 @@ module RedmineTinyFeatures::IssuesControllerPatch + def retrieve_previous_and_next_issue_ids(force_load = false) + # Disable if settings are set to Asynchronous loading + if Setting.plugin_redmine_tiny_features.key?('load_issue_edit_form_asynchronously').present? && !force_load + false + else + super() + end + end + end class IssuesController + prepend RedmineTinyFeatures::IssuesControllerPatch + append_before_action :find_optional_project_for_new_issue, :only => [:new] - skip_before_action :authorize, :only => [:render_form_by_ajax, :switch_display_mode] + skip_before_action :authorize, :only => [:render_form_by_ajax, :switch_display_mode, :load_previous_and_next_issue_ids] def render_form_by_ajax @issue = Issue.find(params[:id]) @@ -25,6 +36,12 @@ def switch_display_mode redirect_to params[:path] end + def load_previous_and_next_issue_ids + find_issue + retrieve_previous_and_next_issue_ids(true) + render json: { html: render_to_string(partial: 'issues/previous_and_next_issue_ids') } + end + private def find_optional_project_for_new_issue diff --git a/spec/controllers/issues_controller_spec.rb b/spec/controllers/issues_controller_spec.rb index e856226..83f16c7 100644 --- a/spec/controllers/issues_controller_spec.rb +++ b/spec/controllers/issues_controller_spec.rb @@ -166,4 +166,35 @@ end + describe '#retrieve_previous_and_next_issue_ids' do + + let(:issue) { Issue.first } + + context 'with asynchronous loading enabled' do + before do + Setting.send "plugin_redmine_tiny_features=", { + "warning_message_on_closed_issues" => "1", + "default_open_status" => "2", + "default_project" => "1", + "load_issue_edit_form_asynchronously" => "1", + } + end + + it 'allows patched method to receive an argument' do + controller.retrieve_previous_and_next_issue_ids(false) + end + + it 'allows patched method to receive true as an argument' do + controller.retrieve_previous_and_next_issue_ids(true) + end + + it 'renders previous and next issue ids as JSON response' do + get :load_previous_and_next_issue_ids, params: { id: issue.id } + expect(response).to have_http_status(:success) + expect(response.content_type).to include('application/json') + expect(JSON.parse(response.body)).to have_key('html') + end + end + end + end diff --git a/spec/requests/issues_spec.rb b/spec/requests/issues_spec.rb new file mode 100644 index 0000000..9079fb5 --- /dev/null +++ b/spec/requests/issues_spec.rb @@ -0,0 +1,26 @@ +require 'rails_helper' + +RSpec.describe 'Issues AJAX requests', type: :request do + + fixtures :issues + + let(:issue) { Issue.first } + + describe 'GET /issues/render_form_by_ajax/:id' do + it 'loads the edit form asynchronously' do + get render_form_by_ajax_path(issue.id) + expect(response).to have_http_status(:success) + expect(response.content_type).to include('application/json') + expect(JSON.parse(response.body)).to have_key('html') + end + end + + describe 'GET /issues/load_previous_and_next_issue_ids/:id' do + it 'loads previous and next issue ids asynchronously' do + get load_previous_and_next_issue_ids_path(issue.id) + expect(response).to have_http_status(:success) + expect(response.content_type).to include('application/json') + expect(JSON.parse(response.body)).to have_key('html') + end + end +end