diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9262551021..8a820b59f5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -60,6 +60,7 @@ For more detailed explanation, please refer to this video : https://www.youtube.
### Enhancements
- Added enum to the funding status attribute of plan model to make the dropdown of 'funding status' being translatable
+- Allow users to download both single phase and in PDF, TEXT and DOCX format. CSV file can only download single phase instead of all phases.
### Bug Fixes
diff --git a/app/controllers/plan_exports_controller.rb b/app/controllers/plan_exports_controller.rb
index f89458508f..a000a53588 100644
--- a/app/controllers/plan_exports_controller.rb
+++ b/app/controllers/plan_exports_controller.rb
@@ -36,12 +36,18 @@ def show
@hash = @plan.as_pdf(current_user, @show_coversheet)
@formatting = export_params[:formatting] || @plan.settings(:export).formatting
- @selected_phase = if params.key?(:phase_id)
- @plan.phases.find(params[:phase_id])
- else
- @plan.phases.order('phases.updated_at DESC')
+ if params.key?(:phase_id) && params[:phase_id].length.positive?
+ # order phases by phase number asc
+ @hash[:phases] = @hash[:phases].sort_by { |phase| phase[:number] }
+ if params[:phase_id] == 'All'
+ @hash[:all_phases] = true
+ else
+ @selected_phase = @plan.phases.find(params[:phase_id])
+ end
+ else
+ @selected_phase = @plan.phases.order('phases.updated_at DESC')
.detect { |p| p.visibility_allowed?(@plan) }
- end
+ end
# Added contributors to coverage of plans.
# Users will see both roles and contributor names if the role is filled
@@ -102,7 +108,7 @@ def show_pdf
date: l(@plan.updated_at.to_date, format: :readable)),
font_size: 8,
spacing: (Integer(@formatting[:margin][:bottom]) / 2) - 4,
- right: '[page] of [topage]',
+ right: _('[page] of [topage]'),
encoding: 'utf8'
}
end
diff --git a/app/controllers/plans_controller.rb b/app/controllers/plans_controller.rb
index 84b0af25c7..421514001a 100644
--- a/app/controllers/plans_controller.rb
+++ b/app/controllers/plans_controller.rb
@@ -376,6 +376,7 @@ def download
@plan = Plan.find(params[:id])
authorize @plan
@phase_options = @plan.phases.order(:number).pluck(:title, :id)
+ @phase_options.insert(0, ['All phases', 'All']) if @phase_options.length > 1
@export_settings = @plan.settings(:export)
render 'download'
end
diff --git a/app/javascript/src/plans/download.js b/app/javascript/src/plans/download.js
index e772b83221..6e1440f04c 100644
--- a/app/javascript/src/plans/download.js
+++ b/app/javascript/src/plans/download.js
@@ -21,5 +21,15 @@ $(() => {
} else {
$('#download-settings').show();
}
- });
+
+ if (frmt === 'csv') {
+ $('#phase_id').find('option[value="All"').hide();
+ $('#phase_id option:eq(1)').attr('selected', 'selected');
+ $('#phase_id').val($('#phase_id option:eq(1)').val());
+ } else if (frmt === 'pdf' || frmt === 'html' || frmt === 'docx' || frmt === 'text') {
+ $('#phase_id').find('option[value="All"').show();
+ $('#phase_id').val($('#phase_id option:first').val());
+ $('#phase_id option:first').attr('selected', 'selected');
+ }
+ }).trigger('change');
});
diff --git a/app/views/shared/export/_plan.erb b/app/views/shared/export/_plan.erb
index dac27560f2..aae3b9b705 100644
--- a/app/views/shared/export/_plan.erb
+++ b/app/views/shared/export/_plan.erb
@@ -18,7 +18,7 @@
<% @hash[:phases].each do |phase| %>
<%# Only render selected phase %>
- <% if phase[:title] == @selected_phase.title %>
+ <% if @hash[:all_phases] || (@selected_phase.present? && phase[:title] == @selected_phase.title) %>
<%# Page break before each phase %>
<%= download_plan_page_title(@plan, phase, @hash) %>
diff --git a/app/views/shared/export/_plan_txt.erb b/app/views/shared/export/_plan_txt.erb
index 7a9c42b87f..ff8570c785 100644
--- a/app/views/shared/export/_plan_txt.erb
+++ b/app/views/shared/export/_plan_txt.erb
@@ -38,7 +38,7 @@
<% @hash[:phases].each do |phase| %>
<%# Only render selected phase %>
-<% if phase[:title] == @selected_phase.title %>
+<% if @hash[:all_phases] || (@selected_phase.present? && phase[:title] == @selected_phase.title) %>
<%= (@hash[:phases].length > 1 ? "#{phase[:title]}" : "") %>
<% phase[:sections].each do |section| %>
<% if display_section?(@hash[:customization], section, @show_custom_sections) && num_section_questions(@plan, section, phase) > 0 %>
diff --git a/spec/features/plans/exports_spec.rb b/spec/features/plans/exports_spec.rb
index 4feec44845..38081afb3f 100644
--- a/spec/features/plans/exports_spec.rb
+++ b/spec/features/plans/exports_spec.rb
@@ -78,15 +78,35 @@
expect(page).not_to have_text(new_plan.title)
end
+ # Separate code to test all-phase-download for html since it requires operation in new window
scenario 'User downloads their plan as HTML' do
within("#plan_#{plan.id}") do
click_button('Actions')
click_link 'Download'
end
select('html')
- new_window = window_opened_by { click_button 'Download Plan' }
- within_window new_window do
- expect(page.source).to have_text(plan.title)
+ if plan.phases.present?
+ new_window = window_opened_by do
+ _select_option('phase_id', 'All')
+ click_button 'Download Plan'
+ end
+ within_window new_window do
+ expect(page.source).to have_text(plan.title)
+ plan.phases.each do |phase|
+ expect(page.source).to have_text(phase.title)
+ end
+ end
+ new_window = window_opened_by do
+ _select_option('phase_id', plan.phases[1].id)
+ click_button 'Download Plan'
+ end
+ within_window new_window do
+ expect(page.source).to have_text(plan.title)
+ expect(page.source).to have_text(plan.phases[1].title)
+ expect(page.source).not_to have_text(plan.phases[2].title) if plan.phases.length > 2
+ end
+ else
+ _regular_download('html')
end
end
@@ -96,8 +116,12 @@
click_link 'Download'
end
select('pdf')
- click_button 'Download Plan'
- expect(page.source).to have_text(plan.title)
+ if plan.phases.present?
+ _all_phase_download
+ _single_phase_download
+ else
+ _regular_download('pdf')
+ end
end
scenario 'User downloads their plan as CSV' do
@@ -106,8 +130,7 @@
click_link 'Download'
end
select('csv')
- click_button 'Download Plan'
- expect(page.source).to have_text(plan.title)
+ _regular_download('csv')
end
scenario 'User downloads their plan as text' do
@@ -116,8 +139,12 @@
click_link 'Download'
end
select('text')
- click_button 'Download Plan'
- expect(page.source).to have_text(plan.title)
+ if plan.phases.present?
+ _all_phase_download
+ _single_phase_download
+ else
+ _regular_download('text')
+ end
end
scenario 'User downloads their plan as docx' do
@@ -126,7 +153,53 @@
click_link 'Download'
end
select('docx')
+ if plan.phases.present?
+ _all_phase_download
+ _single_phase_download
+ else
+ _regular_download('docx')
+ end
+ end
+
+ # ===========================
+ # = Helper methods =
+ # ===========================
+
+ # rubocop:disable Metrics/AbcSize
+ # disable Rubocup metrics check to confirm both plan title and phase title on downloaded file
+ def _regular_download(format)
+ if format == 'html'
+ new_window = window_opened_by do
+ click_button 'Download Plan'
+ end
+ within_window new_window do
+ expect(page.source).to have_text(plan.title)
+ end
+ else
+ click_button 'Download Plan'
+ expect(page.source).to have_text(plan.title)
+ end
+ end
+
+ def _all_phase_download
+ _select_option('phase_id', 'All')
click_button 'Download Plan'
expect(page.source).to have_text(plan.title)
+ plan.phases.each do |phase| # All phase titles should be included in output
+ expect(page.source).to have_text(phase.title)
+ end
+ end
+
+ def _single_phase_download
+ _select_option('phase_id', plan.phases[1].id)
+ click_button 'Download Plan'
+ expect(page.source).to have_text(plan.title)
+ expect(page.source).to have_text(plan.phases[1].title)
+ expect(page.source).not_to have_text(plan.phases[2].title) if plan.phases.length > 2
+ end
+
+ # rubocop:enable Metrics/AbcSize
+ def _select_option(select_id, option_value)
+ find(:id, select_id).find("option[value='#{option_value}']").select_option
end
end