Browse Source

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
pull/3352/head^2
Nat Dean-Lewis 6 days ago committed by GitHub
parent
commit
e0c3938b6b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 4
      Gemfile
  2. 106
      Gemfile.lock
  3. 4
      app/components/bulk_upload_error_row_component.html.erb
  4. 9
      app/components/bulk_upload_error_row_component.rb
  5. 4
      app/components/bulk_upload_error_summary_table_component.html.erb
  6. 3
      app/components/bulk_upload_error_summary_table_component.rb
  7. 16
      app/components/bulk_upload_summary_component.rb
  8. 6
      app/components/check_answers_summary_list_card_component.html.erb
  9. 11
      app/components/check_answers_summary_list_card_component.rb
  10. 18
      app/components/create_log_actions_component.html.erb
  11. 19
      app/components/create_log_actions_component.rb
  12. 2
      app/components/data_protection_confirmation_banner_component.html.erb
  13. 5
      app/components/data_protection_confirmation_banner_component.rb
  14. 2
      app/components/document_list_component.html.erb
  15. 2
      app/components/document_list_component.rb
  16. 2
      app/components/lettings_log_summary_component.html.erb
  17. 2
      app/components/lettings_log_summary_component.rb
  18. 2
      app/components/missing_stock_owners_banner_component.html.erb
  19. 9
      app/components/missing_stock_owners_banner_component.rb
  20. 2
      app/components/primary_navigation_component.html.erb
  21. 2
      app/components/primary_navigation_component.rb
  22. 2
      app/components/sales_log_summary_component.html.erb
  23. 2
      app/components/sales_log_summary_component.rb
  24. 4
      app/components/search_component.html.erb
  25. 2
      app/components/search_component.rb
  26. 2
      app/components/search_result_caption_component.rb
  27. 4
      app/components/sub_navigation_component.html.erb
  28. 2
      app/components/sub_navigation_component.rb
  29. 2
      app/frontend/styles/_filter.scss
  30. 11
      app/frontend/styles/_header.scss
  31. 2
      app/frontend/styles/_related-navigation.scss
  32. 2
      app/frontend/styles/_tag.scss
  33. 2
      app/frontend/styles/_testing-tools.scss
  34. 12
      app/frontend/styles/application.scss
  35. 13
      app/helpers/application_helper.rb
  36. 30
      app/views/layouts/application.html.erb
  37. 18
      app/views/layouts/rails_admin/_navigation.html.erb
  38. 4
      app/views/users/_user_list.html.erb
  39. 4
      package.json
  40. 46
      spec/helpers/application_helper_spec.rb
  41. 54
      spec/requests/users_controller_spec.rb
  42. 4
      webpack.config.js
  43. 1377
      yarn.lock

4
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.

106
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

4
app/components/bulk_upload_error_row_component.html.erb

@ -13,7 +13,7 @@
<% if critical_errors.any? %>
<h2 class="govuk-heading-m">Critical errors</h2>
<p class="govuk-body">These errors must be fixed to complete your logs.</p>
<%= 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? %>
<h2 class="govuk-heading-m">Confirmation needed</h2>
<p class="govuk-body">Potential data discrepancies exist in the following cells.<br><br>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.</p>
<%= 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") %>

9
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

4
app/components/bulk_upload_error_summary_table_component.html.erb

@ -3,7 +3,7 @@
</p>
<% 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 %>

3
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

16
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

6
app/components/check_answers_summary_list_card_component.html.erb

@ -7,12 +7,12 @@
<% end %>
<div class="govuk-summary-card__content">
<%= 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",

11
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

18
app/components/create_log_actions_component.html.erb

@ -1,11 +1,11 @@
<div class="govuk-button-group app-filter-toggle <%= "govuk-!-margin-bottom-6" if display_actions? %>">
<% if display_actions? %>
<%= govuk_button_to create_button_copy, create_button_href, class: "govuk-!-margin-right-3" %>
<%= helpers.govuk_button_to create_button_copy, create_button_href, class: "govuk-!-margin-right-3" %>
<% unless user.support? %>
<%= govuk_button_link_to upload_button_copy, upload_button_href, secondary: true %>
<%= helpers.govuk_button_link_to upload_button_copy, upload_button_href, secondary: true %>
<% end %>
<% if user.support? %>
<%= govuk_button_link_to view_uploads_button_copy, view_uploads_button_href, secondary: true %>
<%= helpers.govuk_button_link_to view_uploads_button_copy, view_uploads_button_href, secondary: true %>
<% end %>
<% if FeatureToggle.create_test_logs_enabled? %>
@ -13,42 +13,42 @@
<span class="govuk-tag app-testing-tools__tag">Testing tools</span>
<span class="govuk-body govuk-body-s">These tools can only be seen and used in testing environments.</span>
<div>
<%= govuk_button_link_to create_test_log_href, class: "govuk-button" do %>
<%= helpers.govuk_button_link_to create_test_log_href, class: "govuk-button" do %>
New <%= current_collection_year_label %> test log
<svg class="govuk-button__start-icon" xmlns="http://www.w3.org/2000/svg" width="17.5" height="19" viewBox="0 0 33 40" aria-hidden="true" focusable="false">
<path fill="currentColor" d="M0 0h13l20 20-20 20H0l20-20z"></path>
</svg>
<% end %>
<% if FeatureToggle.allow_future_form_use? %>
<%= govuk_button_link_to create_next_year_test_log_href, class: "govuk-button" do %>
<%= helpers.govuk_button_link_to create_next_year_test_log_href, class: "govuk-button" do %>
New <%= next_collection_year_label %> test log
<svg class="govuk-button__start-icon" xmlns="http://www.w3.org/2000/svg" width="17.5" height="19" viewBox="0 0 33 40" aria-hidden="true" focusable="false">
<path fill="currentColor" d="M0 0h13l20 20-20 20H0l20-20z"></path>
</svg>
<% end %>
<% end %>
<%= govuk_button_link_to create_setup_test_log_href, class: "govuk-button" do %>
<%= helpers.govuk_button_link_to create_setup_test_log_href, class: "govuk-button" do %>
New <%= current_collection_year_label %> test log (setup only)
<svg class="govuk-button__start-icon" xmlns="http://www.w3.org/2000/svg" width="17.5" height="19" viewBox="0 0 33 40" aria-hidden="true" focusable="false">
<path fill="currentColor" d="M0 0h13l20 20-20 20H0l20-20z"></path>
</svg>
<% end %>
<% if FeatureToggle.allow_future_form_use? %>
<%= govuk_button_link_to create_next_year_setup_test_log_href, class: "govuk-button" do %>
<%= helpers.govuk_button_link_to create_next_year_setup_test_log_href, class: "govuk-button" do %>
New <%= next_collection_year_label %> test log (setup only)
<svg class="govuk-button__start-icon" xmlns="http://www.w3.org/2000/svg" width="17.5" height="19" viewBox="0 0 33 40" aria-hidden="true" focusable="false">
<path fill="currentColor" d="M0 0h13l20 20-20 20H0l20-20z"></path>
</svg>
<% end %>
<% end %>
<%= govuk_button_link_to create_test_bulk_upload_href(2025), class: "govuk-button govuk-button--secondary" do %>
<%= helpers.govuk_button_link_to create_test_bulk_upload_href(2025), class: "govuk-button govuk-button--secondary" do %>
25/26 BU test file
<svg class="govuk-button__start-icon bi bi-download" xmlns="http://www.w3.org/2000/svg" width="18" height="19" fill="currentColor" viewBox="0 0 16 16" stroke="currentColor" stroke-width="1.4">
<path d="M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5" />
<path d="M7.646 11.854a.5.5 0 0 0 .708 0l3-3a.5.5 0 0 0-.708-.708L8.5 10.293V1.5a.5.5 0 0 0-1 0v8.793L5.354 8.146a.5.5 0 1 0-.708.708z" />
</svg>
<% end %>
<%= govuk_button_link_to create_test_bulk_upload_href(2026), class: "govuk-button govuk-button--secondary" do %>
<%= helpers.govuk_button_link_to create_test_bulk_upload_href(2026), class: "govuk-button govuk-button--secondary" do %>
26/27 BU test file
<svg class="govuk-button__start-icon bi bi-download" xmlns="http://www.w3.org/2000/svg" width="18" height="19" fill="currentColor" viewBox="0 0 16 16" stroke="currentColor" stroke-width="1.4">
<path d="M.5 9.9a.5.5 0 0 1 .5.5v2.5a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-2.5a.5.5 0 0 1 1 0v2.5a2 2 0 0 1-2 2H2a2 2 0 0 1-2-2v-2.5a.5.5 0 0 1 .5-.5" />

19
app/components/create_log_actions_component.rb

@ -5,11 +5,10 @@ class CreateLogActionsComponent < ViewComponent::Base
attr_reader :bulk_upload, :user, :log_type
def initialize(user:, log_type:, bulk_upload: nil)
super()
@bulk_upload = bulk_upload
@user = user
@log_type = log_type
super
end
def display_actions?
@ -24,7 +23,7 @@ class CreateLogActionsComponent < ViewComponent::Base
end
def create_button_href
send("#{log_type}_logs_path")
helpers.send("#{log_type}_logs_path")
end
def upload_button_copy
@ -32,23 +31,23 @@ class CreateLogActionsComponent < ViewComponent::Base
end
def upload_button_href
send("bulk_upload_#{log_type}_log_path", id: "start")
helpers.send("bulk_upload_#{log_type}_log_path", id: "start")
end
def create_test_log_href
send("create_test_#{log_type}_log_path")
helpers.send("create_test_#{log_type}_log_path")
end
def create_next_year_test_log_href
send("create_next_year_test_#{log_type}_log_path")
helpers.send("create_next_year_test_#{log_type}_log_path")
end
def create_setup_test_log_href
send("create_setup_test_#{log_type}_log_path")
helpers.send("create_setup_test_#{log_type}_log_path")
end
def create_next_year_setup_test_log_href
send("create_next_year_setup_test_#{log_type}_log_path")
helpers.send("create_next_year_setup_test_#{log_type}_log_path")
end
def current_collection_year_label
@ -60,7 +59,7 @@ class CreateLogActionsComponent < ViewComponent::Base
end
def create_test_bulk_upload_href(year)
send("create_#{year}_test_#{log_type}_bulk_upload_path")
helpers.send("create_#{year}_test_#{log_type}_bulk_upload_path")
end
def view_uploads_button_copy
@ -68,6 +67,6 @@ class CreateLogActionsComponent < ViewComponent::Base
end
def view_uploads_button_href
send("bulk_uploads_#{log_type}_logs_path")
helpers.send("bulk_uploads_#{log_type}_logs_path")
end
end

2
app/components/data_protection_confirmation_banner_component.html.erb

@ -1,5 +1,5 @@
<% if display_banner? %>
<%= govuk_notification_banner(title_text: "Important") do %>
<%= helpers.govuk_notification_banner(title_text: "Important") do %>
<p class="govuk-notification-banner__heading govuk-!-width-full" style="max-width: fit-content">
<%= header_text %>
<p>

5
app/components/data_protection_confirmation_banner_component.rb

@ -4,10 +4,9 @@ class DataProtectionConfirmationBannerComponent < ViewComponent::Base
attr_reader :user, :organisation
def initialize(user:, organisation: nil)
super()
@user = user
@organisation = organisation
super
end
def display_banner?
@ -32,7 +31,7 @@ class DataProtectionConfirmationBannerComponent < ViewComponent::Base
def banner_text
if show_no_dpo_message? || user.is_dpo? || !org_or_user_org.holds_own_stock?
govuk_link_to(
helpers.govuk_link_to(
link_text,
link_href,
class: "govuk-notification-banner__link govuk-!-font-weight-bold",

2
app/components/document_list_component.html.erb

@ -5,7 +5,7 @@
<% items.each do |item| %>
<div class="app-document-list__item">
<dt class="app-document-list__item-title">
<%= govuk_link_to item[:name], item[:href] %>
<%= helpers.govuk_link_to item[:name], item[:href] %>
</dt>
<% if item[:description] %>
<dd class="app-document-list__item-description"><%= item[:description] %></dd>

2
app/components/document_list_component.rb

@ -2,8 +2,8 @@ class DocumentListComponent < ViewComponent::Base
attr_reader :items, :label
def initialize(items:, label:)
super()
@items = items
@label = label
super
end
end

2
app/components/lettings_log_summary_component.html.erb

@ -3,7 +3,7 @@
<div class="govuk-grid-column-two-thirds">
<header class="app-log-summary__header">
<h2 class="app-log-summary__title">
<%= govuk_link_to lettings_log_path(log) do %>
<%= helpers.govuk_link_to lettings_log_path(log) do %>
Log <%= log.id %>
<% end %>
</h2>

2
app/components/lettings_log_summary_component.rb

@ -2,9 +2,9 @@ class LettingsLogSummaryComponent < ViewComponent::Base
attr_reader :current_user, :log
def initialize(current_user:, log:)
super()
@current_user = current_user
@log = log
super
end
def log_status

2
app/components/missing_stock_owners_banner_component.html.erb

@ -1,5 +1,5 @@
<% if display_banner? %>
<%= govuk_notification_banner(title_text: "Important") do %>
<%= helpers.govuk_notification_banner(title_text: "Important") do %>
<p class="govuk-notification-banner__heading govuk-!-width-full" style="max-width: fit-content">
<%= header_text %>
<p>

9
app/components/missing_stock_owners_banner_component.rb

@ -4,10 +4,9 @@ class MissingStockOwnersBannerComponent < ViewComponent::Base
attr_reader :user, :organisation
def initialize(user:, organisation: nil)
super()
@user = user
@organisation = organisation || user.organisation
super
end
def display_banner?
@ -36,7 +35,7 @@ class MissingStockOwnersBannerComponent < ViewComponent::Base
private
def add_stock_owner_link
govuk_link_to(
helpers.govuk_link_to(
"add a stock owner",
stock_owners_add_organisation_path(id: organisation.id),
class: "govuk-notification-banner__link govuk-!-font-weight-bold",
@ -44,7 +43,7 @@ private
end
def contact_helpdesk_link
govuk_link_to(
helpers.govuk_link_to(
"contact the helpdesk",
GlobalConstants::HELPDESK_URL,
class: "govuk-notification-banner__link govuk-!-font-weight-bold",
@ -52,7 +51,7 @@ private
end
def users_link
govuk_link_to(
helpers.govuk_link_to(
"users page",
users_path,
class: "govuk-notification-banner__link govuk-!-font-weight-bold",

2
app/components/primary_navigation_component.html.erb

@ -1,4 +1,4 @@
<%= govuk_service_navigation(navigation_id: "primary-navigation", classes: "app-service-navigation") do |sn|
<%= helpers.govuk_service_navigation(navigation_id: "primary-navigation", classes: "app-service-navigation") do |sn|
items.each do |item|
sn.with_navigation_item(text: item[:text], href: item[:href], classes: "", current: item[:current])
end

2
app/components/primary_navigation_component.rb

@ -2,8 +2,8 @@ class PrimaryNavigationComponent < ViewComponent::Base
attr_reader :items
def initialize(items:)
super()
@items = items
super
end
def highlighted_item?(item, _path)

2
app/components/sales_log_summary_component.html.erb

@ -3,7 +3,7 @@
<div class="govuk-grid-column-two-thirds">
<header class="app-log-summary__header">
<h2 class="app-log-summary__title">
<%= govuk_link_to sales_log_path(log) do %>
<%= helpers.govuk_link_to sales_log_path(log) do %>
Log <%= log.id %>
<% end %>
</h2>

2
app/components/sales_log_summary_component.rb

@ -2,9 +2,9 @@ class SalesLogSummaryComponent < ViewComponent::Base
attr_reader :current_user, :log
def initialize(current_user:, log:)
super()
@current_user = current_user
@log = log
super
end
def log_status

4
app/components/search_component.html.erb

@ -1,4 +1,4 @@
<%= form_with url: path(current_user), method: "get", local: true do |f| %>
<%= helpers.form_with url: path(current_user), method: "get", local: true do |f| %>
<div class="app-search govuk-!-margin-bottom-4">
<%= f.govuk_text_field :search,
form_group: {
@ -11,6 +11,6 @@
class: "app-search__input" %>
<%= f.govuk_submit "Search", class: "app-search__button" %>
<%= govuk_button_link_to "Clear search", path(current_user), secondary: true, class: "app-search__button" %>
<%= helpers.govuk_button_link_to "Clear search", path(current_user), secondary: true, class: "app-search__button" %>
</div>
<% end %>

2
app/components/search_component.rb

@ -2,10 +2,10 @@ class SearchComponent < ViewComponent::Base
attr_reader :current_user, :search_label, :value
def initialize(current_user:, search_label:, value: nil)
super()
@current_user = current_user
@search_label = search_label
@value = value
super
end
def path(current_user)

2
app/components/search_result_caption_component.rb

@ -2,12 +2,12 @@ class SearchResultCaptionComponent < ViewComponent::Base
attr_reader :searched, :count, :item_label, :total_count, :item, :filters_count
def initialize(searched:, count:, item_label:, total_count:, item:, filters_count:)
super()
@searched = searched
@count = count
@item_label = item_label
@total_count = total_count
@item = item
@filters_count = filters_count
super
end
end

4
app/components/sub_navigation_component.html.erb

@ -3,11 +3,11 @@
<% items.each do |item| %>
<% if item.current %>
<li class="app-sub-navigation__item app-sub-navigation__item--current">
<%= govuk_link_to item[:text], item[:href], class: "app-sub-navigation__link", aria: { current: "page" } %>
<%= helpers.govuk_link_to item[:text], item[:href], class: "app-sub-navigation__link", aria: { current: "page" } %>
</li>
<% else %>
<li class="app-sub-navigation__item">
<%= govuk_link_to item[:text], item[:href], class: "app-sub-navigation__link" %>
<%= helpers.govuk_link_to item[:text], item[:href], class: "app-sub-navigation__link" %>
</li>
<% end %>
<% end %>

2
app/components/sub_navigation_component.rb

@ -2,8 +2,8 @@ class SubNavigationComponent < ViewComponent::Base
attr_reader :items
def initialize(items:)
super()
@items = items
super
end
def highlighted_item?(item, _path)

2
app/frontend/styles/_filter.scss

@ -109,7 +109,7 @@
}
.autocomplete__option__hint {
@include govuk-font(14);
@include govuk-font(16);
word-break: break-all;
}
}

11
app/frontend/styles/_header.scss

@ -1,6 +1,4 @@
.app-header {
border-bottom: govuk-spacing(2) solid $govuk-brand-colour;
.govuk-header__logo {
@include govuk-media-query($from: desktop) {
width: 60%;
@ -21,12 +19,3 @@
}
}
}
.app-header--orange,
.app-header--orange .govuk-header__container {
border-bottom-color: govuk-colour("orange");
}
.app-header__no-border-bottom {
border-bottom: 0;
}

2
app/frontend/styles/_related-navigation.scss

@ -11,7 +11,7 @@
.app-related-navigation__sub-heading {
@include govuk-font(16);
border-top: 1px solid govuk-colour("mid-grey", $legacy: "grey-2");
border-top: 1px solid govuk-colour("mid-grey");
margin: 0;
padding-top: govuk-spacing(3);
}

2
app/frontend/styles/_tag.scss

@ -1,5 +1,5 @@
.app-tag--small {
@include govuk-font(14, $weight: bold);
@include govuk-font(16, $weight: bold);
padding-top: 2px;
padding-right: 6px;
padding-bottom: 2px;

2
app/frontend/styles/_testing-tools.scss

@ -12,7 +12,7 @@
}
.app-testing-tools__tag {
@include govuk-font(14);
@include govuk-font(16);
background-color: #fcd6c3;
margin-top: 0;
margin-bottom: 10px;

12
app/frontend/styles/application.scss

@ -130,3 +130,15 @@ $govuk-breakpoints: (
left: -15px;
position: relative;
}
.app-main-service-navigation {
border-bottom: govuk-spacing(2) solid $govuk-brand-colour;
}
.app-service-navigation--orange {
border-bottom-color: govuk-colour("orange");
}
.app-service-navigation--no-border {
border-bottom: 0;
}

13
app/helpers/application_helper.rb

@ -10,14 +10,11 @@ module ApplicationHelper
end
end
def govuk_header_classes(current_user)
if current_user&.support?
"app-header app-header--orange"
elsif notifications_to_display?
"app-header app-header__no-border-bottom"
else
"app-header"
end
def govuk_service_navigation_classes(current_user)
return "app-service-navigation--orange" if current_user&.support?
return "app-service-navigation--no-border" if notifications_to_display?
""
end
def govuk_phase_banner_tag(current_user)

30
app/views/layouts/application.html.erb

@ -81,20 +81,24 @@
<%= govuk_skip_link %>
<%= govuk_header(
classes: govuk_header_classes(current_user),
classes: "app-header",
homepage_url: root_path,
navigation_classes: "govuk-header__navigation--end",
) do |component|
component.with_product_name(name: t("service_name"))
unless FeatureToggle.service_moved? || FeatureToggle.service_unavailable?
if current_user.nil?
component.with_navigation_item(text: "Sign in", href: user_session_path)
else
component.with_navigation_item(text: "Your account", href: account_path)
component.with_navigation_item(text: "Sign out", href: destroy_user_session_path)
end
end
end %>
) %>
<%= govuk_service_navigation(
service_name: t("service_name"),
service_url: root_path,
classes: "app-main-service-navigation #{govuk_service_navigation_classes(current_user)}",
) do |component| %>
<% unless FeatureToggle.service_moved? || FeatureToggle.service_unavailable? %>
<% if current_user.nil? %>
<%= component.with_navigation_item(text: "Sign in", href: user_session_path) %>
<% else %>
<%= component.with_navigation_item(text: "Your account", href: account_path) %>
<%= component.with_navigation_item(text: "Sign out", href: destroy_user_session_path) %>
<% end %>
<% end %>
<% end %>
<% if notifications_to_display? %>
<%= render "notifications/notification_banner" %>

18
app/views/layouts/rails_admin/_navigation.html.erb

@ -1,9 +1,13 @@
<%= govuk_header(
classes: "app-header app-header--orange",
classes: "app-header",
homepage_url: Rails.application.routes.url_helpers.root_path,
navigation_classes: "govuk-header__navigation--end",
) do |component|
component.with_product_name(name: t("service_name"))
component.with_navigation_item(text: "Your account", href: Rails.application.routes.url_helpers.account_path)
component.with_navigation_item(text: "Sign out", href: Rails.application.routes.url_helpers.destroy_user_session_path)
end %>
) %>
<%= govuk_service_navigation(
service_name: t("service_name"),
service_url: Rails.application.routes.url_helpers.root_path,
classes: "app-main-service-navigation app-service-navigation--orange",
) do |component| %>
<%= component.with_navigation_item(text: "Your account", href: Rails.application.routes.url_helpers.account_path) %>
<%= component.with_navigation_item(text: "Sign out", href: Rails.application.routes.url_helpers.destroy_user_session_path) %>
<% end %>

4
app/views/users/_user_list.html.erb

@ -36,7 +36,7 @@
<% if user.is_data_protection_officer? %>
<%= govuk_tag(
classes: "app-tag--small",
colour: "turquoise",
colour: "teal",
text: "Data protection officer",
) %>
<% else %>
@ -45,7 +45,7 @@
<% if user.is_key_contact? %>
<%= govuk_tag(
classes: "app-tag--small",
colour: "turquoise",
colour: "teal",
text: "Key contact",
) %>
<% else %>

4
package.json

@ -12,7 +12,7 @@
"@ministryofjustice/frontend": "^3.3.0",
"@stimulus/polyfills": "^2.0.0",
"@webcomponents/webcomponentsjs": "^2.6.0",
"@x-govuk/govuk-prototype-components": "^3.0.9",
"@x-govuk/govuk-prototype-components": "^6.0.0",
"accessible-autocomplete": "^2.0.3",
"babel-loader": "^8.2.3",
"babel-plugin-macros": "^3.1.0",
@ -21,7 +21,7 @@
"css-loader": "^6.7.1",
"custom-event-polyfill": "^1.0.7",
"file-loader": "^6.2.0",
"govuk-frontend": "5.7.1",
"govuk-frontend": "6.0.0",
"html5shiv": "^3.7.3",
"intersection-observer": "^0.12.0",
"jquery": "^3.7.1",

46
spec/helpers/application_helper_spec.rb

@ -8,18 +8,50 @@ RSpec.describe ApplicationHelper do
let(:pagy) { nil }
let(:current_user) { FactoryBot.create(:user) }
describe "govuk_header_classes" do
context "with external user" do
it "shows the standard app header" do
expect(govuk_header_classes(current_user)).to eq("app-header")
describe "govuk_service_navigation_classes" do
context "with non-support user" do
context "when no notifications are displayed" do
before do
allow(helper).to receive(:notifications_to_display?).and_return(false)
end
it "returns empty string for blue border (default)" do
expect(helper.govuk_service_navigation_classes(current_user)).to eq("")
end
end
context "when notifications are displayed" do
before do
allow(helper).to receive(:notifications_to_display?).and_return(true)
end
it "returns no-border class to hide the border (notification banner shows instead)" do
expect(helper.govuk_service_navigation_classes(current_user)).to eq("app-service-navigation--no-border")
end
end
end
context "with internal support user" do
context "with support user" do
let(:current_user) { FactoryBot.create(:user, :support) }
it "shows an orange header" do
expect(govuk_header_classes(current_user)).to eq("app-header app-header--orange")
context "when no notifications are displayed" do
before do
allow(helper).to receive(:notifications_to_display?).and_return(false)
end
it "always returns orange class for orange border" do
expect(helper.govuk_service_navigation_classes(current_user)).to eq("app-service-navigation--orange")
end
end
context "when notifications are displayed" do
before do
allow(helper).to receive(:notifications_to_display?).and_return(true)
end
it "still returns orange class (support users always see orange border)" do
expect(helper.govuk_service_navigation_classes(current_user)).to eq("app-service-navigation--orange")
end
end
end
end

54
spec/requests/users_controller_spec.rb

@ -76,13 +76,39 @@ RSpec.describe UsersController, type: :request do
end
describe "title link" do
it "routes user to the home page" do
sign_in user
get "/", headers:, params: {}
expect(path).to eq("/")
expect(page).to have_content("Welcome back")
expected_link = "<a class=\"govuk-header__link govuk-header__link--homepage\" href=\"/\">"
expect(CGI.unescape_html(response.body)).to include(expected_link)
context "with a non-support user" do
before do
sign_in user
end
it "has GOV.UK header and service navigation both linking to home page" do
get "/", headers:, params: {}
expect(path).to eq("/")
expect(page).to have_content("Welcome back")
govuk_header_link = '<a class="govuk-header__link govuk-header__homepage-link" href="/">'
expect(CGI.unescape_html(response.body)).to include(govuk_header_link)
expect(page).to have_css(".govuk-service-navigation__link[href='/']", text: "Submit social housing lettings and sales data (CORE)")
end
end
context "with a support user" do
let(:support_user) { create(:user, :support) }
before do
sign_in support_user
end
it "has GOV.UK header and service navigation both linking to home page" do
get "/", headers:, params: {}
follow_redirect!
govuk_header_link = '<a class="govuk-header__link govuk-header__homepage-link" href="/">'
expect(CGI.unescape_html(response.body)).to include(govuk_header_link)
expect(page).to have_css(".govuk-service-navigation__link[href='/']", text: "Submit social housing lettings and sales data (CORE)")
end
end
end
@ -2597,18 +2623,4 @@ RSpec.describe UsersController, type: :request do
end
end
end
describe "title link" do
before do
sign_in user
end
it "routes user to the home page" do
get "/", headers:, params: {}
expect(path).to eq("/")
expect(page).to have_content("Welcome back")
expected_link = "<a class=\"govuk-header__link govuk-header__link--homepage\" href=\"/\">"
expect(CGI.unescape_html(response.body)).to include(expected_link)
end
end
end

4
webpack.config.js

@ -40,8 +40,8 @@ module.exports = {
},
resolve: {
alias: {
'govuk-frontend-styles': path.resolve(__dirname, 'node_modules/govuk-frontend/dist/govuk/all.scss'),
'govuk-prototype-styles': path.resolve(__dirname, 'node_modules/@x-govuk/govuk-prototype-components/x-govuk/all.scss'),
'govuk-frontend-styles': path.resolve(__dirname, 'node_modules/govuk-frontend/dist/govuk/index.scss'),
'govuk-prototype-styles': path.resolve(__dirname, 'node_modules/@x-govuk/govuk-prototype-components/dist/govuk-prototype-components.scss'),
'moj-frontend': path.resolve(__dirname, 'node_modules/@ministryofjustice/frontend/moj/all.js')
},
modules: ['node_modules', 'node_modules/govuk-frontend/dist/govuk']

1377
yarn.lock

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save