Skip to content

Commit

Permalink
Load previous and next issue links asynchronously
Browse files Browse the repository at this point in the history
  • Loading branch information
nanego committed Oct 30, 2024
1 parent cf9ff4a commit 1269d53
Show file tree
Hide file tree
Showing 7 changed files with 161 additions and 48 deletions.
48 changes: 4 additions & 44 deletions app/overrides/issues/_action_menu_edit.rb
Original file line number Diff line number Diff line change
@@ -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 %>
<script>
function loadIssueEditForm(id){
if ($('#issue-form').length < 1) {
$.ajax({
url: "<%= render_form_by_ajax_path(@issue.id) %>",
beforeSend: function(){
$('#ajax-indicator').addClass('bottom');
},
success: function(response) {
$('#ajax-indicator').removeClass('bottom');
if(response){
$('#update').append(response.html);
$(document).ready(function() {
// for datepicker element,
<% include_calendar_headers_tags %>
// for wikitoolbar element in mode Textile,
setupFileDrop();
// But for mode visual there is no need to call because it is already called in { $(document).ajaxSuccess/redmine_wysiwyg_editor }
});
}
},error: function(response) {
$('#ajax-indicator').removeClass('bottom');
console.error(response);
},
});
}
}
$(document).ready(function() {
loadIssueEditForm();
});
</script>
<% 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'
54 changes: 54 additions & 0 deletions app/views/issues/_load_issue_show_asynchronously.html.erb
Original file line number Diff line number Diff line change
@@ -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 %>
<script>
function loadIssueEditForm() {
if ($('#issue-form').length < 1) {
$.ajax({
url: "<%= render_form_by_ajax_path(@issue.id) %>",
beforeSend: function () {
$('#ajax-indicator').addClass('bottom');
},
success: function (response) {
$('#ajax-indicator').removeClass('bottom');
if (response) {
$('#update').append(response.html);
$(document).ready(function () {
// for datepicker element,
<% include_calendar_headers_tags %>
// for wikitoolbar element in mode Textile,
setupFileDrop();
// But for mode visual there is no need to call because it is already called in { $(document).ajaxSuccess/redmine_wysiwyg_editor }
});
}
}, error: function (response) {
$('#ajax-indicator').removeClass('bottom');
console.error(response);
},
});
}
}

function loadPreviousAndNextIssueIds() {
$.ajax({
url: "<%= load_previous_and_next_issue_ids_path(@issue.id) %>",
success: function (response) {
if (response) {
$('.issue.details').prepend(response.html);
}
}, error: function (response) {
console.error(response);
},
});
}

$(document).ready(function () {
loadIssueEditForm();
loadPreviousAndNextIssueIds();
});
</script>
<% end %>
24 changes: 24 additions & 0 deletions app/views/issues/_previous_and_next_issue_ids.html.erb
Original file line number Diff line number Diff line change
@@ -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 %>
<div class="next-prev-links contextual">
<%= link_to_if @prev_issue_id,
"\xc2\xab #{l(:label_previous)}",
(@prev_issue_id ? issue_path(@prev_issue_id) : nil),
:title => "##{@prev_issue_id}",
:accesskey => accesskey(:previous) %> |
<% if @issue_position && @issue_count %>
<span class="position">
<%= link_to_if @query_path,
l(:label_item_position, :position => @issue_position, :count => @issue_count),
@query_path %>
</span> |
<% end %>
<%= link_to_if @next_issue_id,
"#{l(:label_next)} \xc2\xbb",
(@next_issue_id ? issue_path(@next_issue_id) : nil),
:title => "##{@next_issue_id}",
:accesskey => accesskey(:next) %>
</div>
<% end %>
7 changes: 4 additions & 3 deletions config/routes.rb
Original file line number Diff line number Diff line change
@@ -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
19 changes: 18 additions & 1 deletion lib/redmine_tiny_features/issues_controller_patch.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand All @@ -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
Expand Down
31 changes: 31 additions & 0 deletions spec/controllers/issues_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
26 changes: 26 additions & 0 deletions spec/requests/issues_spec.rb
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 1269d53

Please sign in to comment.