From 13b2fc61c1b047d7e5494b07f543a86826de1556 Mon Sep 17 00:00:00 2001
From: Samuel Young
Date: Thu, 30 Apr 2026 15:16:27 +0100
Subject: [PATCH 1/6] CLDC-3280: Remove error report upload again when viewing
before decision (#3303)
* CLDC-3280: Add back link to error summary page
* CLDC-3280: Hide upload button if navigating from a view url
* CLDC-3280: Update tests
* CLDC-3280: Make read only error report opt-in
this means we can be happy only the touched pages will have a change in behaviour
* CLDC-3280: Rename fix errors in tests to reupload file
Co-authored-by: Oscar Richardson <116292912+oscar-richardson-softwire@users.noreply.github.com>
---------
Co-authored-by: Oscar Richardson <116292912+oscar-richardson-softwire@users.noreply.github.com>
---
.../forms/bulk_upload_resume/confirm.rb | 6 ++--
.../forms/bulk_upload_resume/fix_choice.rb | 6 ++--
.../show.html.erb | 4 ++-
.../summary.html.erb | 8 ++++-
.../confirm.html.erb | 2 +-
.../fix_choice.html.erb | 2 +-
.../bulk_upload_sales_results/show.html.erb | 4 ++-
.../summary.html.erb | 8 ++++-
.../bulk_upload_sales_resume/confirm.html.erb | 2 +-
.../fix_choice.html.erb | 2 +-
...upload_lettings_results_controller_spec.rb | 36 +++++++++++++++++++
...lk_upload_sales_results_controller_spec.rb | 36 +++++++++++++++++++
12 files changed, 102 insertions(+), 14 deletions(-)
diff --git a/app/models/forms/bulk_upload_resume/confirm.rb b/app/models/forms/bulk_upload_resume/confirm.rb
index 96a1fe1bc..596018d50 100644
--- a/app/models/forms/bulk_upload_resume/confirm.rb
+++ b/app/models/forms/bulk_upload_resume/confirm.rb
@@ -20,11 +20,11 @@ module Forms
send("resume_bulk_upload_#{log_type}_result_path", bulk_upload)
end
- def error_report_path
+ def error_report_path(read_only: false)
if BulkUploadErrorSummaryTableComponent.new(bulk_upload:).errors?
- send("summary_bulk_upload_#{log_type}_result_path", bulk_upload)
+ send("summary_bulk_upload_#{log_type}_result_path", bulk_upload, hide_upload_button: read_only ? "true" : nil)
else
- send("bulk_upload_#{log_type}_result_path", bulk_upload)
+ send("bulk_upload_#{log_type}_result_path", bulk_upload, hide_upload_button: read_only ? "true" : nil)
end
end
diff --git a/app/models/forms/bulk_upload_resume/fix_choice.rb b/app/models/forms/bulk_upload_resume/fix_choice.rb
index c731dbf93..b14970643 100644
--- a/app/models/forms/bulk_upload_resume/fix_choice.rb
+++ b/app/models/forms/bulk_upload_resume/fix_choice.rb
@@ -34,11 +34,11 @@ module Forms
end
end
- def error_report_path
+ def error_report_path(read_only: false)
if BulkUploadErrorSummaryTableComponent.new(bulk_upload:).errors?
- send("summary_bulk_upload_#{log_type}_result_path", bulk_upload)
+ send("summary_bulk_upload_#{log_type}_result_path", bulk_upload, hide_upload_button: read_only ? "true" : nil)
else
- send("bulk_upload_#{log_type}_result_path", bulk_upload)
+ send("bulk_upload_#{log_type}_result_path", bulk_upload, hide_upload_button: read_only ? "true" : nil)
end
end
diff --git a/app/views/bulk_upload_lettings_results/show.html.erb b/app/views/bulk_upload_lettings_results/show.html.erb
index 5eedefe49..cf8c62eeb 100644
--- a/app/views/bulk_upload_lettings_results/show.html.erb
+++ b/app/views/bulk_upload_lettings_results/show.html.erb
@@ -33,4 +33,6 @@
-<%= govuk_button_link_to "Upload your file again", start_bulk_upload_lettings_logs_path(organisation_id: @bulk_upload.organisation_id) %>
+<% if params[:hide_upload_button] != "true" %>
+ <%= govuk_button_link_to "Upload your file again", start_bulk_upload_lettings_logs_path(organisation_id: @bulk_upload.organisation_id) %>
+<% end %>
diff --git a/app/views/bulk_upload_lettings_results/summary.html.erb b/app/views/bulk_upload_lettings_results/summary.html.erb
index ab60212e9..1a31eb0a9 100644
--- a/app/views/bulk_upload_lettings_results/summary.html.erb
+++ b/app/views/bulk_upload_lettings_results/summary.html.erb
@@ -1,3 +1,7 @@
+<% content_for :before_content do %>
+ <%= govuk_back_link(href: :back) %>
+<% end %>
+
<%= render partial: "bulk_upload_shared/moved_user_banner" %>
@@ -34,4 +38,6 @@
<% end %>
-<%= govuk_button_link_to "Upload your file again", start_bulk_upload_lettings_logs_path(organisation_id: @bulk_upload.organisation_id) %>
+<% if params[:hide_upload_button] != "true" %>
+ <%= govuk_button_link_to "Upload your file again", start_bulk_upload_lettings_logs_path(organisation_id: @bulk_upload.organisation_id) %>
+<% end %>
diff --git a/app/views/bulk_upload_lettings_resume/confirm.html.erb b/app/views/bulk_upload_lettings_resume/confirm.html.erb
index bb15c7101..c72cab57b 100644
--- a/app/views/bulk_upload_lettings_resume/confirm.html.erb
+++ b/app/views/bulk_upload_lettings_resume/confirm.html.erb
@@ -9,7 +9,7 @@
<%= logs_and_errors_warning(@bulk_upload) %>
- <%= govuk_link_to "View the error report", @form.error_report_path %>
+ <%= govuk_link_to "View the error report", @form.error_report_path(read_only: true) %>
<% if unique_answers_to_be_cleared(@bulk_upload).present? %>
diff --git a/app/views/bulk_upload_lettings_resume/fix_choice.html.erb b/app/views/bulk_upload_lettings_resume/fix_choice.html.erb
index 225fb07bf..3bb326d02 100644
--- a/app/views/bulk_upload_lettings_resume/fix_choice.html.erb
+++ b/app/views/bulk_upload_lettings_resume/fix_choice.html.erb
@@ -19,7 +19,7 @@
- <%= govuk_link_to "View the error report", @form.error_report_path %>
+ <%= govuk_link_to "View the error report", @form.error_report_path(read_only: true) %>
<%= govuk_details(summary_text: "How to choose between fixing errors on the CORE site or in the CSV") do %>
diff --git a/app/views/bulk_upload_sales_results/show.html.erb b/app/views/bulk_upload_sales_results/show.html.erb
index 2276285fe..68aaf7311 100644
--- a/app/views/bulk_upload_sales_results/show.html.erb
+++ b/app/views/bulk_upload_sales_results/show.html.erb
@@ -33,4 +33,6 @@
-<%= govuk_button_link_to "Upload your file again", start_bulk_upload_sales_logs_path(organisation_id: @bulk_upload.organisation_id) %>
+<% if params[:hide_upload_button] != "true" %>
+ <%= govuk_button_link_to "Upload your file again", start_bulk_upload_sales_logs_path(organisation_id: @bulk_upload.organisation_id) %>
+<% end %>
diff --git a/app/views/bulk_upload_sales_results/summary.html.erb b/app/views/bulk_upload_sales_results/summary.html.erb
index ed2ec14b3..fc9f39d82 100644
--- a/app/views/bulk_upload_sales_results/summary.html.erb
+++ b/app/views/bulk_upload_sales_results/summary.html.erb
@@ -1,3 +1,7 @@
+<% content_for :before_content do %>
+ <%= govuk_back_link(href: :back) %>
+<% end %>
+
<%= render partial: "bulk_upload_shared/moved_user_banner" %>
@@ -34,4 +38,6 @@
<% end %>
-<%= govuk_button_link_to "Upload your file again", start_bulk_upload_sales_logs_path(organisation_id: @bulk_upload.organisation_id) %>
+<% if params[:hide_upload_button] != "true" %>
+ <%= govuk_button_link_to "Upload your file again", start_bulk_upload_sales_logs_path(organisation_id: @bulk_upload.organisation_id) %>
+<% end %>
diff --git a/app/views/bulk_upload_sales_resume/confirm.html.erb b/app/views/bulk_upload_sales_resume/confirm.html.erb
index b47619053..1259d8bf9 100644
--- a/app/views/bulk_upload_sales_resume/confirm.html.erb
+++ b/app/views/bulk_upload_sales_resume/confirm.html.erb
@@ -9,7 +9,7 @@
<%= logs_and_errors_warning(@bulk_upload) %>
- <%= govuk_link_to "View the error report", @form.error_report_path %>
+ <%= govuk_link_to "View the error report", @form.error_report_path(read_only: true) %>
<% if unique_answers_to_be_cleared(@bulk_upload).present? %>
diff --git a/app/views/bulk_upload_sales_resume/fix_choice.html.erb b/app/views/bulk_upload_sales_resume/fix_choice.html.erb
index b376ee62d..8a2887678 100644
--- a/app/views/bulk_upload_sales_resume/fix_choice.html.erb
+++ b/app/views/bulk_upload_sales_resume/fix_choice.html.erb
@@ -19,7 +19,7 @@
- <%= govuk_link_to "View the error report", @form.error_report_path %>
+ <%= govuk_link_to "View the error report", @form.error_report_path(read_only: true) %>
<%= govuk_details(summary_text: "How to choose between fixing errors on the CORE site or in the CSV") do %>
diff --git a/spec/requests/bulk_upload_lettings_results_controller_spec.rb b/spec/requests/bulk_upload_lettings_results_controller_spec.rb
index 3416b6da9..e3ec4b4c1 100644
--- a/spec/requests/bulk_upload_lettings_results_controller_spec.rb
+++ b/spec/requests/bulk_upload_lettings_results_controller_spec.rb
@@ -82,6 +82,24 @@ RSpec.describe BulkUploadLettingsResultsController, type: :request do
expect(response.body).to include("You moved to a different organisation since this file was uploaded. Upload the file again to get an accurate error report.")
end
end
+
+ context "and user has upload button shown" do
+ it "displays a link to reupload file" do
+ get "/lettings-logs/bulk-upload-results/#{bulk_upload.id}/summary"
+
+ expect(response.body).to include("Upload your file again")
+ expect(response.body).to include("/lettings-logs/bulk-upload-logs/start")
+ end
+ end
+
+ context "and user has upload button hidden" do
+ it "does not display a link to reupload file" do
+ get "/lettings-logs/bulk-upload-results/#{bulk_upload.id}/summary?hide_upload_button=true"
+
+ expect(response.body).not_to include("Upload your file again")
+ expect(response.body).not_to include("/lettings-logs/bulk-upload-logs/start")
+ end
+ end
end
end
@@ -152,5 +170,23 @@ RSpec.describe BulkUploadLettingsResultsController, type: :request do
expect(response.body).to include("You moved to a different organisation since this file was uploaded. Upload the file again to get an accurate error report.")
end
end
+
+ context "and user has upload button shown" do
+ it "displays a link to reupload file" do
+ get "/lettings-logs/bulk-upload-results/#{bulk_upload.id}"
+
+ expect(response.body).to include("Upload your file again")
+ expect(response.body).to include("/lettings-logs/bulk-upload-logs/start")
+ end
+ end
+
+ context "and user has upload button hidden" do
+ it "does not display a link to reupload file" do
+ get "/lettings-logs/bulk-upload-results/#{bulk_upload.id}?hide_upload_button=true"
+
+ expect(response.body).not_to include("Upload your file again")
+ expect(response.body).not_to include("/lettings-logs/bulk-upload-logs/start")
+ end
+ end
end
end
diff --git a/spec/requests/bulk_upload_sales_results_controller_spec.rb b/spec/requests/bulk_upload_sales_results_controller_spec.rb
index 2236475fa..c6d31b0f4 100644
--- a/spec/requests/bulk_upload_sales_results_controller_spec.rb
+++ b/spec/requests/bulk_upload_sales_results_controller_spec.rb
@@ -44,6 +44,24 @@ RSpec.describe BulkUploadSalesResultsController, type: :request do
expect(response.body).to include("You moved to a different organisation since this file was uploaded. Upload the file again to get an accurate error report.")
end
end
+
+ context "and user has upload button shown" do
+ it "displays a link to reupload file" do
+ get "/sales-logs/bulk-upload-results/#{bulk_upload.id}/summary"
+
+ expect(response.body).to include("Upload your file again")
+ expect(response.body).to include("/sales-logs/bulk-upload-logs/start")
+ end
+ end
+
+ context "and user has upload button hidden" do
+ it "does not display a link to reupload file" do
+ get "/sales-logs/bulk-upload-results/#{bulk_upload.id}/summary?hide_upload_button=true"
+
+ expect(response.body).not_to include("Upload your file again")
+ expect(response.body).not_to include("/sales-logs/bulk-upload-logs/start")
+ end
+ end
end
end
@@ -127,5 +145,23 @@ RSpec.describe BulkUploadSalesResultsController, type: :request do
expect(response.body).to include("You moved to a different organisation since this file was uploaded. Upload the file again to get an accurate error report.")
end
end
+
+ context "and user has upload button shown" do
+ it "displays a link to reupload file" do
+ get "/sales-logs/bulk-upload-results/#{bulk_upload.id}"
+
+ expect(response.body).to include("Upload your file again")
+ expect(response.body).to include("/sales-logs/bulk-upload-logs/start")
+ end
+ end
+
+ context "and user has upload button hidden" do
+ it "does not display a link to reupload file" do
+ get "/sales-logs/bulk-upload-results/#{bulk_upload.id}?hide_upload_button=true"
+
+ expect(response.body).not_to include("Upload your file again")
+ expect(response.body).not_to include("/sales-logs/bulk-upload-logs/start")
+ end
+ end
end
end
From 614fd111e5b11469fb3f9087bf6b0249b261b7f5 Mon Sep 17 00:00:00 2001
From: Samuel Young
Date: Thu, 30 Apr 2026 17:04:20 +0100
Subject: [PATCH 2/6] CLDC-4300: Update sale date staircasing date validation
(#3341)
* CLDC-4300: Stricten validation on initialpurchase
* CLDC-4300: Add a correction script
* CLDC-4300: Update tests
* CLDC-4300: Ensure lasttransaction cannot equal saledate or initialtransaction
* CLDC-4300: Update date correcting rake to also account for lasttransaction = initialpurchase
* CLDC-4300: Revert updates to copy
* CLDC-4300: Apply these changes from 2026 only
* CLDC-4300: Compare lasttransaction to saledate
due to the it <= lt <= sd relationship, there's no need to comparse it to sd. if it == sd then it == lt and lt == sd
* CLDC-4300: Fix script in cases where all 3 dates are equal
---
.../sales/sale_information_validations.rb | 6 +-
...valid_initialpurchase_lasttransaction.rake | 15 ++++
.../sale_information_validations_spec.rb | 69 +++++++++++++++----
3 files changed, 75 insertions(+), 15 deletions(-)
create mode 100644 lib/tasks/fix_sales_logs_with_invalid_initialpurchase_lasttransaction.rake
diff --git a/app/models/validations/sales/sale_information_validations.rb b/app/models/validations/sales/sale_information_validations.rb
index 32bf2a716..7cd24183c 100644
--- a/app/models/validations/sales/sale_information_validations.rb
+++ b/app/models/validations/sales/sale_information_validations.rb
@@ -42,7 +42,7 @@ module Validations::Sales::SaleInformationValidations
record.errors.add :initialpurchase, I18n.t("validations.sales.sale_information.initialpurchase.must_be_after_1980")
end
- if record.saledate.present? && record.initialpurchase > record.saledate
+ if record.saledate.present? && ((record.initialpurchase > record.saledate) || (record.initialpurchase == record.saledate && record.form.start_year_2026_or_later?))
record.errors.add :initialpurchase, I18n.t("validations.sales.sale_information.initialpurchase.must_be_before_saledate")
record.errors.add :saledate, :skip_bu_error, message: I18n.t("validations.sales.sale_information.saledate.must_be_after_initial_purchase_date")
end
@@ -55,11 +55,11 @@ module Validations::Sales::SaleInformationValidations
record.errors.add :lasttransaction, I18n.t("validations.sales.sale_information.lasttransaction.must_be_after_1980")
end
- if record.saledate.present? && record.lasttransaction > record.saledate
+ if record.saledate.present? && ((record.lasttransaction > record.saledate) || (record.lasttransaction == record.saledate && record.form.start_year_2026_or_later?))
record.errors.add :lasttransaction, I18n.t("validations.sales.sale_information.lasttransaction.must_be_before_saledate")
record.errors.add :saledate, :skip_bu_error, message: I18n.t("validations.sales.sale_information.saledate.must_be_after_last_transaction_date")
end
- if record.initialpurchase.present? && record.lasttransaction < record.initialpurchase
+ if record.initialpurchase.present? && ((record.lasttransaction < record.initialpurchase) || (record.lasttransaction == record.initialpurchase && record.form.start_year_2026_or_later?))
record.errors.add :initialpurchase, I18n.t("validations.sales.sale_information.initialpurchase.must_be_before_last_transaction")
record.errors.add :lasttransaction, I18n.t("validations.sales.sale_information.lasttransaction.must_be_after_initial_purchase")
end
diff --git a/lib/tasks/fix_sales_logs_with_invalid_initialpurchase_lasttransaction.rake b/lib/tasks/fix_sales_logs_with_invalid_initialpurchase_lasttransaction.rake
new file mode 100644
index 000000000..11ff853a1
--- /dev/null
+++ b/lib/tasks/fix_sales_logs_with_invalid_initialpurchase_lasttransaction.rake
@@ -0,0 +1,15 @@
+desc "We tightened the validation between initial purchase date in 2026, last transaction date and sale date so the two can no longer be equal. To avoid invalid logs we clear initialpurchase if it equals saledate and if initialpurchase = lasttransaction we clear both"
+task fix_sales_logs_with_invalid_initialpurchase_lasttransaction: :environment do
+ initial_purchase_equal_lasttransaction_logs = SalesLog.filter_by_year_or_later(2026).where("initialpurchase = lasttransaction")
+ lasttransaction_equal_saledate_logs = SalesLog.filter_by_year_or_later(2026).where("lasttransaction = saledate")
+
+ # this one must happen first since this will always result in a log that passes date validations
+ puts "Updating #{initial_purchase_equal_lasttransaction_logs.count} logs where initialpurchase = lasttransaction, #{initial_purchase_equal_lasttransaction_logs.map(&:id)}"
+ initial_purchase_equal_lasttransaction_logs.update!(initialpurchase: nil, lasttransaction: nil)
+
+ # this one could fail if lasttransaction == saledate == initialpurchase, but the above case will have already reset these logs
+ puts "Updating #{lasttransaction_equal_saledate_logs.count} logs where lasttransaction = saledate, #{lasttransaction_equal_saledate_logs.map(&:id)}"
+ lasttransaction_equal_saledate_logs.update!(lasttransaction: nil)
+
+ puts "Done"
+end
diff --git a/spec/models/validations/sales/sale_information_validations_spec.rb b/spec/models/validations/sales/sale_information_validations_spec.rb
index 8d4eb4cea..04f71b198 100644
--- a/spec/models/validations/sales/sale_information_validations_spec.rb
+++ b/spec/models/validations/sales/sale_information_validations_spec.rb
@@ -252,12 +252,27 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
end
context "when initial purchase date == saledate" do
- let(:record) { build(:sales_log, initialpurchase: current_collection_start_date, saledate: current_collection_start_date) }
+ let(:record) { build(:sales_log, initialpurchase: collection_start_date_for_year(start_year), saledate: collection_start_date_for_year(start_year)) }
- it "does not add an error" do
- sale_information_validator.validate_staircasing_initial_purchase_date(record)
+ context "and 2025", metadata: { year: 25 } do
+ let(:start_year) { 2025 }
- expect(record.errors[:initialpurchase]).not_to be_present
+ it "does not add an error" do
+ sale_information_validator.validate_staircasing_initial_purchase_date(record)
+
+ expect(record.errors[:lasttransaction]).not_to be_present
+ end
+ end
+
+ context "and 2026", metadata: { year: 26 } do
+ let(:start_year) { 2026 }
+
+ it "adds error" do
+ sale_information_validator.validate_staircasing_initial_purchase_date(record)
+
+ expect(record.errors[:initialpurchase]).to eq([I18n.t("validations.sales.sale_information.initialpurchase.must_be_before_saledate")])
+ expect(record.errors[:saledate]).to eq([I18n.t("validations.sales.sale_information.saledate.must_be_after_initial_purchase_date")])
+ end
end
end
end
@@ -315,12 +330,27 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
end
context "when last transaction date == saledate" do
- let(:record) { build(:sales_log, lasttransaction: current_collection_start_date, saledate: current_collection_start_date) }
+ let(:record) { build(:sales_log, lasttransaction: collection_start_date_for_year(start_year), saledate: collection_start_date_for_year(start_year)) }
- it "does not add an error" do
- sale_information_validator.validate_staircasing_last_transaction_date(record)
+ context "and 2025", metadata: { year: 25 } do
+ let(:start_year) { 2025 }
- expect(record.errors[:lasttransaction]).not_to be_present
+ it "does not add an error" do
+ sale_information_validator.validate_staircasing_last_transaction_date(record)
+
+ expect(record.errors[:lasttransaction]).not_to be_present
+ end
+ end
+
+ context "and 2026", metadata: { year: 26 } do
+ let(:start_year) { 2026 }
+
+ it "adds error" do
+ sale_information_validator.validate_staircasing_last_transaction_date(record)
+
+ expect(record.errors[:lasttransaction]).to eq([I18n.t("validations.sales.sale_information.lasttransaction.must_be_before_saledate")])
+ expect(record.errors[:saledate]).to eq([I18n.t("validations.sales.sale_information.saledate.must_be_after_last_transaction_date")])
+ end
end
end
@@ -346,12 +376,27 @@ RSpec.describe Validations::Sales::SaleInformationValidations do
end
context "when last transaction date == initial purchase date" do
- let(:record) { build(:sales_log, lasttransaction: current_collection_start_date, initialpurchase: current_collection_start_date) }
+ let(:record) { build(:sales_log, lasttransaction: collection_start_date_for_year(start_year), initialpurchase: collection_start_date_for_year(start_year), saledate: collection_start_date_for_year(start_year) + 1.day) }
- it "does not add an error" do
- sale_information_validator.validate_staircasing_last_transaction_date(record)
+ context "and 2025", metadata: { year: 25 } do
+ let(:start_year) { 2025 }
- expect(record.errors[:lasttransaction]).not_to be_present
+ it "does not add an error" do
+ sale_information_validator.validate_staircasing_last_transaction_date(record)
+
+ expect(record.errors[:lasttransaction]).not_to be_present
+ end
+ end
+
+ context "and 2026", metadata: { year: 26 } do
+ let(:start_year) { 2026 }
+
+ it "adds error" do
+ sale_information_validator.validate_staircasing_last_transaction_date(record)
+
+ expect(record.errors[:lasttransaction]).to eq([I18n.t("validations.sales.sale_information.lasttransaction.must_be_after_initial_purchase")])
+ expect(record.errors[:initialpurchase]).to eq([I18n.t("validations.sales.sale_information.initialpurchase.must_be_before_last_transaction")])
+ end
end
end
end
From e0c3938b6b7b1c94ec632d98f34ac633fd1a28b4 Mon Sep 17 00:00:00 2001
From: Nat Dean-Lewis <94526761+natdeanlewissoftwire@users.noreply.github.com>
Date: Wed, 3 Jun 2026 16:55:34 +0100
Subject: [PATCH 3/6] CLDC-4470: Update vulnerable packages (#3349)
* feat: update addressable
* feat: update rack-session
* feat: update other high criticality dependencies
* feat: update other high criticality dependencies
* feat: update other high criticality dependencies
* feat: align with goovuk-components 6.x
* feat: update navbar styling
* feat: use helpers where required and update misc tests
* feat: add title test for support users
* refactor: linting
* feat: update application helper spec
* feat: add missing helpers
* refactor: make specs more readable
* refactor: lint
---
Gemfile | 4 +-
Gemfile.lock | 106 +-
.../bulk_upload_error_row_component.html.erb | 4 +-
.../bulk_upload_error_row_component.rb | 9 +-
...oad_error_summary_table_component.html.erb | 4 +-
...lk_upload_error_summary_table_component.rb | 3 +-
.../bulk_upload_summary_component.rb | 16 +-
...swers_summary_list_card_component.html.erb | 6 +-
...eck_answers_summary_list_card_component.rb | 11 +-
.../create_log_actions_component.html.erb | 18 +-
.../create_log_actions_component.rb | 19 +-
...ion_confirmation_banner_component.html.erb | 2 +-
...rotection_confirmation_banner_component.rb | 5 +-
.../document_list_component.html.erb | 2 +-
app/components/document_list_component.rb | 2 +-
.../lettings_log_summary_component.html.erb | 2 +-
.../lettings_log_summary_component.rb | 2 +-
...ing_stock_owners_banner_component.html.erb | 2 +-
.../missing_stock_owners_banner_component.rb | 9 +-
.../primary_navigation_component.html.erb | 2 +-
.../primary_navigation_component.rb | 2 +-
.../sales_log_summary_component.html.erb | 2 +-
app/components/sales_log_summary_component.rb | 2 +-
app/components/search_component.html.erb | 4 +-
app/components/search_component.rb | 2 +-
.../search_result_caption_component.rb | 2 +-
.../sub_navigation_component.html.erb | 4 +-
app/components/sub_navigation_component.rb | 2 +-
app/frontend/styles/_filter.scss | 2 +-
app/frontend/styles/_header.scss | 11 -
app/frontend/styles/_related-navigation.scss | 2 +-
app/frontend/styles/_tag.scss | 2 +-
app/frontend/styles/_testing-tools.scss | 2 +-
app/frontend/styles/application.scss | 12 +
app/helpers/application_helper.rb | 13 +-
app/views/layouts/application.html.erb | 30 +-
.../layouts/rails_admin/_navigation.html.erb | 18 +-
app/views/users/_user_list.html.erb | 4 +-
package.json | 4 +-
spec/helpers/application_helper_spec.rb | 46 +-
spec/requests/users_controller_spec.rb | 54 +-
webpack.config.js | 4 +-
yarn.lock | 1377 +++++++++--------
43 files changed, 985 insertions(+), 844 deletions(-)
diff --git a/Gemfile b/Gemfile
index c76a48bec..d68325a7f 100644
--- a/Gemfile
+++ b/Gemfile
@@ -18,7 +18,7 @@ gem "jsbundling-rails"
# Reduces boot times through caching; required in config/boot.rb
gem "bootsnap", ">= 1.4.4", require: false
# GOV UK frontend components
-gem "govuk-components", "~> 5.7"
+gem "govuk-components", "~> 6.2"
# GOV UK component form builder DSL
gem "govuk_design_system_formbuilder", "~> 5.7"
# Convert Markdown into GOV.UK frontend-styled HTML
@@ -40,7 +40,7 @@ gem "devise_two_factor_authentication"
gem "uk_postcode"
# Get rich data from postcode lookups. Wraps postcodes.io
# Use Ruby objects to build reusable markup. A React inspired evolution of the presenter pattern
-gem "view_component", "~> 3.9"
+gem "view_component", "~> 4.9"
# Use the AWS S3 SDK as storage mechanism
gem "aws-sdk-s3"
# Track changes to models for auditing or versioning.
diff --git a/Gemfile.lock b/Gemfile.lock
index c83c95414..903824128 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -78,8 +78,8 @@ GEM
minitest (>= 5.1, < 6)
securerandom (>= 0.3)
tzinfo (~> 2.0, >= 2.0.5)
- addressable (2.8.6)
- public_suffix (>= 2.0.2, < 6.0)
+ addressable (2.9.0)
+ public_suffix (>= 2.0.2, < 8.0)
ast (2.4.3)
auto_strip_attributes (2.6.0)
activerecord (>= 4.0)
@@ -123,7 +123,7 @@ GEM
erubi (~> 1.4)
parser (>= 2.4)
smart_properties
- bigdecimal (4.0.1)
+ bigdecimal (4.1.2)
bindex (0.8.1)
bootsnap (1.18.3)
msgpack (~> 1.2)
@@ -155,18 +155,21 @@ GEM
coercible (1.0.0)
descendants_tracker (~> 0.0.1)
concurrent-ruby (1.3.6)
- connection_pool (2.5.3)
+ connection_pool (2.5.5)
crack (1.0.0)
bigdecimal
rexml
crass (1.0.6)
+ cronex (0.15.0)
+ tzinfo
+ unicode (>= 0.4.4.5)
cssbundling-rails (1.4.0)
railties (>= 6.0.0)
csv (3.3.2)
date (3.5.1)
descendants_tracker (0.0.4)
thread_safe (~> 0.3, >= 0.3.1)
- devise (5.0.3)
+ devise (5.0.4)
bcrypt (~> 3.0)
orm_adapter (~> 0.1)
railties (>= 7.0)
@@ -187,7 +190,7 @@ GEM
drb (2.2.3)
dumb_delegator (1.0.0)
encryptor (3.0.0)
- erb (6.0.2)
+ erb (6.0.4)
erb_lint (0.9.0)
activesupport
better_html (>= 2.0.1)
@@ -196,7 +199,7 @@ GEM
rubocop (>= 1)
smart_properties
erubi (1.13.1)
- et-orbi (1.2.11)
+ et-orbi (1.4.0)
tzinfo
event_stream_parser (1.0.0)
excon (0.111.0)
@@ -207,24 +210,24 @@ GEM
railties (>= 5.0.0)
faker (3.2.3)
i18n (>= 1.8.11, < 2)
- faraday (2.14.1)
+ faraday (2.14.2)
faraday-net_http (>= 2.0, < 3.5)
json
logger
faraday-multipart (1.0.4)
multipart-post (~> 2)
- faraday-net_http (3.1.0)
- net-http
+ faraday-net_http (3.4.3)
+ net-http (~> 0.5)
ffi (1.16.3)
- fugit (1.11.1)
- et-orbi (~> 1, >= 1.2.11)
+ fugit (1.12.2)
+ et-orbi (~> 1.4)
raabro (~> 1.4)
- globalid (1.2.1)
+ globalid (1.3.0)
activesupport (>= 6.1)
- govuk-components (5.7.0)
+ govuk-components (6.2.0)
html-attributes-utils (~> 1.0.0, >= 1.0.0)
pagy (>= 6, < 10)
- view_component (>= 3.9, < 3.17)
+ view_component (>= 4.9, < 4.10)
govuk_design_system_formbuilder (5.7.1)
actionview (>= 6.1)
activemodel (>= 6.1)
@@ -241,7 +244,7 @@ GEM
ice_nine (0.11.2)
iniparse (1.5.0)
io-console (0.8.2)
- irb (1.17.0)
+ irb (1.18.0)
pp (>= 0.6.0)
prism (>= 1.3.0)
rdoc (>= 4.0.0)
@@ -249,10 +252,10 @@ GEM
jmespath (1.6.2)
jsbundling-rails (1.3.0)
railties (>= 6.0.0)
- json (2.19.2)
+ json (2.19.7)
json-schema (4.1.1)
addressable (>= 2.8)
- jwt (2.8.0)
+ jwt (3.2.0)
base64
kaminari (1.2.2)
activesupport (>= 4.1.0)
@@ -290,9 +293,9 @@ GEM
msgpack (1.7.2)
multipart-post (2.4.1)
nested_form (0.3.2)
- net-http (0.4.1)
- uri
- net-imap (0.5.7)
+ net-http (0.9.1)
+ uri (>= 0.11.1)
+ net-imap (0.6.4)
date
net-protocol
net-pop (0.1.2)
@@ -302,22 +305,22 @@ GEM
net-smtp (0.5.1)
net-protocol
nio4r (2.7.4)
- nokogiri (1.19.1-arm64-darwin)
+ nokogiri (1.19.3-arm64-darwin)
racc (~> 1.4)
- nokogiri (1.19.1-x86_64-darwin)
+ nokogiri (1.19.3-x86_64-darwin)
racc (~> 1.4)
- nokogiri (1.19.1-x86_64-linux-gnu)
+ nokogiri (1.19.3-x86_64-linux-gnu)
racc (~> 1.4)
- nokogiri (1.19.1-x86_64-linux-musl)
+ nokogiri (1.19.3-x86_64-linux-musl)
racc (~> 1.4)
- notifications-ruby-client (6.0.0)
- jwt (>= 1.5, < 3)
+ notifications-ruby-client (6.4.0)
+ jwt (>= 1.5, < 4)
orm_adapter (0.5.0)
overcommit (0.63.0)
childprocess (>= 0.6.3, < 6)
iniparse (~> 1.4)
rexml (~> 3.2)
- pagy (9.3.2)
+ pagy (9.4.0)
paper_trail (15.2.0)
activerecord (>= 6.1)
request_store (~> 1.4)
@@ -350,19 +353,19 @@ GEM
psych (5.3.1)
date
stringio
- public_suffix (5.0.4)
+ public_suffix (7.0.5)
puma (6.5.0)
nio4r (~> 2.0)
pundit (2.3.1)
activesupport (>= 3.0.0)
raabro (1.4.0)
racc (1.8.1)
- rack (3.1.20)
+ rack (3.1.21)
rack-attack (6.7.0)
rack (>= 1.0, < 4)
rack-mini-profiler (3.3.1)
rack (>= 1.2.0)
- rack-session (2.1.1)
+ rack-session (2.1.2)
base64 (>= 0.1.0)
rack (>= 3.0.0)
rack-test (2.2.0)
@@ -408,7 +411,7 @@ GEM
tsort (>= 0.2)
zeitwerk (~> 2.6)
rainbow (3.1.1)
- rake (13.3.1)
+ rake (13.4.2)
randexp (0.1.7)
rb-fsevent (0.11.2)
rb-inotify (0.10.1)
@@ -419,7 +422,7 @@ GEM
tsort
redcarpet (3.6.0)
redis (4.8.1)
- redis-client (0.22.1)
+ redis-client (0.29.0)
connection_pool
regexp_parser (2.11.3)
reline (0.6.3)
@@ -508,15 +511,17 @@ GEM
sentry-ruby (~> 5.16.1)
sentry-ruby (5.16.1)
concurrent-ruby (~> 1.0, >= 1.0.2)
- sidekiq (7.2.4)
- concurrent-ruby (< 2)
- connection_pool (>= 2.3.0)
- rack (>= 2.2.4)
- redis-client (>= 0.19.0)
- sidekiq-cron (1.12.0)
- fugit (~> 1.8)
+ sidekiq (8.0.10)
+ connection_pool (>= 2.5.0)
+ json (>= 2.9.0)
+ logger (>= 1.6.2)
+ rack (>= 3.1.0)
+ redis-client (>= 0.23.2)
+ sidekiq-cron (2.4.0)
+ cronex (>= 0.13.0)
+ fugit (~> 1.8, >= 1.11.1)
globalid (>= 1.0.1)
- sidekiq (>= 6)
+ sidekiq (>= 6.5.0)
simplecov (0.22.0)
docile (~> 1.1)
simplecov-html (~> 0.11)
@@ -530,7 +535,7 @@ GEM
thor (1.4.0)
thread_safe (0.3.6)
timecop (0.9.8)
- timeout (0.4.3)
+ timeout (0.6.1)
tsort (0.2.0)
turbo-rails (2.0.13)
actionpack (>= 7.1.0)
@@ -538,17 +543,18 @@ GEM
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
uk_postcode (2.1.8)
+ unicode (0.4.4.5)
unicode-display_width (3.2.0)
unicode-emoji (~> 4.1)
unicode-emoji (4.2.0)
unread (0.14.0)
activerecord (>= 6.1)
- uri (1.0.4)
+ uri (1.1.1)
useragent (0.16.11)
- view_component (3.10.0)
- activesupport (>= 5.2.0, < 8.0)
- concurrent-ruby (~> 1.0)
- method_source (~> 1.0)
+ view_component (4.9.0)
+ actionview (>= 7.1.0)
+ activesupport (>= 7.1.0)
+ concurrent-ruby (~> 1)
virtus (2.0.0)
axiom-types (~> 0.1)
coercible (~> 1.0)
@@ -571,7 +577,7 @@ GEM
websocket-extensions (0.1.5)
xpath (3.2.0)
nokogiri (~> 1.8)
- zeitwerk (2.7.5)
+ zeitwerk (2.8.2)
PLATFORMS
arm64-darwin
@@ -599,7 +605,7 @@ DEPENDENCIES
factory_bot_rails
faker
faraday (>= 2.14.1)
- govuk-components (~> 5.7)
+ govuk-components (~> 6.2)
govuk_design_system_formbuilder (~> 5.7)
govuk_markdown
jsbundling-rails
@@ -643,7 +649,7 @@ DEPENDENCIES
tzinfo-data
uk_postcode
unread
- view_component (~> 3.9)
+ view_component (~> 4.9)
web-console (>= 4.1.0)
webmock
diff --git a/app/components/bulk_upload_error_row_component.html.erb b/app/components/bulk_upload_error_row_component.html.erb
index 8cfdb674e..4ce6e4f5c 100644
--- a/app/components/bulk_upload_error_row_component.html.erb
+++ b/app/components/bulk_upload_error_row_component.html.erb
@@ -13,7 +13,7 @@
<% if critical_errors.any? %>
Critical errors
These errors must be fixed to complete your logs.
- <%= govuk_table(html_attributes: { class: potential_errors.any? ? "" : "no-bottom-border" }) do |table| %>
+ <%= helpers.govuk_table(html_attributes: { class: potential_errors.any? ? "" : "no-bottom-border" }) do |table| %>
<%= table.with_head do |head| %>
<% head.with_row do |row| %>
<% row.with_cell(header: true, text: "Cell") %>
@@ -39,7 +39,7 @@
<% if potential_errors.any? %>
Confirmation needed
Potential data discrepancies exist in the following cells.
Please resolve all critical errors and review the cells with data discrepancies before re-uploading the file. Bulk confirmation of potential discrepancies is accessible only after all critical errors have been resolved.
- <%= govuk_table(html_attributes: { class: "no-bottom-border" }) do |table| %>
+ <%= helpers.govuk_table(html_attributes: { class: "no-bottom-border" }) do |table| %>
<%= table.with_head do |head| %>
<% head.with_row do |row| %>
<% row.with_cell(header: true, text: "Cell") %>
diff --git a/app/components/bulk_upload_error_row_component.rb b/app/components/bulk_upload_error_row_component.rb
index 1cb4de9d8..569f71b85 100644
--- a/app/components/bulk_upload_error_row_component.rb
+++ b/app/components/bulk_upload_error_row_component.rb
@@ -2,9 +2,8 @@ class BulkUploadErrorRowComponent < ViewComponent::Base
attr_reader :bulk_upload_errors
def initialize(bulk_upload_errors:)
+ super()
@bulk_upload_errors = bulk_upload_errors
-
- super
end
def row
@@ -18,7 +17,7 @@ class BulkUploadErrorRowComponent < ViewComponent::Base
def tenant_code_html
return if tenant_code.blank?
- content_tag :span, class: "govuk-!-margin-left-3" do
+ helpers.content_tag :span, class: "govuk-!-margin-left-3" do
"Tenant code: #{tenant_code}"
end
end
@@ -30,7 +29,7 @@ class BulkUploadErrorRowComponent < ViewComponent::Base
def purchaser_code_html
return if purchaser_code.blank?
- content_tag :span, class: "govuk-!-margin-left-3" do
+ helpers.content_tag :span, class: "govuk-!-margin-left-3" do
"Purchaser code: #{purchaser_code}"
end
end
@@ -42,7 +41,7 @@ class BulkUploadErrorRowComponent < ViewComponent::Base
def property_ref_html
return if property_ref.blank?
- content_tag :span, class: "govuk-!-margin-left-3" do
+ helpers.content_tag :span, class: "govuk-!-margin-left-3" do
"Property reference: #{property_ref}"
end
end
diff --git a/app/components/bulk_upload_error_summary_table_component.html.erb b/app/components/bulk_upload_error_summary_table_component.html.erb
index f9b42f34d..58489612a 100644
--- a/app/components/bulk_upload_error_summary_table_component.html.erb
+++ b/app/components/bulk_upload_error_summary_table_component.html.erb
@@ -3,7 +3,7 @@
<% sorted_errors.each do |error| %>
- <%= govuk_table do |table| %>
+ <%= helpers.govuk_table do |table| %>
<%= table.with_head do |head| %>
<% head.with_row do |row| %>
<% row.with_cell(text: question_for_field(error[0][1].to_sym), header: true) %>
@@ -13,7 +13,7 @@
<%= table.with_body do |body| %>
<% body.with_row do |row| %>
<% row.with_cell(text: error[0][2].html_safe) %>
- <% row.with_cell(text: pluralize(error[1], "error"), numeric: true) %>
+ <% row.with_cell(text: helpers.pluralize(error[1], "error"), numeric: true) %>
<% end %>
<% end %>
<% end %>
diff --git a/app/components/bulk_upload_error_summary_table_component.rb b/app/components/bulk_upload_error_summary_table_component.rb
index d15d5280e..db69fd9ec 100644
--- a/app/components/bulk_upload_error_summary_table_component.rb
+++ b/app/components/bulk_upload_error_summary_table_component.rb
@@ -6,9 +6,8 @@ class BulkUploadErrorSummaryTableComponent < ViewComponent::Base
delegate :question_for_field, to: :row_parser_class
def initialize(bulk_upload:)
+ super()
@bulk_upload = bulk_upload
-
- super
end
def sorted_errors
diff --git a/app/components/bulk_upload_summary_component.rb b/app/components/bulk_upload_summary_component.rb
index fa4cad414..2df854536 100644
--- a/app/components/bulk_upload_summary_component.rb
+++ b/app/components/bulk_upload_summary_component.rb
@@ -2,9 +2,9 @@ class BulkUploadSummaryComponent < ViewComponent::Base
attr_reader :bulk_upload
def initialize(bulk_upload:)
+ super()
@bulk_upload = bulk_upload
@bulk_upload_errors = bulk_upload.bulk_upload_errors
- super
end
def upload_status
@@ -27,9 +27,9 @@ class BulkUploadSummaryComponent < ViewComponent::Base
return if count.nil? || count <= 0
text = count > 1 ? (plural_text || singular_text.pluralize(count)) : singular_text
- content_tag(:p, class: "govuk-!-font-size-16 govuk-!-margin-bottom-1") do
- concat(content_tag(:strong, count))
- concat(" #{text}")
+ helpers.content_tag(:p, class: "govuk-!-font-size-16 govuk-!-margin-bottom-1") do
+ helpers.concat(helpers.content_tag(:strong, count))
+ helpers.concat(" #{text}")
end
end
@@ -44,11 +44,11 @@ class BulkUploadSummaryComponent < ViewComponent::Base
end
def download_lettings_file_link(bulk_upload)
- govuk_link_to "Download file", download_lettings_bulk_upload_path(bulk_upload), class: "govuk-link govuk-!-margin-right-2"
+ helpers.govuk_link_to "Download file", download_lettings_bulk_upload_path(bulk_upload), class: "govuk-link govuk-!-margin-right-2"
end
def download_sales_file_link(bulk_upload)
- govuk_link_to "Download file", download_sales_bulk_upload_path(bulk_upload), class: "govuk-link govuk-!-margin-right-2"
+ helpers.govuk_link_to "Download file", download_sales_bulk_upload_path(bulk_upload), class: "govuk-link govuk-!-margin-right-2"
end
def view_error_report_link(bulk_upload)
@@ -61,12 +61,12 @@ class BulkUploadSummaryComponent < ViewComponent::Base
"bulk_upload_#{bulk_upload.log_type}_result_path"
end
- govuk_link_to "View error report", send(path, bulk_upload), class: "govuk-link"
+ helpers.govuk_link_to "View error report", helpers.send(path, bulk_upload), class: "govuk-link"
end
def view_logs_link(bulk_upload)
return unless bulk_upload.status.to_s == "logs_uploaded_with_errors"
- govuk_link_to "View logs with errors", send("#{bulk_upload.log_type}_logs_path", bulk_upload_id: [bulk_upload.id]), class: "govuk-link"
+ helpers.govuk_link_to "View logs with errors", helpers.send("#{bulk_upload.log_type}_logs_path", bulk_upload_id: [bulk_upload.id]), class: "govuk-link"
end
end
diff --git a/app/components/check_answers_summary_list_card_component.html.erb b/app/components/check_answers_summary_list_card_component.html.erb
index 8b0c7d9b0..c9c974938 100644
--- a/app/components/check_answers_summary_list_card_component.html.erb
+++ b/app/components/check_answers_summary_list_card_component.html.erb
@@ -7,12 +7,12 @@
<% end %>
- <%= govuk_summary_list do |summary_list| %>
+ <%= helpers.govuk_summary_list do |summary_list| %>
<% applicable_questions.each do |question| %>
<% summary_list.with_row do |row| %>
<% row.with_key { get_question_label(question) } %>
<% row.with_value do %>
- <%= simple_format(
+ <%= helpers.simple_format(
get_answer_label(question),
wrapper_tag: "span",
class: "govuk-!-margin-right-4",
@@ -21,7 +21,7 @@
<% extra_value = question.get_extra_check_answer_value(log) %>
<% if extra_value && question.answer_label(log).present? %>
- <%= simple_format(
+ <%= helpers.simple_format(
extra_value,
wrapper_tag: "span",
class: "govuk-!-font-weight-regular app-!-colour-muted",
diff --git a/app/components/check_answers_summary_list_card_component.rb b/app/components/check_answers_summary_list_card_component.rb
index 1dc345f01..89345a0eb 100644
--- a/app/components/check_answers_summary_list_card_component.rb
+++ b/app/components/check_answers_summary_list_card_component.rb
@@ -2,12 +2,11 @@ class CheckAnswersSummaryListCardComponent < ViewComponent::Base
attr_reader :questions, :log, :user
def initialize(questions:, log:, user:, correcting_hard_validation: false)
+ super()
@questions = questions
@log = log
@user = user
@correcting_hard_validation = correcting_hard_validation
-
- super
end
def applicable_questions
@@ -34,16 +33,16 @@ class CheckAnswersSummaryListCardComponent < ViewComponent::Base
def action_href(question, log)
referrer = question.displayed_as_answered?(log) ? "check_answers" : "check_answers_new_answer"
- send("#{log.log_type}_#{question.page.id}_path", log, referrer:)
+ helpers.send("#{log.log_type}_#{question.page.id}_path", log, referrer:)
end
def correct_validation_action_href(question, log, _related_question_ids, correcting_hard_validation)
return action_href(question, log) unless correcting_hard_validation
if question.displayed_as_answered?(log)
- send("#{log.log_type}_confirm_clear_answer_path", log, question_id: question.id)
+ helpers.send("#{log.log_type}_confirm_clear_answer_path", log, question_id: question.id)
else
- send("#{log.log_type}_#{question.page.id}_path", log, referrer: "check_errors", related_question_ids: request.query_parameters["related_question_ids"], original_page_id: request.query_parameters["original_page_id"])
+ helpers.send("#{log.log_type}_#{question.page.id}_path", log, referrer: "check_errors", related_question_ids: request.query_parameters["related_question_ids"], original_page_id: request.query_parameters["original_page_id"])
end
end
@@ -56,7 +55,7 @@ private
"govuk-link govuk-link--no-visited-state"
end
- govuk_link_to question.check_answer_prompt, correct_validation_action_href(question, log, nil, @correcting_hard_validation), class: link_class
+ helpers.govuk_link_to question.check_answer_prompt, correct_validation_action_href(question, log, nil, @correcting_hard_validation), class: link_class
end
def number_of_buyers
diff --git a/app/components/create_log_actions_component.html.erb b/app/components/create_log_actions_component.html.erb
index 130072ec0..c8f557bce 100644
--- a/app/components/create_log_actions_component.html.erb
+++ b/app/components/create_log_actions_component.html.erb
@@ -1,11 +1,11 @@