diff --git a/.github/workflows/staging_pipeline.yml b/.github/workflows/staging_pipeline.yml index e743f4504..b9ab15e17 100644 --- a/.github/workflows/staging_pipeline.yml +++ b/.github/workflows/staging_pipeline.yml @@ -5,6 +5,9 @@ on: branches: - main pull_request: + types: + - opened + - ready_for_review workflow_dispatch: defaults: @@ -14,6 +17,7 @@ defaults: jobs: test: name: Test + if: '!github.event.pull_request.draft' runs-on: ubuntu-latest services: @@ -72,6 +76,7 @@ jobs: lint: name: Lint + if: '!github.event.pull_request.draft' runs-on: ubuntu-latest steps: @@ -99,6 +104,7 @@ jobs: audit: name: Audit dependencies + if: '!github.event.pull_request.draft' runs-on: ubuntu-latest steps: diff --git a/Gemfile b/Gemfile index e1cb5e1a9..90ee5eed2 100644 --- a/Gemfile +++ b/Gemfile @@ -27,8 +27,6 @@ gem "govuk_markdown" gem "notifications-ruby-client" # A modest javascript framework for the html you already have gem "stimulus-rails" -# Admin charts -gem "chartkick" # Spreadsheet parsing gem "roo" # Json Schema diff --git a/Gemfile.lock b/Gemfile.lock index 1859e66a6..fec988e50 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -93,7 +93,7 @@ GEM public_suffix (>= 2.0.2, < 5.0) ast (2.4.2) aws-eventstream (1.2.0) - aws-partitions (1.592.0) + aws-partitions (1.598.0) aws-sdk-core (3.131.1) aws-eventstream (~> 1, >= 1.0.2) aws-partitions (~> 1, >= 1.525.0) @@ -118,7 +118,7 @@ GEM parser (>= 2.4) smart_properties bindex (0.8.1) - bootsnap (1.11.1) + bootsnap (1.12.0) msgpack (~> 1.2) builder (3.2.4) bundler-audit (0.9.1) @@ -139,7 +139,6 @@ GEM capybara (>= 2.0) ruby2_keywords selenium-webdriver (>= 3) - chartkick (4.1.3) childprocess (4.1.0) coderay (1.1.3) concurrent-ruby (1.1.10) @@ -174,8 +173,9 @@ GEM ffi (1.15.5) globalid (1.0.0) activesupport (>= 5.0) - govuk-components (3.0.4) + govuk-components (3.0.6) activemodel (>= 6.1) + html-attributes-utils (~> 0.9.0) railties (>= 6.1) view_component (~> 2.49.1) govuk_design_system_formbuilder (3.0.3) @@ -198,7 +198,7 @@ GEM railties (>= 6.0.0) json-schema (3.0.0) addressable (>= 2.8) - jwt (2.3.0) + jwt (2.4.1) listen (3.7.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) @@ -212,7 +212,7 @@ GEM method_source (1.0.0) mini_mime (1.1.2) minitest (5.15.0) - msgpack (1.5.1) + msgpack (1.5.2) net-imap (0.2.3) digest net-protocol @@ -295,7 +295,7 @@ GEM rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) - rails-html-sanitizer (1.4.2) + rails-html-sanitizer (1.4.3) loofah (~> 2.3) railties (7.0.3) actionpack (= 7.0.3) @@ -312,7 +312,7 @@ GEM ffi (~> 1.0) redcarpet (3.5.1) redis (4.6.0) - regexp_parser (2.4.0) + regexp_parser (2.5.0) request_store (1.5.1) rack (>= 1.4) responders (3.0.1) @@ -357,7 +357,7 @@ GEM rubocop-rails (= 2.13.2) rubocop-rake (= 0.6.0) rubocop-rspec (= 2.7.0) - rubocop-performance (1.14.0) + rubocop-performance (1.14.2) rubocop (>= 1.7.0, < 2.0) rubocop-ast (>= 0.4.0) rubocop-rails (2.13.2) @@ -371,10 +371,11 @@ GEM ruby-progressbar (1.11.0) ruby2_keywords (0.0.5) rubyzip (2.3.2) - selenium-webdriver (4.1.0) + selenium-webdriver (4.2.1) childprocess (>= 0.5, < 5.0) rexml (~> 3.2, >= 3.2.5) - rubyzip (>= 1.2.2) + rubyzip (>= 1.2.2, < 3.0) + websocket (~> 1.0) sentry-rails (5.3.1) railties (>= 5.0) sentry-ruby-core (~> 5.3.1) @@ -414,12 +415,13 @@ GEM addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) + websocket (1.2.9) websocket-driver (0.7.5) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) xpath (3.2.0) nokogiri (~> 1.8) - zeitwerk (2.5.4) + zeitwerk (2.6.0) PLATFORMS arm64-darwin-21 @@ -435,7 +437,6 @@ DEPENDENCIES byebug capybara capybara-lockstep - chartkick devise! dotenv-rails erb_lint diff --git a/app/components/primary_navigation_component.rb b/app/components/primary_navigation_component.rb index 0389d30b3..e766a83ce 100644 --- a/app/components/primary_navigation_component.rb +++ b/app/components/primary_navigation_component.rb @@ -3,6 +3,7 @@ class PrimaryNavigationComponent < ViewComponent::Base def initialize(items:) @items = items + Rails.env.production? ? @items = @items.reject { |nav_item| nav_item.text.include?("Supported housing") } : @items super end diff --git a/app/components/search_component.rb b/app/components/search_component.rb index eefdc5309..b08c1039a 100644 --- a/app/components/search_component.rb +++ b/app/components/search_component.rb @@ -13,6 +13,8 @@ class SearchComponent < ViewComponent::Base request.path elsif request.path.include?("organisations") && request.path.include?("logs") request.path + elsif request.path.include?("organisations") && request.path.include?("supported-housing") + request.path elsif request.path.include?("users") user_path(current_user) elsif request.path.include?("organisations") diff --git a/app/controllers/form_controller.rb b/app/controllers/form_controller.rb index 9fbb6fc63..5117ca6e2 100644 --- a/app/controllers/form_controller.rb +++ b/app/controllers/form_controller.rb @@ -13,6 +13,7 @@ class FormController < ApplicationController else redirect_path = "case_log_#{@page.id}_path" session[:errors] = @case_log.errors.to_json + Rails.logger.info "User triggered validation(s) on: #{@case_log.errors.map(&:attribute).join(', ')}" redirect_to(send(redirect_path, @case_log)) end else diff --git a/app/controllers/organisations_controller.rb b/app/controllers/organisations_controller.rb index d57f9b215..7a92e5811 100644 --- a/app/controllers/organisations_controller.rb +++ b/app/controllers/organisations_controller.rb @@ -16,6 +16,14 @@ class OrganisationsController < ApplicationController @total_count = all_organisations.size end + def schemes + all_schemes = Scheme.where(organisation: @organisation) + + @pagy, @schemes = pagy(filtered_collection(all_schemes, search_term)) + @searched = search_term.presence + @total_count = all_schemes.size + end + def show redirect_to details_organisation_path(@organisation) end diff --git a/app/controllers/schemes_controller.rb b/app/controllers/schemes_controller.rb new file mode 100644 index 000000000..d9dccab5d --- /dev/null +++ b/app/controllers/schemes_controller.rb @@ -0,0 +1,31 @@ +class SchemesController < ApplicationController + include Pagy::Backend + include Modules::SearchFilter + + before_action :authenticate_user! + before_action :authenticate_scope! + + def index + redirect_to supported_housing_organisation_path(current_user.organisation) unless current_user.support? + all_schemes = Scheme.all + + @pagy, @schemes = pagy(filtered_collection(all_schemes, search_term)) + @searched = search_term.presence + @total_count = all_schemes.size + end + + def show + @scheme = Scheme.find_by(id: params[:id]) + render_not_found and return unless (current_user.organisation == @scheme.organisation) || current_user.support? + end + +private + + def search_term + params["search"] + end + + def authenticate_scope! + head :unauthorized and return unless current_user.data_coordinator? || current_user.support? + end +end diff --git a/app/frontend/styles/_header.scss b/app/frontend/styles/_header.scss index 670aeb8e9..12cfd4e54 100644 --- a/app/frontend/styles/_header.scss +++ b/app/frontend/styles/_header.scss @@ -21,3 +21,8 @@ } } } + +.app-header--orange, +.app-header--orange .govuk-header__container { + border-bottom-color: govuk-colour("orange"); +} diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 3b1332b28..971dd68d9 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -9,6 +9,22 @@ module ApplicationHelper end end + def govuk_header_classes(current_user) + if current_user && current_user.support? + "app-header app-header--orange" + else + "app-header" + end + end + + def govuk_phase_banner_tag(current_user) + if current_user && current_user.support? + { colour: "orange", text: "Support beta" } + else + { text: "Beta" } + end + end + private def paginated_title(title, pagy) diff --git a/app/helpers/navigation_items_helper.rb b/app/helpers/navigation_items_helper.rb index 1ebf17d11..369428053 100644 --- a/app/helpers/navigation_items_helper.rb +++ b/app/helpers/navigation_items_helper.rb @@ -7,6 +7,14 @@ module NavigationItemsHelper NavigationItem.new("Organisations", organisations_path, organisations_current?(path)), NavigationItem.new("Users", "/users", users_current?(path)), NavigationItem.new("Logs", case_logs_path, logs_current?(path)), + NavigationItem.new("Supported housing", "/supported-housing", supported_housing_current?(path)), + ] + elsif current_user.data_coordinator? + [ + NavigationItem.new("Logs", case_logs_path, logs_current?(path)), + NavigationItem.new("Supported housing", "/supported-housing", subnav_supported_housing_path?(path)), + NavigationItem.new("Users", users_organisation_path(current_user.organisation), subnav_users_path?(path)), + NavigationItem.new("About your organisation", "/organisations/#{current_user.organisation.id}", subnav_details_path?(path)), ] else [ @@ -20,6 +28,7 @@ module NavigationItemsHelper def secondary_items(path, current_organisation_id) [ NavigationItem.new("Logs", "/organisations/#{current_organisation_id}/logs", subnav_logs_path?(path)), + NavigationItem.new("Supported housing", "/organisations/#{current_organisation_id}/supported-housing", subnav_supported_housing_path?(path)), NavigationItem.new("Users", "/organisations/#{current_organisation_id}/users", subnav_users_path?(path)), NavigationItem.new("About this organisation", "/organisations/#{current_organisation_id}", subnav_details_path?(path)), ] @@ -32,15 +41,23 @@ private end def users_current?(path) - path == "/users" + path == "/users" || path.include?("/users/") + end + + def supported_housing_current?(path) + path == "/supported-housing" || path.include?("/supported-housing/") end def organisations_current?(path) - path == "/organisations" || subnav_users_path?(path) || subnav_logs_path?(path) || subnav_details_path?(path) + path == "/organisations" || path.include?("/organisations/") + end + + def subnav_supported_housing_path?(path) + path.include?("/organisations") && path.include?("/supported-housing") || path.include?("/supported-housing/") end def subnav_users_path?(path) - path.include?("/organisations") && path.include?("/users") + (path.include?("/organisations") && path.include?("/users")) || path.include?("/users/") end def subnav_logs_path?(path) diff --git a/app/helpers/tab_nav_helper.rb b/app/helpers/tab_nav_helper.rb index 1157b83e6..bb163ddd8 100644 --- a/app/helpers/tab_nav_helper.rb +++ b/app/helpers/tab_nav_helper.rb @@ -6,6 +6,11 @@ module TabNavHelper [govuk_link_to(link_text, user), "User #{user.email}"].join("\n") end + def scheme_cell(scheme) + link_text = scheme.service_name.presence + [govuk_link_to(link_text, scheme), "Scheme #{scheme.primary_client_group_display}"].join("\n") + end + def org_cell(user) role = "#{user.role.to_s.humanize}" [user.organisation.name, role].join("\n") diff --git a/app/models/organisation.rb b/app/models/organisation.rb index 6f04c037a..0319befa4 100644 --- a/app/models/organisation.rb +++ b/app/models/organisation.rb @@ -4,6 +4,7 @@ class Organisation < ApplicationRecord has_many :managed_case_logs, class_name: "CaseLog", foreign_key: "managing_organisation_id" has_many :data_protection_confirmations has_many :organisation_rent_periods + has_many :schemes scope :search_by_name, ->(name) { where("name ILIKE ?", "%#{name}%") } scope :search_by, ->(param) { search_by_name(param) } diff --git a/app/models/scheme.rb b/app/models/scheme.rb new file mode 100644 index 000000000..096706018 --- /dev/null +++ b/app/models/scheme.rb @@ -0,0 +1,107 @@ +class Scheme < ApplicationRecord + belongs_to :organisation + + scope :search_by_code, ->(code) { where("code ILIKE ?", "%#{code}%") } + scope :search_by_service_name, ->(name) { where("service_name ILIKE ?", "%#{name}%") } + scope :search_by, ->(param) { search_by_code(param).or(search_by_service_name(param)) } + + SCHEME_TYPE = { + 0 => "Missings", + 4 => "Foyer", + 5 => "Direct Access Hostel", + 6 => "Other Supported Housing", + 7 => "Housing for older people", + }.freeze + + PRIMARY_CLIENT_GROUP = { + "O" => "Homeless families with support needs", + "H" => "Offenders & people at risk of offending", + "M" => "Older people with support needs", + "L" => "People at risk of domestic violence", + "A" => "People with a physical or sensory disability", + "G" => "People with alcohol problems", + "F" => "People with drug problems", + "B" => "People with HIV or AIDS", + "D" => "People with learning disabilities", + "E" => "People with mental health problems", + "I" => "Refugees (permanent)", + "S" => "Rough sleepers", + "N" => "Single homeless people with support needs", + "R" => "Teenage parents", + "Q" => "Young people at risk", + "P" => "Young people leaving care", + "X" => "Missing", + }.freeze + + SUPPORT_TYPE = { + 0 => "Missing", + 1 => "Resettlement Support", + 2 => "Low levels of support", + 3 => "Medium levels of support", + 4 => "High levels of care and support", + 5 => "Nursing care services to a care home", + 6 => "Floating Support", + }.freeze + + INTENDED_STAY = { + "M" => "Medium stay", + "P" => "Permanent", + "S" => "Short Stay", + "V" => "Very short stay", + "X" => "Missing", + }.freeze + + REGISTERED_UNDER_CARE_ACT = { + 0 => "No", + 1 => "Yes – part registered as a care home", + }.freeze + + SENSITIVE = { + 0 => "No", + 1 => "Yes", + }.freeze + + def display_attributes + [ + { name: "Service code", value: code }, + { name: "Name", value: service_name }, + { name: "Confidential information", value: sensitive_display }, + { name: "Managing agent", value: organisation.name }, + { name: "Type of service", value: scheme_type_display }, + { name: "Registered under Care Standards Act 2000", value: registered_under_care_act_display }, + { name: "Total number of units", value: total_units }, + { name: "Primary client group", value: primary_client_group_display }, + { name: "Secondary client group", value: secondary_client_group_display }, + { name: "Level of support given", value: support_type_display }, + { name: "Intended length of stay", value: intended_stay_display }, + ] + end + + def scheme_type_display + SCHEME_TYPE[scheme_type] + end + + def sensitive_display + SENSITIVE[sensitive] + end + + def registered_under_care_act_display + REGISTERED_UNDER_CARE_ACT[registered_under_care_act] + end + + def primary_client_group_display + PRIMARY_CLIENT_GROUP[primary_client_group] + end + + def secondary_client_group_display + PRIMARY_CLIENT_GROUP[secondary_client_group] + end + + def support_type_display + SUPPORT_TYPE[support_type] + end + + def intended_stay_display + INTENDED_STAY[intended_stay] + end +end diff --git a/app/views/case_logs/index.html.erb b/app/views/case_logs/index.html.erb index 583eac968..6d52d0060 100644 --- a/app/views/case_logs/index.html.erb +++ b/app/views/case_logs/index.html.erb @@ -14,7 +14,7 @@ <%= render partial: "log_filters" %>
<%= render SearchComponent.new(current_user:, search_label: "Search by log ID, tenant code, property reference or postcode", value: @searched) %> -
+ <%= govuk_section_break(visible: true, size: "m") %> <%= render partial: "log_list", locals: { case_logs: @case_logs, title: "Logs", pagy: @pagy, searched: @searched, item_label:, total_count: @total_count } %> <%== render partial: "pagy/nav", locals: { pagy: @pagy, item_name: "logs" } %>
diff --git a/app/views/form/page.html.erb b/app/views/form/page.html.erb index 999fd664f..ebbdd681b 100644 --- a/app/views/form/page.html.erb +++ b/app/views/form/page.html.erb @@ -31,7 +31,7 @@ <% @page.non_conditional_questions.map do |question| %>
> <% if question.read_only? %> -
+ <%= govuk_section_break(visible: true, size: "m") %> <% end %> <% if question.type == "interruption_screen" %> <%= render partial: "form/#{question.type}_question", locals: { question:, caption_text: @subsection.label, page_header: @page.header, case_log: @case_log, title_text: @page.title_text, informative_text: @page.informative_text, form: @form, f:, conditional: false } %> diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 7a3e85d89..e71f828be 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -43,7 +43,7 @@ <%= govuk_skip_link %> <%= govuk_header( - classes: "app-header", + classes: govuk_header_classes(current_user), service_url: current_user.nil? ? "/" : "/logs", navigation_classes: "govuk-header__navigation--end", ) do |component| @@ -60,7 +60,7 @@ <%= govuk_phase_banner( classes: "govuk-width-container", - tag: { text: "Beta" }, + tag: govuk_phase_banner_tag(current_user), text: "This is a new service – help us improve it by #{feedback_link}".html_safe, ) %> diff --git a/app/views/organisations/index.html.erb b/app/views/organisations/index.html.erb index 65f8134b7..967c2d0bf 100644 --- a/app/views/organisations/index.html.erb +++ b/app/views/organisations/index.html.erb @@ -13,7 +13,7 @@ <%= render SearchComponent.new(current_user:, search_label: "Search by organisation name", value: @searched) %> -
+<%= govuk_section_break(visible: true, size: "m") %> <%= render partial: "organisation_list", locals: { organisations: @organisations, title: "Organisations", pagy: @pagy, searched: @searched, item_label:, total_count: @total_count } %> <%== render partial: "pagy/nav", locals: { pagy: @pagy, item_name: "organisations" } %> diff --git a/app/views/organisations/logs.html.erb b/app/views/organisations/logs.html.erb index a12ef6a32..b4625d594 100644 --- a/app/views/organisations/logs.html.erb +++ b/app/views/organisations/logs.html.erb @@ -15,7 +15,7 @@ <%= render partial: "case_logs/log_filters" %>
<%= render SearchComponent.new(current_user:, search_label: "Search by log ID, tenant code, property reference or postcode", value: @searched) %> -
+ <%= govuk_section_break(visible: true, size: "m") %> <%= render partial: "case_logs/log_list", locals: { case_logs: @case_logs, title: "Logs", pagy: @pagy, searched: @searched, item_label:, total_count: @total_count } %> <%== render partial: "pagy/nav", locals: { pagy: @pagy, item_name: "logs" } %>
diff --git a/app/views/organisations/schemes.html.erb b/app/views/organisations/schemes.html.erb new file mode 100644 index 000000000..b28d9c306 --- /dev/null +++ b/app/views/organisations/schemes.html.erb @@ -0,0 +1,22 @@ +<% item_label = format_label(@pagy.count, "scheme") %> +<% title = format_title(@searched, "Supported housing services", current_user, item_label, @pagy.count, @organisation.name) %> + +<% content_for :title, title %> + +<%= render partial: "organisations/headings", locals: current_user.support? ? { main: @organisation.name, sub: nil } : { main: "Supported housing services", sub: current_user.organisation.name } %> + +<% if current_user.support? %> + <%= render SubNavigationComponent.new( + items: secondary_items(request.path, @organisation.id), + ) %> +<% end %> + +

Supported housing services

+ +<%= render SearchComponent.new(current_user:, search_label: "Search by service name or code", value: @searched) %> + +
+ +<%= render partial: "schemes/scheme_list", locals: { schemes: @schemes, title:, pagy: @pagy, searched: @searched, item_label:, total_count: @total_count } %> + +<%== render partial: "pagy/nav", locals: { pagy: @pagy, item_name: "schemes" } %> diff --git a/app/views/organisations/users.html.erb b/app/views/organisations/users.html.erb index d7a889b2e..e8dc383ed 100644 --- a/app/views/organisations/users.html.erb +++ b/app/views/organisations/users.html.erb @@ -17,7 +17,7 @@ <%= render SearchComponent.new(current_user:, search_label: "Search by name or email address", value: @searched) %> -
+<%= govuk_section_break(visible: true, size: "m") %> <%= render partial: "users/user_list", locals: { users: @users, title:, pagy: @pagy, searched: @searched, item_label:, total_count: @total_count } %> <%== render partial: "pagy/nav", locals: { pagy: @pagy, item_name: "users" } %> diff --git a/app/views/schemes/_scheme_list.html.erb b/app/views/schemes/_scheme_list.html.erb new file mode 100644 index 000000000..8d6ef7a72 --- /dev/null +++ b/app/views/schemes/_scheme_list.html.erb @@ -0,0 +1,39 @@ +
+ <%= govuk_table do |table| %> + <%= table.caption(classes: %w[govuk-!-font-size-19 govuk-!-font-weight-regular]) do |caption| %> + + <% if searched.present? %> + <%= pagy.count %> <%= item_label %> found matching ‘<%= searched %>’ of <%= total_count %> total schemes. <%= govuk_link_to("Clear search", request.path) %> + <% else %> + <%= pagy.count %> total schemes. + <% end %> + + <% end %> + <%= table.head do |head| %> + <%= head.row do |row| %> + <% row.cell(header: true, text: "Code", html_attributes: { + scope: "col", + }) %> + <% row.cell(header: true, text: "Service", html_attributes: { + scope: "col", + }) %> + <% row.cell(header: true, text: "Managing agent", html_attributes: { + scope: "col", + }) %> + <% row.cell(header: true, text: "Created", html_attributes: { + scope: "col", + }) %> + <% end %> + <% end %> + <% @schemes.each do |scheme| %> + <%= table.body do |body| %> + <%= body.row do |row| %> + <% row.cell(text: scheme.code) %> + <% row.cell(text: simple_format(scheme_cell(scheme), { class: "govuk-!-font-weight-bold" }, wrapper_tag: "div")) %> + <% row.cell(text: scheme.organisation.name) %> + <% row.cell(text: scheme.created_at.to_formatted_s(:govuk_date)) %> + <% end %> + <% end %> + <% end %> + <% end %> +
diff --git a/app/views/schemes/index.html.erb b/app/views/schemes/index.html.erb new file mode 100644 index 000000000..b96e7bdc3 --- /dev/null +++ b/app/views/schemes/index.html.erb @@ -0,0 +1,16 @@ +<% item_label = format_label(@pagy.count, "scheme") %> +<% title = format_title(@searched, "Supported housing services", current_user, item_label, @pagy.count, nil) %> + +<% content_for :title, title %> + +<%= render partial: "organisations/headings", locals: current_user.support? ? { main: "Supported housing services", sub: nil } : { main: "Supported housing services", sub: current_user.organisation.name } %> + +

Supported housing services

+ +<%= render SearchComponent.new(current_user:, search_label: "Search by service name or code", value: @searched) %> + +
+ +<%= render partial: "schemes/scheme_list", locals: { schemes: @schemes, title:, pagy: @pagy, searched: @searched, item_label:, total_count: @total_count } %> + +<%== render partial: "pagy/nav", locals: { pagy: @pagy, item_name: "schemes" } %> diff --git a/app/views/schemes/show.html.erb b/app/views/schemes/show.html.erb new file mode 100644 index 000000000..bb883d0e9 --- /dev/null +++ b/app/views/schemes/show.html.erb @@ -0,0 +1,17 @@ +<% title = @scheme.service_name %> +<% content_for :title, title %> + +<%= render partial: "organisations/headings", locals: { main: @scheme.service_name, sub: nil } %> + +
+
+ <%= govuk_summary_list do |summary_list| %> + <% @scheme.display_attributes.each do |attr| %> + <%= summary_list.row do |row| %> + <% row.key { attr[:name].to_s.humanize } %> + <% row.value { details_html(attr) } %> + <% end %> + <% end %> + <% end %> +
+
diff --git a/app/views/users/index.html.erb b/app/views/users/index.html.erb index 3444479c2..da05e2905 100644 --- a/app/views/users/index.html.erb +++ b/app/views/users/index.html.erb @@ -13,7 +13,7 @@ <%= render SearchComponent.new(current_user:, search_label: "Search by name or email address", value: @searched) %> -
+<%= govuk_section_break(visible: true, size: "m") %> <%= render partial: "users/user_list", locals: { users: @users, title:, pagy: @pagy, searched: @searched, item_label:, total_count: @total_count } %> <%== render partial: "pagy/nav", locals: { pagy: @pagy, item_name: "users" } %> diff --git a/config/routes.rb b/config/routes.rb index 4f7bc91e5..3e4492127 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -35,6 +35,8 @@ Rails.application.routes.draw do get "edit/password", to: "users#edit_password" end + resources :schemes, path: "/supported-housing", only: %i[index show] + resources :users do member do get "deactivate", to: "users#deactivate" @@ -48,6 +50,7 @@ Rails.application.routes.draw do get "users", to: "organisations#users" get "users/invite", to: "users/account#new" get "logs", to: "organisations#logs" + get "supported-housing", to: "organisations#schemes" end end diff --git a/db/migrate/20220608144156_create_schemes.rb b/db/migrate/20220608144156_create_schemes.rb new file mode 100644 index 000000000..2f96bc29f --- /dev/null +++ b/db/migrate/20220608144156_create_schemes.rb @@ -0,0 +1,11 @@ +class CreateSchemes < ActiveRecord::Migration[7.0] + def change + create_table :schemes do |t| + t.string :code + t.string :service_name + t.references :organisation, null: false, foreign_key: true + + t.timestamps + end + end +end diff --git a/db/migrate/20220613094847_add_missing_attributes_to_scheme.rb b/db/migrate/20220613094847_add_missing_attributes_to_scheme.rb new file mode 100644 index 000000000..ca0121d3d --- /dev/null +++ b/db/migrate/20220613094847_add_missing_attributes_to_scheme.rb @@ -0,0 +1,14 @@ +class AddMissingAttributesToScheme < ActiveRecord::Migration[7.0] + def change + change_table :schemes, bulk: true do |t| + t.string :primary_client_group + t.string :secondary_client_group + t.integer :sensitive + t.integer :total_units + t.integer :scheme_type + t.integer :registered_under_care_act + t.integer :support_type + t.string :intended_stay + end + end +end diff --git a/db/schema.rb b/db/schema.rb index f97623a7a..4e42ac3a6 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -191,9 +191,9 @@ ActiveRecord::Schema[7.0].define(version: 2022_06_13_123730) do t.integer "joint" t.bigint "created_by_id" t.integer "illness_type_0" + t.integer "retirement_value_check" t.integer "tshortfall_known" t.integer "sheltered" - t.integer "retirement_value_check" t.integer "pregnancy_value_check" t.integer "hhtype" t.integer "new_old" @@ -234,7 +234,7 @@ ActiveRecord::Schema[7.0].define(version: 2022_06_13_123730) do create_table "logs_exports", force: :cascade do |t| t.datetime "created_at", default: -> { "CURRENT_TIMESTAMP" } - t.datetime "started_at", precision: nil, null: false + t.datetime "started_at", null: false t.integer "base_number", default: 1, null: false t.integer "increment_number", default: 1, null: false t.boolean "empty_export", default: false, null: false @@ -279,6 +279,23 @@ ActiveRecord::Schema[7.0].define(version: 2022_06_13_123730) do t.index ["old_visible_id"], name: "index_organisations_on_old_visible_id", unique: true end + create_table "schemes", force: :cascade do |t| + t.string "code" + t.string "service_name" + t.bigint "organisation_id", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "primary_client_group" + t.string "secondary_client_group" + t.integer "sensitive" + t.integer "total_units" + t.integer "scheme_type" + t.integer "registered_under_care_act" + t.integer "support_type" + t.string "intended_stay" + t.index ["organisation_id"], name: "index_schemes_on_organisation_id" + end + create_table "users", force: :cascade do |t| t.string "email", default: "", null: false t.string "encrypted_password", default: "", null: false @@ -332,4 +349,5 @@ ActiveRecord::Schema[7.0].define(version: 2022_06_13_123730) do t.index ["item_type", "item_id"], name: "index_versions_on_item_type_and_item_id" end + add_foreign_key "schemes", "organisations" end diff --git a/db/seeds.rb b/db/seeds.rb index 54ffb843a..ad1fc1ac4 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -54,6 +54,69 @@ unless Rails.env.test? pp "Seeded 3 dummy users" end + if Rails.env.development? + dummy_org = Organisation.find_or_create_by!( + name: "FooBar LTD", + address_line1: "Higher Kingston", + address_line2: "Yeovil", + postcode: "BA21 4AT", + holds_own_stock: false, + other_stock_owners: "None", + managing_agents: "None", + provider_type: "LA", + ) + + pp "Seeded dummy FooBar LTD organisation" + end + + if Rails.env.development? && Scheme.count.zero? + Scheme.create!( + code: "S878", + service_name: "Beulahside Care", + sensitive: 0, + registered_under_care_act: 0, + support_type: 1, + scheme_type: 4, + total_units: 5, + intended_stay: "M", + primary_client_group: "O", + secondary_client_group: "H", + organisation: org, + created_at: Time.zone.now, + ) + + Scheme.create!( + code: "S312", + service_name: "Abdullahview Point", + sensitive: 0, + registered_under_care_act: 1, + support_type: 1, + scheme_type: 5, + total_units: 2, + intended_stay: "S", + primary_client_group: "D", + secondary_client_group: "E", + organisation: org, + created_at: Time.zone.now, + ) + + Scheme.create!( + code: "7XYZ", + service_name: "Caspermouth Center", + sensitive: 1, + registered_under_care_act: 1, + support_type: 4, + scheme_type: 7, + total_units: 7, + intended_stay: "X", + primary_client_group: "G", + secondary_client_group: "R", + organisation: dummy_org, + created_at: Time.zone.now, + ) + end + + pp "Seeded 3 dummy schemes" if LaRentRange.count.zero? Dir.glob("config/rent_range_data/*.csv").each do |path| start_year = File.basename(path, ".csv") diff --git a/package.json b/package.json index ef6f2bd7e..296b1c0c9 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,6 @@ "babel-loader": "^8.2.3", "babel-plugin-macros": "^3.1.0", "chart.js": "^3.6.0", - "chartkick": "^4.1.0", "copy-webpack-plugin": "^10.2.4", "core-js": "^3.21.1", "css-loader": "^6.7.1", diff --git a/spec/components/primary_navigation_component_spec.rb b/spec/components/primary_navigation_component_spec.rb index 0de1c58d1..9a3c91d09 100644 --- a/spec/components/primary_navigation_component_spec.rb +++ b/spec/components/primary_navigation_component_spec.rb @@ -6,6 +6,7 @@ RSpec.describe PrimaryNavigationComponent, type: :component do NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", true), NavigationItemsHelper::NavigationItem.new("Users", "/users", false), NavigationItemsHelper::NavigationItem.new("Logs ", "/logs", false), + NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", false), ] end @@ -24,6 +25,7 @@ RSpec.describe PrimaryNavigationComponent, type: :component do expect(navigation_panel).to be_highlighted_item(items[0], "/something-else") expect(navigation_panel).not_to be_highlighted_item(items[1], "/something-else") expect(navigation_panel).not_to be_highlighted_item(items[2], "/something-else") + expect(navigation_panel).not_to be_highlighted_item(items[3], "/something-else") end end @@ -34,6 +36,18 @@ RSpec.describe PrimaryNavigationComponent, type: :component do expect(result.text).to include("Organisations") expect(result.text).to include("Users") expect(result.text).to include("Logs") + expect(result.text).to include("Supported housing") + end + end + + context "when production environment" do + before do + allow(Rails.env).to receive(:production?).and_return(true) + end + + it "doesn't render supported housing" do + result = render_inline(described_class.new(items:)) + expect(result.text).not_to include("Supported housing") end end end diff --git a/spec/factories/scheme.rb b/spec/factories/scheme.rb new file mode 100644 index 000000000..6c3537146 --- /dev/null +++ b/spec/factories/scheme.rb @@ -0,0 +1,16 @@ +FactoryBot.define do + factory :scheme do + code { Faker::Name.initials(number: 4) } + service_name { Faker::Name.name_with_middle } + sensitive { Faker::Number.within(range: 0..1) } + registered_under_care_act { Faker::Number.within(range: 0..1) } + support_type { Faker::Number.within(range: 0..6) } + scheme_type { 0 } + total_units { Faker::Number.number(digits: 2) } + intended_stay { %w[M P S V X].sample } + primary_client_group { %w[O H M L A G F B D E I S N R Q P X].sample } + secondary_client_group { %w[O H M L A G F B D E I S N R Q P X].sample } + organisation + created_at { Time.zone.now } + end +end diff --git a/spec/features/schemes_spec.rb b/spec/features/schemes_spec.rb new file mode 100644 index 000000000..f772a24c8 --- /dev/null +++ b/spec/features/schemes_spec.rb @@ -0,0 +1,135 @@ +require "rails_helper" + +RSpec.describe "Supported housing scheme Features" do + context "when viewing list of schemes" do + context "when I am signed as a support user and there are schemes in the database" do + let(:user) { FactoryBot.create(:user, :support, last_sign_in_at: Time.zone.now) } + let!(:schemes) { FactoryBot.create_list(:scheme, 5) } + let!(:scheme_to_search) { FactoryBot.create(:scheme) } + let(:notify_client) { instance_double(Notifications::Client) } + let(:confirmation_token) { "MCDH5y6Km-U7CFPgAMVS" } + let(:devise_notify_mailer) { DeviseNotifyMailer.new } + let(:otp) { "999111" } + + before do + allow(DeviseNotifyMailer).to receive(:new).and_return(devise_notify_mailer) + allow(devise_notify_mailer).to receive(:notify_client).and_return(notify_client) + allow(Devise).to receive(:friendly_token).and_return(confirmation_token) + allow(notify_client).to receive(:send_email).and_return(true) + allow(SecureRandom).to receive(:random_number).and_return(otp) + visit("/logs") + fill_in("user[email]", with: user.email) + fill_in("user[password]", with: user.password) + click_button("Sign in") + fill_in("code", with: otp) + click_button("Submit") + end + + it "displays the link to the supported housing" do + expect(page).to have_link("Supported housing", href: "/supported-housing") + end + + context "when I click Supported housing" do + before do + click_link "Supported housing", href: "/supported-housing" + end + + it "shows list of schemes" do + schemes.each do |scheme| + expect(page).to have_content(scheme.code) + end + end + + context "when I search for a specific scheme" do + it "there is a search bar with a message and search button for schemes" do + expect(page).to have_field("search") + expect(page).to have_content("Search by service name or code") + expect(page).to have_button("Search") + end + + context "when I fill in search information and press the search button" do + before do + fill_in("search", with: scheme_to_search.code) + click_button("Search") + end + + it "displays scheme matching the scheme code" do + expect(page).to have_content(scheme_to_search.code) + end + + context "when I want to clear results" do + it "there is link to clear the search results" do + expect(page).to have_link("Clear search") + end + + it "displays all schemes after I clear the search results" do + click_link("Clear search") + expect(page).to have_content(scheme_to_search.code) + schemes.each do |scheme| + expect(page).to have_content(scheme.code) + end + end + end + end + end + end + end + end + + context "when viewing individual scheme" do + context "when I am signed as a support user and there are schemes in the database" do + let(:user) { FactoryBot.create(:user, :support, last_sign_in_at: Time.zone.now) } + let!(:schemes) { FactoryBot.create_list(:scheme, 5) } + let(:notify_client) { instance_double(Notifications::Client) } + let(:confirmation_token) { "MCDH5y6Km-U7CFPgAMVS" } + let(:devise_notify_mailer) { DeviseNotifyMailer.new } + let(:otp) { "999111" } + + before do + allow(DeviseNotifyMailer).to receive(:new).and_return(devise_notify_mailer) + allow(devise_notify_mailer).to receive(:notify_client).and_return(notify_client) + allow(Devise).to receive(:friendly_token).and_return(confirmation_token) + allow(notify_client).to receive(:send_email).and_return(true) + allow(SecureRandom).to receive(:random_number).and_return(otp) + visit("/logs") + fill_in("user[email]", with: user.email) + fill_in("user[password]", with: user.password) + click_button("Sign in") + fill_in("code", with: otp) + click_button("Submit") + end + + context "when I visit supported housing page" do + before do + visit("supported-housing") + end + + it "shows list of links to schemes" do + schemes.each do |scheme| + expect(page).to have_link(scheme.service_name) + expect(page).to have_content(scheme.primary_client_group_display) + end + end + + context "when I click to see individual scheme" do + before do + click_link(schemes.first.service_name) + end + + it "shows me details about the selected scheme" do + expect(page).to have_content(schemes.first.code) + expect(page).to have_content(schemes.first.service_name) + expect(page).to have_content(schemes.first.sensitive_display) + expect(page).to have_content(schemes.first.scheme_type_display) + expect(page).to have_content(schemes.first.registered_under_care_act_display) + expect(page).to have_content(schemes.first.total_units) + expect(page).to have_content(schemes.first.primary_client_group_display) + expect(page).to have_content(schemes.first.secondary_client_group_display) + expect(page).to have_content(schemes.first.support_type_display) + expect(page).to have_content(schemes.first.intended_stay_display) + end + end + end + end + end +end diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb index b5cde06ce..c0bb02fd2 100644 --- a/spec/helpers/application_helper_spec.rb +++ b/spec/helpers/application_helper_spec.rb @@ -6,6 +6,42 @@ RSpec.describe ApplicationHelper do let(:subsection) { form.get_subsection("household_characteristics") } let(:case_log) { FactoryBot.build(:case_log, :in_progress) } 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") + end + end + + context "with internal 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") + end + end + end + + describe "govuk_phase_banner_tag" do + context "with external user" do + it "shows the standard phase tag" do + expect(govuk_phase_banner_tag(current_user)).to eq({ text: "Beta" }) + end + end + + context "with support user" do + let(:current_user) { FactoryBot.create(:user, :support) } + + it "shows an orange phase tag" do + expect(govuk_phase_banner_tag(current_user)).to eq({ + colour: "orange", + text: "Support beta", + }) + end + end + end describe "browser_title" do context "with no pagination" do diff --git a/spec/helpers/navigation_items_helper_spec.rb b/spec/helpers/navigation_items_helper_spec.rb index 1bcf23f1a..52ad582c5 100644 --- a/spec/helpers/navigation_items_helper_spec.rb +++ b/spec/helpers/navigation_items_helper_spec.rb @@ -8,10 +8,26 @@ RSpec.describe NavigationItemsHelper do describe "#primary items" do context "when the user is a data coordinator" do + context "when the user is on the logs page" do + let(:expected_navigation_items) do + [ + NavigationItemsHelper::NavigationItem.new("Logs", "/logs", true), + NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", false), + NavigationItemsHelper::NavigationItem.new("Users", users_path, false), + NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, false), + ] + end + + it "returns navigation items with the users item set as current" do + expect(primary_items("/logs", current_user)).to eq(expected_navigation_items) + end + end + context "when the user is on the users page" do let(:expected_navigation_items) do [ NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false), + NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", false), NavigationItemsHelper::NavigationItem.new("Users", users_path, true), NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, false), ] @@ -26,6 +42,7 @@ RSpec.describe NavigationItemsHelper do let(:expected_navigation_items) do [ NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false), + NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", false), NavigationItemsHelper::NavigationItem.new("Users", users_path, false), NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, true), ] @@ -40,6 +57,7 @@ RSpec.describe NavigationItemsHelper do let(:expected_navigation_items) do [ NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false), + NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", false), NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false), NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, false), ] @@ -49,17 +67,63 @@ RSpec.describe NavigationItemsHelper do expect(primary_items("/account", current_user)).to eq(expected_navigation_items) end end + + context "when the user is on the individual user's page" do + let(:expected_navigation_items) do + [ + NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false), + NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", false), + NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", true), + NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, false), + ] + end + + it "returns navigation items with the users item set as current" do + expect(primary_items("/users/1", current_user)).to eq(expected_navigation_items) + end + end + + context "when the user is on the individual scheme's page" do + let(:expected_navigation_items) do + [ + NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false), + NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", true), + NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false), + NavigationItemsHelper::NavigationItem.new("About your organisation", organisation_path, false), + ] + end + + it "returns navigation items with supported housing item set as current" do + expect(primary_items("/supported-housing/1", current_user)).to eq(expected_navigation_items) + end + end end context "when the user is a support user" do let(:current_user) { FactoryBot.create(:user, :support) } + context "when the user is on the logs page" do + let(:expected_navigation_items) do + [ + NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false), + NavigationItemsHelper::NavigationItem.new("Users", "/users", false), + NavigationItemsHelper::NavigationItem.new("Logs", "/logs", true), + NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", false), + ] + end + + it "returns navigation items with the users item set as current" do + expect(primary_items("/logs", current_user)).to eq(expected_navigation_items) + end + end + context "when the user is on the users page" do let(:expected_navigation_items) do [ NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false), NavigationItemsHelper::NavigationItem.new("Users", "/users", true), NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false), + NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", false), ] end @@ -74,6 +138,7 @@ RSpec.describe NavigationItemsHelper do NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false), NavigationItemsHelper::NavigationItem.new("Users", "/users", false), NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false), + NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", false), ] end @@ -82,6 +147,51 @@ RSpec.describe NavigationItemsHelper do end end + context "when the user is on the supported housing page" do + let(:expected_navigation_items) do + [ + NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false), + NavigationItemsHelper::NavigationItem.new("Users", "/users", false), + NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false), + NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", true), + ] + end + + it "returns navigation items with the users item set as current" do + expect(primary_items("/supported-housing", current_user)).to eq(expected_navigation_items) + end + end + + context "when the user is on the individual user's page" do + let(:expected_navigation_items) do + [ + NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false), + NavigationItemsHelper::NavigationItem.new("Users", "/users", true), + NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false), + NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", false), + ] + end + + it "returns navigation items with the users item set as current" do + expect(primary_items("/users/1", current_user)).to eq(expected_navigation_items) + end + end + + context "when the user is on the individual scheme's page" do + let(:expected_navigation_items) do + [ + NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", false), + NavigationItemsHelper::NavigationItem.new("Users", "/users", false), + NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false), + NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", true), + ] + end + + it "returns navigation items with supported housing item set as current" do + expect(primary_items("/supported-housing/1", current_user)).to eq(expected_navigation_items) + end + end + context "when the user is on the specific organisation's page" do context "when the user is on organisation logs page" do let(:required_sub_path) { "logs" } @@ -90,12 +200,14 @@ RSpec.describe NavigationItemsHelper do NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", true), NavigationItemsHelper::NavigationItem.new("Users", "/users", false), NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false), + NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", false), ] end let(:expected_secondary_navigation_items) do [ NavigationItemsHelper::NavigationItem.new("Logs", "/organisations/#{current_user.organisation.id}/logs", true), + NavigationItemsHelper::NavigationItem.new("Supported housing", "/organisations/#{current_user.organisation.id}/supported-housing", false), NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false), NavigationItemsHelper::NavigationItem.new("About this organisation", "/organisations/#{current_user.organisation.id}", false), ] @@ -114,12 +226,14 @@ RSpec.describe NavigationItemsHelper do NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", true), NavigationItemsHelper::NavigationItem.new("Users", "/users", false), NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false), + NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", false), ] end let(:expected_secondary_navigation_items) do [ NavigationItemsHelper::NavigationItem.new("Logs", "/organisations/#{current_user.organisation.id}/logs", false), + NavigationItemsHelper::NavigationItem.new("Supported housing", "/organisations/#{current_user.organisation.id}/supported-housing", false), NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", true), NavigationItemsHelper::NavigationItem.new("About this organisation", "/organisations/#{current_user.organisation.id}", false), ] @@ -131,6 +245,32 @@ RSpec.describe NavigationItemsHelper do end end + context "when the user is on organisation schemes page" do + let(:required_sub_path) { "supported-housing" } + let(:expected_navigation_items) do + [ + NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", true), + NavigationItemsHelper::NavigationItem.new("Users", "/users", false), + NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false), + NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", false), + ] + end + + let(:expected_secondary_navigation_items) do + [ + NavigationItemsHelper::NavigationItem.new("Logs", "/organisations/#{current_user.organisation.id}/logs", false), + NavigationItemsHelper::NavigationItem.new("Supported housing", "/organisations/#{current_user.organisation.id}/supported-housing", true), + NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false), + NavigationItemsHelper::NavigationItem.new("About this organisation", "/organisations/#{current_user.organisation.id}", false), + ] + end + + it "returns navigation items with the schemes item set as current" do + expect(primary_items("/organisations/#{current_user.organisation.id}/#{required_sub_path}", current_user)).to eq(expected_navigation_items) + expect(secondary_items("/organisations/#{current_user.organisation.id}/#{required_sub_path}", current_user.organisation.id)).to eq(expected_secondary_navigation_items) + end + end + context "when the user is on organisation details page" do let(:required_sub_path) { "details" } let(:expected_navigation_items) do @@ -138,12 +278,14 @@ RSpec.describe NavigationItemsHelper do NavigationItemsHelper::NavigationItem.new("Organisations", "/organisations", true), NavigationItemsHelper::NavigationItem.new("Users", "/users", false), NavigationItemsHelper::NavigationItem.new("Logs", "/logs", false), + NavigationItemsHelper::NavigationItem.new("Supported housing", "/supported-housing", false), ] end let(:expected_secondary_navigation_items) do [ NavigationItemsHelper::NavigationItem.new("Logs", "/organisations/#{current_user.organisation.id}/logs", false), + NavigationItemsHelper::NavigationItem.new("Supported housing", "/organisations/#{current_user.organisation.id}/supported-housing", false), NavigationItemsHelper::NavigationItem.new("Users", "/organisations/#{current_user.organisation.id}/users", false), NavigationItemsHelper::NavigationItem.new("About this organisation", "/organisations/#{current_user.organisation.id}", true), ] diff --git a/spec/helpers/tab_nav_helper_spec.rb b/spec/helpers/tab_nav_helper_spec.rb index b59bb5d05..ba2dd3174 100644 --- a/spec/helpers/tab_nav_helper_spec.rb +++ b/spec/helpers/tab_nav_helper_spec.rb @@ -3,6 +3,7 @@ require "rails_helper" RSpec.describe TabNavHelper do let(:organisation) { FactoryBot.create(:organisation) } let(:user) { FactoryBot.build(:user, organisation:) } + let(:scheme) { FactoryBot.build(:scheme) } describe "#user_cell" do it "returns user link and email separated by a newline character" do @@ -18,6 +19,13 @@ RSpec.describe TabNavHelper do end end + describe "#scheme_cell" do + it "returns the scheme link service name and primary user group separated by a newline character" do + expected_html = "#{scheme.service_name}\nScheme #{scheme.primary_client_group_display}" + expect(scheme_cell(scheme)).to match(expected_html) + end + end + describe "#tab_items" do context "when user is a data_coordinator" do let(:user) { FactoryBot.build(:user, :data_coordinator, organisation:) } diff --git a/spec/helpers/tag_helper_spec.rb b/spec/helpers/tag_helper_spec.rb index bbdaeb8be..dd7ad664d 100644 --- a/spec/helpers/tag_helper_spec.rb +++ b/spec/helpers/tag_helper_spec.rb @@ -10,7 +10,7 @@ RSpec.describe TagHelper do end it "returns tag with correct status text and colour and custom class" do - expect(status_tag("not_started", "app-tag--small")).to eq("Not started") + expect(status_tag("not_started", "app-tag--small")).to eq("Not started") end end end diff --git a/spec/models/organisation_spec.rb b/spec/models/organisation_spec.rb index a524e1e85..17b8ec200 100644 --- a/spec/models/organisation_spec.rb +++ b/spec/models/organisation_spec.rb @@ -4,6 +4,7 @@ RSpec.describe Organisation, type: :model do describe "#new" do let(:user) { FactoryBot.create(:user) } let!(:organisation) { user.organisation } + let!(:scheme) { FactoryBot.create(:scheme, organisation:) } it "has expected fields" do expect(organisation.attribute_names).to include("name", "phone", "provider_type") @@ -13,6 +14,10 @@ RSpec.describe Organisation, type: :model do expect(organisation.users.first).to eq(user) end + it "has schemes" do + expect(organisation.schemes.first).to eq(scheme) + end + it "validates provider_type presence" do expect { FactoryBot.create(:organisation, provider_type: nil) } .to raise_error(ActiveRecord::RecordInvalid, "Validation failed: Provider type can’t be blank") diff --git a/spec/models/scheme_spec.rb b/spec/models/scheme_spec.rb new file mode 100644 index 000000000..bbeec6746 --- /dev/null +++ b/spec/models/scheme_spec.rb @@ -0,0 +1,49 @@ +require "rails_helper" + +RSpec.describe Scheme, type: :model do + describe "#new" do + let(:scheme) { FactoryBot.create(:scheme) } + + it "belongs to an organisation" do + expect(scheme.organisation).to be_a(Organisation) + end + + describe "scopes" do + let!(:scheme_1) { FactoryBot.create(:scheme) } + let!(:scheme_2) { FactoryBot.create(:scheme) } + + context "when searching by code" do + it "returns case insensitive matching records" do + expect(described_class.search_by_code(scheme_1.code.upcase).count).to eq(1) + expect(described_class.search_by_code(scheme_1.code.downcase).count).to eq(1) + expect(described_class.search_by_code(scheme_1.code.downcase).first.code).to eq(scheme_1.code) + expect(described_class.search_by_code(scheme_2.code.upcase).count).to eq(1) + expect(described_class.search_by_code(scheme_2.code.downcase).count).to eq(1) + expect(described_class.search_by_code(scheme_2.code.downcase).first.code).to eq(scheme_2.code) + end + end + + context "when searching by service name" do + it "returns case insensitive matching records" do + expect(described_class.search_by_service_name(scheme_1.service_name.upcase).count).to eq(1) + expect(described_class.search_by_service_name(scheme_1.service_name.downcase).count).to eq(1) + expect(described_class.search_by_service_name(scheme_1.service_name.downcase).first.service_name).to eq(scheme_1.service_name) + expect(described_class.search_by_service_name(scheme_2.service_name.upcase).count).to eq(1) + expect(described_class.search_by_service_name(scheme_2.service_name.downcase).count).to eq(1) + expect(described_class.search_by_service_name(scheme_2.service_name.downcase).first.service_name).to eq(scheme_2.service_name) + end + end + + context "when searching by all searchable field" do + it "returns case insensitive matching records" do + expect(described_class.search_by(scheme_1.code.upcase).count).to eq(1) + expect(described_class.search_by(scheme_1.code.downcase).count).to eq(1) + expect(described_class.search_by(scheme_1.code.downcase).first.code).to eq(scheme_1.code) + expect(described_class.search_by_service_name(scheme_2.service_name.upcase).count).to eq(1) + expect(described_class.search_by_service_name(scheme_2.service_name.downcase).count).to eq(1) + expect(described_class.search_by_service_name(scheme_2.service_name.downcase).first.service_name).to eq(scheme_2.service_name) + end + end + end + end +end diff --git a/spec/requests/form_controller_spec.rb b/spec/requests/form_controller_spec.rb index 27eea334f..fded09217 100644 --- a/spec/requests/form_controller_spec.rb +++ b/spec/requests/form_controller_spec.rb @@ -174,26 +174,33 @@ RSpec.describe FormController, type: :request do } end - before do - post "/logs/#{case_log.id}/form", params: - end - context "with invalid answers" do let(:page) { Capybara::Node::Simple.new(response.body) } let(:answer) { 2000 } let(:valid_answer) { 20 } + before do + allow(Rails.logger).to receive(:info) + end + it "re-renders the same page with errors if validation fails" do + post "/logs/#{case_log.id}/form", params: params expect(response).to redirect_to("/logs/#{case_log.id}/#{page_id.dasherize}") follow_redirect! expect(page).to have_content("There is a problem") end it "resets errors when fixed" do + post "/logs/#{case_log.id}/form", params: params post "/logs/#{case_log.id}/form", params: valid_params get "/logs/#{case_log.id}/#{page_id.dasherize}" expect(page).not_to have_content("There is a problem") end + + it "logs that validation was triggered" do + expect(Rails.logger).to receive(:info).with("User triggered validation(s) on: age1").once + post "/logs/#{case_log.id}/form", params: params + end end context "with valid answers" do @@ -209,6 +216,10 @@ RSpec.describe FormController, type: :request do } end + before do + post "/logs/#{case_log.id}/form", params: + end + it "re-renders the same page with errors if validation fails" do expect(response).to have_http_status(:redirect) end diff --git a/spec/requests/organisations_controller_spec.rb b/spec/requests/organisations_controller_spec.rb index 416ad8e37..b692d02b2 100644 --- a/spec/requests/organisations_controller_spec.rb +++ b/spec/requests/organisations_controller_spec.rb @@ -30,10 +30,141 @@ RSpec.describe OrganisationsController, type: :request do get "/organisations", headers: headers, params: {} expect(response).to redirect_to("/account/sign-in") end + + it "does not let you see supported housing list" do + get "/organisations/#{organisation.id}/supported-housing", headers: headers, params: {} + expect(response).to redirect_to("/account/sign-in") + end end end context "when user is signed in" do + describe "#schemes" do + context "when support user" do + let(:user) { FactoryBot.create(:user, :support) } + let!(:schemes) { FactoryBot.create_list(:scheme, 5) } + let!(:same_org_scheme) { FactoryBot.create(:scheme, organisation: user.organisation) } + + before do + allow(user).to receive(:need_two_factor_authentication?).and_return(false) + sign_in user + get "/organisations/#{organisation.id}/supported-housing", headers:, params: {} + end + + it "has page heading" do + expect(page).to have_content("Supported housing services") + end + + it "shows a search bar" do + expect(page).to have_field("search", type: "search") + end + + it "has hidden accebility field with description" do + expected_field = "

Supported housing services

" + expect(CGI.unescape_html(response.body)).to include(expected_field) + end + + it "shows only schemes belonging to the same organisation" do + expect(page).to have_content(same_org_scheme.code) + schemes.each do |scheme| + expect(page).not_to have_content(scheme.code) + end + end + + context "when searching" do + let!(:searched_scheme) { FactoryBot.create(:scheme, code: "CODE321", organisation: user.organisation) } + let(:search_param) { "CODE321" } + + before do + allow(user).to receive(:need_two_factor_authentication?).and_return(false) + get "/organisations/#{organisation.id}/supported-housing?search=#{search_param}" + end + + it "returns matching results" do + expect(page).to have_content(searched_scheme.code) + schemes.each do |scheme| + expect(page).not_to have_content(scheme.code) + end + end + + it "updates the table caption" do + expect(page).to have_content("1 scheme found matching ‘#{search_param}’") + end + + it "has search in the title" do + expect(page).to have_title("#{user.organisation.name} (1 scheme matching ‘#{search_param}’) - Submit social housing lettings and sales data (CORE) - GOV.UK") + end + end + end + + context "when data coordinator user" do + let(:user) { FactoryBot.create(:user, :data_coordinator) } + let!(:schemes) { FactoryBot.create_list(:scheme, 5) } + let!(:same_org_scheme) { FactoryBot.create(:scheme, organisation: user.organisation) } + + before do + sign_in user + get "/organisations/#{organisation.id}/supported-housing", headers:, params: {} + end + + it "has page heading" do + expect(page).to have_content("Supported housing services") + end + + it "shows a search bar" do + expect(page).to have_field("search", type: "search") + end + + it "has hidden accebility field with description" do + expected_field = "

Supported housing services

" + expect(CGI.unescape_html(response.body)).to include(expected_field) + end + + it "shows only schemes belonging to the same organisation" do + expect(page).to have_content(same_org_scheme.code) + schemes.each do |scheme| + expect(page).not_to have_content(scheme.code) + end + end + + context "with schemes that are not in scope for the user, i.e. that they do not belong to" do + let!(:unauthorised_organisation) { FactoryBot.create(:organisation) } + + before do + get "/organisations/#{unauthorised_organisation.id}/supported-housing", headers:, params: {} + end + + it "returns not found 404 from org details route" do + expect(response).to have_http_status(:not_found) + end + end + + context "when searching" do + let!(:searched_scheme) { FactoryBot.create(:scheme, code: "CODE321", organisation: user.organisation) } + let(:search_param) { "CODE321" } + + before do + get "/organisations/#{organisation.id}/supported-housing?search=#{search_param}" + end + + it "returns matching results" do + expect(page).to have_content(searched_scheme.code) + schemes.each do |scheme| + expect(page).not_to have_content(scheme.code) + end + end + + it "updates the table caption" do + expect(page).to have_content("1 scheme found matching ‘#{search_param}’") + end + + it "has search in the title" do + expect(page).to have_title("Supported housing services (1 scheme matching ‘#{search_param}’) - Submit social housing lettings and sales data (CORE) - GOV.UK") + end + end + end + end + describe "#show" do context "with an organisation that the user belongs to" do before do @@ -572,10 +703,10 @@ RSpec.describe OrganisationsController, type: :request do it "shows only logs matching both search and filters" do get "/organisations/#{organisation.id}/logs?search=#{matching_postcode}&status[]=#{matching_status}", headers: headers, params: {} - expect(page).to have_content(log_matching_filter_and_search.id) - expect(page).not_to have_content(log_to_search.id) + expect(page).to have_link(log_matching_filter_and_search.id.to_s) + expect(page).not_to have_link(log_to_search.id.to_s) logs.each do |log| - expect(page).not_to have_content(log.id) + expect(page).not_to have_link(log.id.to_s) end end end diff --git a/spec/requests/schemes_controller_spec.rb b/spec/requests/schemes_controller_spec.rb new file mode 100644 index 000000000..4d5c248d5 --- /dev/null +++ b/spec/requests/schemes_controller_spec.rb @@ -0,0 +1,249 @@ +require "rails_helper" + +RSpec.describe SchemesController, type: :request do + let(:organisation) { user.organisation } + let(:headers) { { "Accept" => "text/html" } } + let(:page) { Capybara::Node::Simple.new(response.body) } + let(:user) { FactoryBot.create(:user, :support) } + let!(:schemes) { FactoryBot.create_list(:scheme, 5) } + + describe "#index" do + context "when not signed in" do + it "redirects to the sign in page" do + get "/supported-housing" + expect(response).to redirect_to("/account/sign-in") + end + end + + context "when signed in as a data provider user" do + let(:user) { FactoryBot.create(:user) } + + before do + sign_in user + get "/supported-housing" + end + + it "returns 401 unauthorized" do + request + expect(response).to have_http_status(:unauthorized) + end + end + + context "when signed in as a data coordinator user" do + let(:user) { FactoryBot.create(:user, :data_coordinator) } + + before do + sign_in user + get "/supported-housing" + end + + it "redirects to the organisation schemes path" do + follow_redirect! + expect(path).to match("/organisations/#{user.organisation.id}/supported-housing") + end + end + + context "when signed in as a support user" do + before do + allow(user).to receive(:need_two_factor_authentication?).and_return(false) + sign_in user + get "/supported-housing" + end + + it "has page heading" do + expect(page).to have_content("Supported housing services") + end + + it "shows all schemes" do + schemes.each do |scheme| + expect(page).to have_content(scheme.code) + end + end + + it "shows a search bar" do + expect(page).to have_field("search", type: "search") + end + + it "has correct title" do + expect(page).to have_title("Supported housing services - Submit social housing lettings and sales data (CORE) - GOV.UK") + end + + it "shows the total organisations count" do + expect(CGI.unescape_html(response.body)).to match("#{schemes.count} total schemes.") + end + + it "has hidden accebility field with description" do + expected_field = "

Supported housing services

" + expect(CGI.unescape_html(response.body)).to include(expected_field) + end + + context "when paginating over 20 results" do + let(:total_schemes_count) { Scheme.count } + + before do + FactoryBot.create_list(:scheme, 20) + end + + context "when on the first page" do + before do + get "/supported-housing" + end + + it "shows the total schemes count" do + expect(CGI.unescape_html(response.body)).to match("#{total_schemes_count} total schemes.") + end + + it "shows which schemes are being shown on the current page" do + expect(CGI.unescape_html(response.body)).to match("Showing 1 to 20 of #{total_schemes_count} schemes") + end + + it "has correct page 1 of 2 title" do + expect(page).to have_title("Supported housing services (page 1 of 2) - Submit social housing lettings and sales data (CORE) - GOV.UK") + end + + it "has pagination links" do + expect(page).to have_content("Previous") + expect(page).not_to have_link("Previous") + expect(page).to have_content("Next") + expect(page).to have_link("Next") + end + end + + context "when on the second page" do + before do + get "/supported-housing?page=2" + end + + it "shows the total schemes count" do + expect(CGI.unescape_html(response.body)).to match("#{total_schemes_count} total schemes.") + end + + it "has pagination links" do + expect(page).to have_content("Previous") + expect(page).to have_link("Previous") + expect(page).to have_content("Next") + expect(page).not_to have_link("Next") + end + + it "shows which schemes are being shown on the current page" do + expect(CGI.unescape_html(response.body)).to match("Showing 21 to 25 of #{total_schemes_count} schemes") + end + + it "has correct page 1 of 2 title" do + expect(page).to have_title("Supported housing services (page 2 of 2) - Submit social housing lettings and sales data (CORE) - GOV.UK") + end + end + end + + context "when searching" do + let!(:searched_scheme) { FactoryBot.create(:scheme, code: "CODE321") } + let(:search_param) { "CODE321" } + + before do + get "/supported-housing?search=#{search_param}" + end + + it "returns matching results" do + expect(page).to have_content(searched_scheme.code) + schemes.each do |scheme| + expect(page).not_to have_content(scheme.code) + end + end + + it "updates the table caption" do + expect(page).to have_content("1 scheme found matching ‘#{search_param}’") + end + + it "has search in the title" do + expect(page).to have_title("Supported housing services (1 scheme matching ‘#{search_param}’) - Submit social housing lettings and sales data (CORE) - GOV.UK") + end + end + end + end + + describe "#show" do + let(:specific_scheme) { schemes.first } + + context "when not signed in" do + it "redirects to the sign in page" do + get "/supported-housing/#{specific_scheme.id}" + expect(response).to redirect_to("/account/sign-in") + end + end + + context "when signed in as a data provider user" do + let(:user) { FactoryBot.create(:user) } + + before do + sign_in user + get "/supported-housing/#{specific_scheme.id}" + end + + it "returns 401 unauthorized" do + request + expect(response).to have_http_status(:unauthorized) + end + end + + context "when signed in as a data coordinator user" do + let(:user) { FactoryBot.create(:user, :data_coordinator) } + let!(:specific_scheme) { FactoryBot.create(:scheme, organisation: user.organisation) } + + before do + sign_in user + end + + it "has page heading" do + get "/supported-housing/#{specific_scheme.id}" + expect(page).to have_content(specific_scheme.code) + expect(page).to have_content(specific_scheme.service_name) + expect(page).to have_content(specific_scheme.organisation.name) + expect(page).to have_content(specific_scheme.sensitive_display) + expect(page).to have_content(specific_scheme.code) + expect(page).to have_content(specific_scheme.service_name) + expect(page).to have_content(specific_scheme.sensitive_display) + expect(page).to have_content(specific_scheme.scheme_type_display) + expect(page).to have_content(specific_scheme.registered_under_care_act_display) + expect(page).to have_content(specific_scheme.total_units) + expect(page).to have_content(specific_scheme.primary_client_group_display) + expect(page).to have_content(specific_scheme.secondary_client_group_display) + expect(page).to have_content(specific_scheme.support_type_display) + expect(page).to have_content(specific_scheme.intended_stay_display) + end + + context "when coordinator attempts to see scheme belogning to a different organisation" do + let!(:specific_scheme) { FactoryBot.create(:scheme) } + + it "returns 404 not found" do + get "/supported-housing/#{specific_scheme.id}" + expect(response).to have_http_status(:not_found) + end + end + end + + context "when signed in as a support user" do + before do + allow(user).to receive(:need_two_factor_authentication?).and_return(false) + sign_in user + get "/supported-housing/#{specific_scheme.id}" + end + + it "has page heading" do + expect(page).to have_content(specific_scheme.code) + expect(page).to have_content(specific_scheme.service_name) + expect(page).to have_content(specific_scheme.organisation.name) + expect(page).to have_content(specific_scheme.sensitive_display) + expect(page).to have_content(specific_scheme.code) + expect(page).to have_content(specific_scheme.service_name) + expect(page).to have_content(specific_scheme.sensitive_display) + expect(page).to have_content(specific_scheme.scheme_type_display) + expect(page).to have_content(specific_scheme.registered_under_care_act_display) + expect(page).to have_content(specific_scheme.total_units) + expect(page).to have_content(specific_scheme.primary_client_group_display) + expect(page).to have_content(specific_scheme.secondary_client_group_display) + expect(page).to have_content(specific_scheme.support_type_display) + expect(page).to have_content(specific_scheme.intended_stay_display) + end + end + end +end diff --git a/yarn.lock b/yarn.lock index 3cbc753f7..9e9c09845 100644 --- a/yarn.lock +++ b/yarn.lock @@ -18,14 +18,14 @@ "@babel/highlight" "^7.16.7" "@babel/compat-data@^7.13.11", "@babel/compat-data@^7.17.10": - version "7.17.10" - resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.17.10.tgz#711dc726a492dfc8be8220028b1b92482362baab" - integrity sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw== + version "7.18.5" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.5.tgz#acac0c839e317038c73137fbb6ef71a1d6238471" + integrity sha512-BxhE40PVCBxVEJsSBhB6UWyAuqJRxGsAw8BdHMJ3AKGydcwuWW4kOO3HmqBQAdcq/OP+/DlTVxLvsCzRTnZuGg== "@babel/core@^7.17.7": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.2.tgz#87b2fcd7cce9becaa7f5acebdc4f09f3dd19d876" - integrity sha512-A8pri1YJiC5UnkdrWcmfZTJTV85b4UXTAfImGmCfYmax4TR9Cw8sDS0MOk++Gp2mE/BefVJ5nwy5yzqNJbP/DQ== + version "7.18.5" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.5.tgz#c597fa680e58d571c28dda9827669c78cdd7f000" + integrity sha512-MGY8vg3DxMnctw0LdvSEojOsumc70g0t18gNyUdAZqB1Rpd1Bqo/svHGvt+UJ6JcGX+DIekGFDxxIWofBxLCnQ== dependencies: "@ampproject/remapping" "^2.1.0" "@babel/code-frame" "^7.16.7" @@ -33,10 +33,10 @@ "@babel/helper-compilation-targets" "^7.18.2" "@babel/helper-module-transforms" "^7.18.0" "@babel/helpers" "^7.18.2" - "@babel/parser" "^7.18.0" + "@babel/parser" "^7.18.5" "@babel/template" "^7.16.7" - "@babel/traverse" "^7.18.2" - "@babel/types" "^7.18.2" + "@babel/traverse" "^7.18.5" + "@babel/types" "^7.18.4" convert-source-map "^1.7.0" debug "^4.1.0" gensync "^1.0.0-beta.2" @@ -188,7 +188,7 @@ "@babel/helper-wrap-function" "^7.16.8" "@babel/types" "^7.16.8" -"@babel/helper-replace-supers@^7.16.7": +"@babel/helper-replace-supers@^7.16.7", "@babel/helper-replace-supers@^7.18.2": version "7.18.2" resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.18.2.tgz#41fdfcc9abaf900e18ba6e5931816d9062a7b2e0" integrity sha512-XzAIyxx+vFnrOxiQrToSUOzUOn0e1J2Li40ntddek1Y69AXUTXoDJ40/D5RdjFu7s7qHiaeoTiempZcbuVXh2Q== @@ -258,10 +258,10 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/parser@^7.16.7", "@babel/parser@^7.18.0": - version "7.18.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.3.tgz#39e99c7b0c4c56cef4d1eed8de9f506411c2ebc2" - integrity sha512-rL50YcEuHbbauAFAysNsJA4/f89fGTOBRNs9P81sniKnKAr4xULe5AecolcsKbi88xu0ByWYDj/S1AJ3FSFuSQ== +"@babel/parser@^7.16.7", "@babel/parser@^7.18.5": + version "7.18.5" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.5.tgz#337062363436a893a2d22faa60be5bb37091c83c" + integrity sha512-YZWVaglMiplo7v8f1oMQ5ZPQr0vn7HPeZXxXWsxXJRjGVrzUFn9OxFQl1sb5wzfootjA/yChhW84BV+383FSOw== "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.17.12": version "7.17.12" @@ -536,23 +536,23 @@ "@babel/helper-plugin-utils" "^7.16.7" "@babel/plugin-transform-block-scoping@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.17.12.tgz#68fc3c4b3bb7dfd809d97b7ed19a584052a2725c" - integrity sha512-jw8XW/B1i7Lqwqj2CbrViPcZijSxfguBWZP2aN59NHgxUyO/OcO1mfdCxH13QhN5LbWhPkX+f+brKGhZTiqtZQ== + version "7.18.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.18.4.tgz#7988627b3e9186a13e4d7735dc9c34a056613fb9" + integrity sha512-+Hq10ye+jlvLEogSOtq4mKvtk7qwcUQ1f0Mrueai866C82f844Yom2cttfJdMdqRLTxWpsbfbkIkOIfovyUQXw== dependencies: "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-transform-classes@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.17.12.tgz#da889e89a4d38375eeb24985218edeab93af4f29" - integrity sha512-cvO7lc7pZat6BsvH6l/EGaI8zpl8paICaoGk+7x7guvtfak/TbIf66nYmJOH13EuG0H+Xx3M+9LQDtSvZFKXKw== + version "7.18.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.18.4.tgz#51310b812a090b846c784e47087fa6457baef814" + integrity sha512-e42NSG2mlKWgxKUAD9EJJSkZxR67+wZqzNxLSpc51T8tRU5SLFHsPmgYR5yr7sdgX4u+iHA1C5VafJ6AyImV3A== dependencies: "@babel/helper-annotate-as-pure" "^7.16.7" - "@babel/helper-environment-visitor" "^7.16.7" + "@babel/helper-environment-visitor" "^7.18.2" "@babel/helper-function-name" "^7.17.9" "@babel/helper-optimise-call-expression" "^7.16.7" "@babel/helper-plugin-utils" "^7.17.12" - "@babel/helper-replace-supers" "^7.16.7" + "@babel/helper-replace-supers" "^7.18.2" "@babel/helper-split-export-declaration" "^7.16.7" globals "^11.1.0" @@ -643,9 +643,9 @@ babel-plugin-dynamic-import-node "^2.3.3" "@babel/plugin-transform-modules-systemjs@^7.18.0": - version "7.18.0" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.18.0.tgz#50ecdb43de97c8483824402f7125edb94cddb09a" - integrity sha512-vwKpxdHnlM5tIrRt/eA0bzfbi7gUBLN08vLu38np1nZevlPySRe6yvuATJB5F/WPJ+ur4OXwpVYq9+BsxqAQuQ== + version "7.18.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.18.5.tgz#87f11c44fbfd3657be000d4897e192d9cb535996" + integrity sha512-SEewrhPpcqMF1V7DhnEbhVJLrC+nnYfe1E0piZMZXBpxi9WvZqWGwpsk7JYP7wPWeqaBh4gyKlBhHJu3uz5g4Q== dependencies: "@babel/helper-hoist-variables" "^7.16.7" "@babel/helper-module-transforms" "^7.18.0" @@ -670,9 +670,9 @@ "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-transform-new-target@^7.17.12": - version "7.17.12" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.17.12.tgz#10842cd605a620944e81ea6060e9e65c265742e3" - integrity sha512-CaOtzk2fDYisbjAD4Sd1MTKGVIpRtx9bWLyj24Y/k6p4s4gQ3CqDGJauFJxt8M/LEx003d0i3klVqnN73qvK3w== + version "7.18.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.18.5.tgz#8c228c4a07501dd12c95c5f23d1622131cc23931" + integrity sha512-TuRL5uGW4KXU6OsRj+mLp9BM7pO8e7SGNTEokQRRxHFkXYMFiy2jlKSZPFtI/mKORDzciH+hneskcSOp0gU8hg== dependencies: "@babel/helper-plugin-utils" "^7.17.12" @@ -714,9 +714,9 @@ "@babel/helper-plugin-utils" "^7.17.12" "@babel/plugin-transform-runtime@^7.17.0": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.2.tgz#04637de1e45ae8847ff14b9beead09c33d34374d" - integrity sha512-mr1ufuRMfS52ttq+1G1PD8OJNqgcTFjq3hwn8SZ5n1x1pBhi0E36rYMdTK0TsKtApJ4lDEdfXJwtGobQMHSMPg== + version "7.18.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.18.5.tgz#f4d3188ba6a8815793993c71c2c225d0ee1d7743" + integrity sha512-Q17hHxXr2fplrE+5BSC1j1Fo5cOA8YeP8XW3/1paI8MzF/faZGh0MaH1KC4jLAvqLPamQWHB5/B7KqSLY1kuHA== dependencies: "@babel/helper-module-imports" "^7.16.7" "@babel/helper-plugin-utils" "^7.17.12" @@ -884,10 +884,10 @@ "@babel/parser" "^7.16.7" "@babel/types" "^7.16.7" -"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.8", "@babel/traverse@^7.18.0", "@babel/traverse@^7.18.2": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.2.tgz#b77a52604b5cc836a9e1e08dca01cba67a12d2e8" - integrity sha512-9eNwoeovJ6KH9zcCNnENY7DMFwTU9JdGCFtqNLfUAqtUHRCOsTOqWoffosP8vKmNYeSBUv3yVJXjfd8ucwOjUA== +"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.8", "@babel/traverse@^7.18.0", "@babel/traverse@^7.18.2", "@babel/traverse@^7.18.5": + version "7.18.5" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.5.tgz#94a8195ad9642801837988ab77f36e992d9a20cd" + integrity sha512-aKXj1KT66sBj0vVzk6rEeAO6Z9aiiQ68wfDgge3nHhA/my6xMM/7HGQUNumKZaoa2qUPQ5whJG9aAifsxUKfLA== dependencies: "@babel/code-frame" "^7.16.7" "@babel/generator" "^7.18.2" @@ -895,19 +895,24 @@ "@babel/helper-function-name" "^7.17.9" "@babel/helper-hoist-variables" "^7.16.7" "@babel/helper-split-export-declaration" "^7.16.7" - "@babel/parser" "^7.18.0" - "@babel/types" "^7.18.2" + "@babel/parser" "^7.18.5" + "@babel/types" "^7.18.4" debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.17.0", "@babel/types@^7.18.0", "@babel/types@^7.18.2", "@babel/types@^7.4.4": - version "7.18.2" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.2.tgz#191abfed79ebe6f4242f643a9a5cbaa36b10b091" - integrity sha512-0On6B8A4/+mFUto5WERt3EEuG1NznDirvwca1O8UwXQHVY8g3R7OzYgxXdOfMwLO08UrpUD/2+3Bclyq+/C94Q== +"@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.16.8", "@babel/types@^7.17.0", "@babel/types@^7.18.0", "@babel/types@^7.18.2", "@babel/types@^7.18.4", "@babel/types@^7.4.4": + version "7.18.4" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.4.tgz#27eae9b9fd18e9dccc3f9d6ad051336f307be354" + integrity sha512-ThN1mBcMq5pG/Vm2IcBmPPfyPXbd8S02rS+OBIDENdufvqC7Z/jHPCv9IcP01277aKtDI8g/2XysBN4hA8niiw== dependencies: "@babel/helper-validator-identifier" "^7.16.7" to-fast-properties "^2.0.0" +"@csstools/selector-specificity@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@csstools/selector-specificity/-/selector-specificity-2.0.1.tgz#b6b8d81780b9a9f6459f4bfe9226ac6aefaefe87" + integrity sha512-aG20vknL4/YjQF9BSV7ts4EWm/yrjagAN7OWBNmlbEOUiu0llj4OGrFoOKK3g2vey4/p2omKCoHrWtPxSwV3HA== + "@discoveryjs/json-ext@^0.5.0": version "0.5.7" resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" @@ -945,12 +950,20 @@ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.1.tgz#36a6acc93987adcf0ba50c66908bd0b70de8afea" integrity sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ== +"@jridgewell/source-map@^0.3.2": + version "0.3.2" + resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb" + integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + "@jridgewell/sourcemap-codec@^1.4.10": version "1.4.13" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz#b6461fb0c2964356c469e115f504c95ad97ab88c" integrity sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w== -"@jridgewell/trace-mapping@^0.3.9": +"@jridgewell/trace-mapping@^0.3.7", "@jridgewell/trace-mapping@^0.3.9": version "0.3.13" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz#dcfe3e95f224c8fe97a87a5235defec999aa92ea" integrity sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w== @@ -998,9 +1011,9 @@ "@types/estree" "*" "@types/eslint@*": - version "8.4.2" - resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.2.tgz#48f2ac58ab9c631cb68845c3d956b28f79fad575" - integrity sha512-Z1nseZON+GEnFjJc04sv4NSALGjhFwy6K0HXt7qsn5ArfAKtb63dXNJHf+1YW6IpOIYRBGUbu3GwJdj8DGnCjA== + version "8.4.3" + resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-8.4.3.tgz#5c92815a3838b1985c90034cd85f26f59d9d0ece" + integrity sha512-YP1S7YJRMPs+7KZKDb9G63n8YejIwW9BALq7a5j2+H4yl6iOv9CB29edho+cuFRrvmJbbaH2yiVChKLJVysDGw== dependencies: "@types/estree" "*" "@types/json-schema" "*" @@ -1021,9 +1034,9 @@ integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== "@types/node@*": - version "17.0.35" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.35.tgz#635b7586086d51fb40de0a2ec9d1014a5283ba4a" - integrity sha512-vu1SrqBjbbZ3J6vwY17jBs8Sr/BKA+/a/WtjRG+whKg1iuLFOosq872EXS0eXWILdO36DHQQeku/ZcL6hz2fpg== + version "17.0.42" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.42.tgz#d7e8f22700efc94d125103075c074396b5f41f9b" + integrity sha512-Q5BPGyGKcvQgAMbsr7qEGN/kIPN6zZecYYABeTDBizOsau+2NMdSVTar9UQw21A2+JyA2KRNDYaYrPB0Rpk2oQ== "@types/normalize-package-data@^2.4.0": version "2.4.1" @@ -1161,22 +1174,22 @@ resolved "https://registry.yarnpkg.com/@webcomponents/webcomponentsjs/-/webcomponentsjs-2.6.0.tgz#7d1674c40bddf0c6dd974c44ffd34512fe7274ff" integrity sha512-Moog+Smx3ORTbWwuPqoclr+uvfLnciVd6wdCaVscHPrxbmQ/IJKm3wbB7hpzJtXWjAq2l/6QMlO85aZiOdtv5Q== -"@webpack-cli/configtest@^1.1.1": - version "1.1.1" - resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.1.1.tgz#9f53b1b7946a6efc2a749095a4f450e2932e8356" - integrity sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg== +"@webpack-cli/configtest@^1.2.0": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.2.0.tgz#7b20ce1c12533912c3b217ea68262365fa29a6f5" + integrity sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg== -"@webpack-cli/info@^1.4.1": - version "1.4.1" - resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.4.1.tgz#2360ea1710cbbb97ff156a3f0f24556e0fc1ebea" - integrity sha512-PKVGmazEq3oAo46Q63tpMr4HipI3OPfP7LiNOEJg963RMgT0rqheag28NCML0o3GIzA3DmxP1ZIAv9oTX1CUIA== +"@webpack-cli/info@^1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.5.0.tgz#6c78c13c5874852d6e2dd17f08a41f3fe4c261b1" + integrity sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ== dependencies: envinfo "^7.7.3" -"@webpack-cli/serve@^1.6.1": - version "1.6.1" - resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.6.1.tgz#0de2875ac31b46b6c5bb1ae0a7d7f0ba5678dffe" - integrity sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw== +"@webpack-cli/serve@^1.7.0": + version "1.7.0" + resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.7.0.tgz#e1993689ac42d2b16e9194376cfb6753f6254db1" + integrity sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q== "@xtuc/ieee754@^1.2.0": version "1.2.0" @@ -1401,15 +1414,15 @@ braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" -browserslist@^4.14.5, browserslist@^4.20.2, browserslist@^4.20.3: - version "4.20.3" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.3.tgz#eb7572f49ec430e054f56d52ff0ebe9be915f8bf" - integrity sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg== +browserslist@^4.14.5, browserslist@^4.20.2, browserslist@^4.20.4: + version "4.20.4" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.20.4.tgz#98096c9042af689ee1e0271333dbc564b8ce4477" + integrity sha512-ok1d+1WpnU24XYN7oC3QWgTyMhY/avPJ/r9T00xxvUOIparA/gc+UPUMaod3i+G6s+nI2nUb9xZ5k794uIwShw== dependencies: - caniuse-lite "^1.0.30001332" - electron-to-chromium "^1.4.118" + caniuse-lite "^1.0.30001349" + electron-to-chromium "^1.4.147" escalade "^3.1.1" - node-releases "^2.0.3" + node-releases "^2.0.5" picocolors "^1.0.0" buffer-from@^1.0.0: @@ -1444,10 +1457,10 @@ camelcase@^5.3.1: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== -caniuse-lite@^1.0.30001332: - version "1.0.30001343" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001343.tgz#8e1107e30d9a4d2f63782b48ae0a3ce34e2f9c2a" - integrity sha512-8KeCrAtPMabo/XW14B+R9sZYoClx1n0b+WYgwDKZPtWR3TcdvWzdSy7mPyFEmR5WU1St9v1PW6sdO5dkFOEzfA== +caniuse-lite@^1.0.30001349: + version "1.0.30001352" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001352.tgz#cc6f5da3f983979ad1e2cdbae0505dccaa7c6a12" + integrity sha512-GUgH8w6YergqPQDGWhJGt8GDRnY0L/iJVQcU3eJ46GYf52R8tk0Wxp0PymuFVZboJYXGiCqwozAYZNRjVj6IcA== chalk@^2.0.0: version "2.4.2" @@ -1458,25 +1471,11 @@ chalk@^2.0.0: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chart.js@>=3.0.2, chart.js@^3.6.0: +chart.js@^3.6.0: version "3.8.0" resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-3.8.0.tgz#c6c14c457b9dc3ce7f1514a59e9b262afd6f1a94" integrity sha512-cr8xhrXjLIXVLOBZPkBZVF6NDeiVIrPLHcMhnON7UufudL+CNeRrD+wpYanswlm8NpudMdrt3CHoLMQMxJhHRg== -chartjs-adapter-date-fns@>=2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/chartjs-adapter-date-fns/-/chartjs-adapter-date-fns-2.0.0.tgz#5e53b2f660b993698f936f509c86dddf9ed44c6b" - integrity sha512-rmZINGLe+9IiiEB0kb57vH3UugAtYw33anRiw5kS2Tu87agpetDDoouquycWc9pRsKtQo5j+vLsYHyr8etAvFw== - -chartkick@^4.1.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/chartkick/-/chartkick-4.2.0.tgz#106fc5ff7eef5343a9e6977f259a8a8a1ea57bf9" - integrity sha512-7yYZyxeFhOh/LA7gc1VwDFgc6t4ZM9RrbBjgb4dJoFukk2+94QkK0yulYI2OUH1cjcfrf1qmj04FkjZx7kZDeg== - optionalDependencies: - chart.js ">=3.0.2" - chartjs-adapter-date-fns ">=2.0.0" - date-fns ">=2.0.0" - "chokidar@>=3.0.0 <4.0.0": version "3.5.3" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" @@ -1543,9 +1542,9 @@ colord@^2.9.2: integrity sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ== colorette@^2.0.14: - version "2.0.16" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.16.tgz#713b9af84fdb000139f04546bd4a93f62a5085da" - integrity sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g== + version "2.0.18" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.18.tgz#4c260bcf86437ce94fa58e2e49a83b623f3c4d66" + integrity sha512-rHDY1i4V4JBCXHnHwaVyA202CKSj2kUrjI5cSJQbTdnFeI4ShV3e19Fe7EQfzL2tjSrvYyWugdGAtEc1lLvGDg== commander@^2.19.0, commander@^2.20.0: version "2.20.3" @@ -1565,7 +1564,7 @@ commondir@^1.0.1: concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== convert-source-map@^1.7.0: version "1.8.0" @@ -1587,17 +1586,17 @@ copy-webpack-plugin@^10.2.4: serialize-javascript "^6.0.0" core-js-compat@^3.21.0, core-js-compat@^3.22.1: - version "3.22.7" - resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.22.7.tgz#8359eb66ecbf726dd0cfced8e48d5e73f3224239" - integrity sha512-uI9DAQKKiiE/mclIC5g4AjRpio27g+VMRhe6rQoz+q4Wm4L6A/fJhiLtBw+sfOpDG9wZ3O0pxIw7GbfOlBgjOA== + version "3.23.0" + resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.23.0.tgz#324191a23bfbd229802718dcc1d213414b244624" + integrity sha512-i4FgbtahOArZBEteiL+czI5N/bp17w16bXmLagGThdA2zuX1a5X4HbBmOVD7ERRtk3wMtPOFEmlXpVV4lsvwNw== dependencies: - browserslist "^4.20.3" + browserslist "^4.20.4" semver "7.0.0" core-js@^3.21.1, core-js@^3.4.0: - version "3.22.7" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.22.7.tgz#8d6c37f630f6139b8732d10f2c114c3f1d00024f" - integrity sha512-Jt8SReuDKVNZnZEzyEQT5eK6T2RRCXkfTq7Lo09kpm+fHjgGewSbNjV+Wt4yZMhPDdzz2x1ulI5z/w4nxpBseg== + version "3.23.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.23.0.tgz#9e33448c8fd3b02ad023d85bd6e85da6335b5cc4" + integrity sha512-v2/hZoRcRrvQiBoGsHwmRdr+S4oICKcjA6xb2qjVurin6TpcDC1X2CIDa8rdu/d5n8RT/Sdoos2IlnpQ1rXs5A== cosmiconfig@^7.0.0, cosmiconfig@^7.0.1: version "7.0.1" @@ -1619,10 +1618,10 @@ cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" -css-functions-list@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/css-functions-list/-/css-functions-list-3.0.1.tgz#1460df7fb584d1692c30b105151dbb988c8094f9" - integrity sha512-PriDuifDt4u4rkDgnqRCLnjfMatufLmWNfQnGCq34xZwpY3oabwhB9SqRBmuvWUgndbemCFlKqg+nO7C2q0SBw== +css-functions-list@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/css-functions-list/-/css-functions-list-3.1.0.tgz#cf5b09f835ad91a00e5959bcfc627cd498e1321b" + integrity sha512-/9lCvYZaUbBGvYUgYGFJ4dcYiyqdhSjG7IPVluoV8A1ILjkF7ilmhp1OGUz8n+nmBcu0RNrQAzgD8B6FJbrt2w== css-loader@^6.7.1: version "6.7.1" @@ -1648,11 +1647,6 @@ custom-event-polyfill@^1.0.7: resolved "https://registry.yarnpkg.com/custom-event-polyfill/-/custom-event-polyfill-1.0.7.tgz#9bc993ddda937c1a30ccd335614c6c58c4f87aee" integrity sha512-TDDkd5DkaZxZFM8p+1I3yAlvM3rSr1wbrOliG4yJiwinMZN8z/iGL7BTlDkrJcYTmgUSb4ywVCc3ZaUtOtC76w== -date-fns@>=2.0.0: - version "2.28.0" - resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.28.0.tgz#9570d656f5fc13143e50c975a3b6bbeb46cd08b2" - integrity sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw== - debug@^4.1.0, debug@^4.1.1, debug@^4.3.4: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" @@ -1663,7 +1657,7 @@ debug@^4.1.0, debug@^4.1.1, debug@^4.3.4: decamelize-keys@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" - integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk= + integrity sha512-ocLWuYzRPoS9bfiSdDd3cxvrzovVMZnRDVEzAs+hWIVXGDbHxWMECij2OBuyB/An0FFW/nLuq6Kv1i/YC5Qfzg== dependencies: decamelize "^1.1.0" map-obj "^1.0.0" @@ -1671,7 +1665,7 @@ decamelize-keys@^1.1.0: decamelize@^1.1.0, decamelize@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" - integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= + integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== define-properties@^1.1.3: version "1.1.4" @@ -1688,15 +1682,15 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" -electron-to-chromium@^1.4.118: - version "1.4.139" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.139.tgz#e634b69769ab4a54626bbd9e1475de872839c89a" - integrity sha512-lYxzcUCjWxxVug+A7UxBCUiVr13TCjfZFYJS9Lq1VpU/ErwV4a6zUQo9dfojuGpw/L/x9REGuBl6ICQPGgbs3g== +electron-to-chromium@^1.4.147: + version "1.4.154" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.154.tgz#d69c60499fc467a6c59591d29183e520afbc78a1" + integrity sha512-GbV9djOkrnj6xmW+YYVVEI3VCQnJ0pnSTu7TW2JyjKd5cakoiSaG5R4RbEtfaD92GsY10DzbU3GYRe+IOA9kqA== element-closest@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/element-closest/-/element-closest-2.0.2.tgz#72a740a107453382e28df9ce5dbb5a8df0f966ec" - integrity sha1-cqdAoQdFM4LijfnOXbtajfD5Zuw= + integrity sha512-QCqAWP3kwj8Gz9UXncVXQGdrhnWxD8SQBSeZp5pOsyCcQ6RpL738L1/tfuwBiMi6F1fYkxqPnBrFBR4L+f49Cg== emoji-regex@^8.0.0: version "8.0.0" @@ -1741,7 +1735,7 @@ escalade@^3.1.1: escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== eslint-scope@5.1.1: version "5.1.1" @@ -1788,21 +1782,6 @@ eventslibjs@^1.2.0: resolved "https://registry.yarnpkg.com/eventslibjs/-/eventslibjs-1.2.0.tgz#5d242b1d71d7376b999611448e91b7947d8cb9d0" integrity sha512-nui7FHXHeeZjWkQ1dZ4R3RchkT+164+y1/puiOY1Zc3CPU9W8XzAzdhqvuVQ4EJt7F/W94O5U26/oVFpBOPY3w== -execa@^5.0.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" - integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.0" - human-signals "^2.1.0" - is-stream "^2.0.0" - merge-stream "^2.0.0" - npm-run-path "^4.0.1" - onetime "^5.1.2" - signal-exit "^3.0.3" - strip-final-newline "^2.0.0" - execall@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/execall/-/execall-2.0.0.tgz#16a06b5fe5099df7d00be5d9c06eecded1663b45" @@ -1898,7 +1877,7 @@ flatted@^3.1.0: fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== fsevents@~2.3.2: version "2.3.2" @@ -1916,24 +1895,19 @@ gensync@^1.0.0-beta.2: integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== get-intrinsic@^1.0.2, get-intrinsic@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.1.tgz#15f59f376f855c446963948f0d24cd3637b4abc6" - integrity sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q== + version "1.1.2" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.1.2.tgz#336975123e05ad0b7ba41f152ee4aadbea6cf598" + integrity sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA== dependencies: function-bind "^1.1.1" has "^1.0.3" - has-symbols "^1.0.1" + has-symbols "^1.0.3" get-stdin@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53" integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg== -get-stream@^6.0.0: - version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" - integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== - glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" @@ -2013,7 +1987,7 @@ globby@^12.0.2: globjoin@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/globjoin/-/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43" - integrity sha1-L0SUrIkZ43Z8XLtpHp9GMyQoXUM= + integrity sha512-xYfnw62CKG8nLkZBfWbhWwDw02CHty86jfPcc2cr3ZfeuK9ysoVPPEUxf21bAD/rWAgk52SuBrLJlefNy8mvFg== govuk-frontend@^4.0.1: version "4.0.1" @@ -2043,7 +2017,7 @@ hard-rejection@^2.1.0: has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== has-flag@^4.0.0: version "4.0.0" @@ -2057,7 +2031,7 @@ has-property-descriptors@^1.0.0: dependencies: get-intrinsic "^1.1.1" -has-symbols@^1.0.1: +has-symbols@^1.0.1, has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== @@ -2089,12 +2063,7 @@ html-tags@^3.2.0: html5shiv@^3.7.3: version "3.7.3" resolved "https://registry.yarnpkg.com/html5shiv/-/html5shiv-3.7.3.tgz#d78a84a367bcb9a710100d57802c387b084631d2" - integrity sha1-14qEo2e8uacQEA1XgCw4ewhGMdI= - -human-signals@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" - integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + integrity sha512-SZwGvLGNtgp8GbgFX7oXEp8OR1aBt5LliX6dG0kdD1kl3KhMonN0QcSa/A3TsTgFewaGCbIryQunjayWDXzxmw== icss-utils@^5.0.0, icss-utils@^5.1.0: version "5.1.0" @@ -2135,7 +2104,7 @@ import-local@^3.0.2: imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" - integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== indent-string@^4.0.0: version "4.0.0" @@ -2145,7 +2114,7 @@ indent-string@^4.0.0: inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== dependencies: once "^1.3.0" wrappy "1" @@ -2173,7 +2142,7 @@ intersection-observer@^0.12.0: is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" - integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== is-binary-path@~2.1.0: version "2.1.0" @@ -2192,7 +2161,7 @@ is-core-module@^2.5.0, is-core-module@^2.8.1: is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== is-fullwidth-code-point@^3.0.0: version "3.0.0" @@ -2214,7 +2183,7 @@ is-number@^7.0.0: is-plain-obj@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= + integrity sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg== is-plain-object@^2.0.4: version "2.0.4" @@ -2233,20 +2202,15 @@ is-regexp@^2.0.0: resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-2.1.0.tgz#cd734a56864e23b956bf4e7c66c396a4c0b22c2d" integrity sha512-OZ4IlER3zmRIoB9AqNhEggVxqIH4ofDns5nRrPS6yQxXE1TPCUpFznBfRQmQa8uC+pXqjMnukiJBxCisIxiLGA== -is-stream@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" - integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== - isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== isobject@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" - integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= + integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== jest-worker@^27.4.5: version "27.5.1" @@ -2270,7 +2234,7 @@ jsesc@^2.5.1: jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" - integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0= + integrity sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA== json-parse-even-better-errors@^2.3.0, json-parse-even-better-errors@^2.3.1: version "2.3.1" @@ -2336,17 +2300,12 @@ locate-path@^5.0.0: lodash.debounce@^4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" - integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= - -lodash.sortby@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" - integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= + integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== lodash.truncate@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" - integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= + integrity sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw== lodash@^4.17.21: version "4.17.21" @@ -2370,7 +2329,7 @@ make-dir@^3.0.2, make-dir@^3.1.0: map-obj@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" - integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= + integrity sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg== map-obj@^4.0.0: version "4.3.0" @@ -2430,11 +2389,6 @@ mime-types@^2.1.27: dependencies: mime-db "1.52.0" -mimic-fn@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" - integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== - min-indent@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" @@ -2483,7 +2437,7 @@ neo-async@^2.6.2: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== -node-releases@^2.0.3: +node-releases@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.5.tgz#280ed5bc3eba0d96ce44897d8aee478bfb3d9666" integrity sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q== @@ -2513,13 +2467,6 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== -npm-run-path@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" - integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== - dependencies: - path-key "^3.0.0" - object-keys@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" @@ -2538,17 +2485,10 @@ object.assign@^4.1.0: once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" -onetime@^5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" - integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== - dependencies: - mimic-fn "^2.1.0" - p-limit@^2.2.0: version "2.3.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" @@ -2593,9 +2533,9 @@ path-exists@^4.0.0: path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== -path-key@^3.0.0, path-key@^3.1.0: +path-key@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== @@ -2630,7 +2570,7 @@ pkg-dir@^4.1.0, pkg-dir@^4.2.0: postcss-media-query-parser@^0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz#27b39c6f4d94f81b1a73b8f76351c609e5cef244" - integrity sha1-J7Ocb02U+Bsac7j3Y1HGCeXO8kQ= + integrity sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig== postcss-modules-extract-imports@^3.0.0: version "3.0.0" @@ -2663,7 +2603,7 @@ postcss-modules-values@^4.0.0: postcss-resolve-nested-selector@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz#29ccbc7c37dedfac304e9fff0bf1596b3f6a0e4e" - integrity sha1-Kcy8fDfe36wwTp//C/FZaz9qDk4= + integrity sha512-HvExULSwLqHLgUy1rl3ANIqCsvMS0WHss2UOsXhXnQaZ9VCc2oBvIpXrl00IUFT5ZDITME0o6oiXeiHr2SAIfw== postcss-safe-parser@^6.0.0: version "6.0.0" @@ -2882,9 +2822,9 @@ sass-loader@^12.6.0: neo-async "^2.6.2" sass@^1.49.9: - version "1.52.1" - resolved "https://registry.yarnpkg.com/sass/-/sass-1.52.1.tgz#554693da808543031f9423911d62c60a1acf7889" - integrity sha512-fSzYTbr7z8oQnVJ3Acp9hV80dM1fkMN7mSD/25mpcct9F7FPBMOI8krEYALgU1aZoqGhQNhTPsuSmxjnIvAm4Q== + version "1.52.3" + resolved "https://registry.yarnpkg.com/sass/-/sass-1.52.3.tgz#b7cc7ffea2341ccc9a0c4fd372bf1b3f9be1b6cb" + integrity sha512-LNNPJ9lafx+j1ArtA7GyEJm9eawXN8KlA1+5dF6IZyoONg1Tyo/g+muOsENWJH/2Q1FHbbV4UwliU0cXMa/VIA== dependencies: chokidar ">=3.0.0 <4.0.0" immutable "^4.0.0" @@ -2966,7 +2906,7 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== -signal-exit@^3.0.3, signal-exit@^3.0.7: +signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== @@ -3003,18 +2943,11 @@ source-map-support@~0.5.20: buffer-from "^1.0.0" source-map "^0.6.0" -source-map@^0.6.0, source-map@^0.6.1: +source-map@^0.6.0: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== -source-map@~0.8.0-beta.0: - version "0.8.0-beta.0" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.8.0-beta.0.tgz#d4c1bb42c3f7ee925f005927ba10709e0d1d1f11" - integrity sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA== - dependencies: - whatwg-url "^7.0.0" - spdx-correct@^3.0.0: version "3.1.1" resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" @@ -3041,11 +2974,6 @@ spdx-license-ids@^3.0.0: resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz#50c0d8c40a14ec1bf449bae69a0ea4685a9d9f95" integrity sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g== -specificity@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/specificity/-/specificity-0.4.1.tgz#aab5e645012db08ba182e151165738d00887b019" - integrity sha512-1klA3Gi5PD1Wv9Q0wUoOQN1IWAuPu0D1U03ThXTr0cJ20+/iq2tHSDnK7Kk/0LXJ1ztUB2/1Os0wKmfyNgUQfg== - string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -3062,11 +2990,6 @@ strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" -strip-final-newline@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" - integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== - strip-indent@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" @@ -3077,7 +3000,7 @@ strip-indent@^3.0.0: style-search@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902" - integrity sha1-eVjHk+R+MuB9K1yv5cC/jhLneQI= + integrity sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg== stylelint-config-gds@^0.2.0: version "0.2.0" @@ -3140,14 +3063,15 @@ stylelint-scss@^4.0.0: postcss-value-parser "^4.1.0" stylelint@^14.7.1: - version "14.8.5" - resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-14.8.5.tgz#0fcbf5b6821283b5a249dde36d70f1158da0a2a3" - integrity sha512-e3t4H/hlWlspkcNUrkhf44RU3OpPTA7uBOoREGBzSwdEF+2g/+gbZq7WEpMP7BpopcSe/uLaTvDuL+URL7cdnQ== + version "14.9.1" + resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-14.9.1.tgz#6494ed38f148b1e75b402d678a3b6a8aae86dfda" + integrity sha512-RdAkJdPiLqHawCSnu21nE27MjNXaVd4WcOHA4vK5GtIGjScfhNnaOuWR2wWdfKFAvcWQPOYe311iveiVKSmwsA== dependencies: + "@csstools/selector-specificity" "^2.0.1" balanced-match "^2.0.0" colord "^2.9.2" cosmiconfig "^7.0.1" - css-functions-list "^3.0.1" + css-functions-list "^3.1.0" debug "^4.3.4" execall "^2.0.0" fast-glob "^3.2.11" @@ -3175,7 +3099,6 @@ stylelint@^14.7.1: postcss-selector-parser "^6.0.10" postcss-value-parser "^4.2.0" resolve-from "^5.0.0" - specificity "^0.4.1" string-width "^4.2.3" strip-ansi "^6.0.1" style-search "^0.1.0" @@ -3222,7 +3145,7 @@ supports-preserve-symlinks-flag@^1.0.0: svg-tags@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" - integrity sha1-WPcc7jvVGbWdSyqEO2x95krAR2Q= + integrity sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA== table@^6.8.0: version "6.8.0" @@ -3241,30 +3164,30 @@ tapable@^2.1.1, tapable@^2.2.0: integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== terser-webpack-plugin@^5.1.3: - version "5.3.1" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz#0320dcc270ad5372c1e8993fabbd927929773e54" - integrity sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g== + version "5.3.3" + resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.3.3.tgz#8033db876dd5875487213e87c627bca323e5ed90" + integrity sha512-Fx60G5HNYknNTNQnzQ1VePRuu89ZVYWfjRAeT5rITuCY/1b08s49e5kSQwHDirKZWuoKOBRFS98EUUoZ9kLEwQ== dependencies: + "@jridgewell/trace-mapping" "^0.3.7" jest-worker "^27.4.5" schema-utils "^3.1.1" serialize-javascript "^6.0.0" - source-map "^0.6.1" terser "^5.7.2" terser@^5.7.2: - version "5.13.1" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.13.1.tgz#66332cdc5a01b04a224c9fad449fc1a18eaa1799" - integrity sha512-hn4WKOfwnwbYfe48NgrQjqNOH9jzLqRcIfbYytOXCOv46LBfWr9bDS17MQqOi+BWGD0sJK3Sj5NC/gJjiojaoA== + version "5.14.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.14.1.tgz#7c95eec36436cb11cf1902cc79ac564741d19eca" + integrity sha512-+ahUAE+iheqBTDxXhTisdA8hgvbEG1hHOQ9xmNjeUJSoi6DU/gMrKNcfZjHkyY6Alnuyc+ikYJaxxfHkT3+WuQ== dependencies: + "@jridgewell/source-map" "^0.3.2" acorn "^8.5.0" commander "^2.20.0" - source-map "~0.8.0-beta.0" source-map-support "~0.5.20" to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" - integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== to-regex-range@^5.0.1: version "5.0.1" @@ -3273,13 +3196,6 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -tr46@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" - integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= - dependencies: - punycode "^2.1.0" - trim-newlines@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" @@ -3338,7 +3254,7 @@ uri-js@^4.2.2: util-deprecate@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" - integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== v8-compile-cache@^2.3.0: version "2.3.0" @@ -3354,30 +3270,25 @@ validate-npm-package-license@^3.0.1: spdx-expression-parse "^3.0.0" watchpack@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.3.1.tgz#4200d9447b401156eeca7767ee610f8809bc9d25" - integrity sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA== + version "2.4.0" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.4.0.tgz#fa33032374962c78113f93c7f2fb4c54c9862a5d" + integrity sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg== dependencies: glob-to-regexp "^0.4.1" graceful-fs "^4.1.2" -webidl-conversions@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" - integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== - webpack-cli@^4.9.2: - version "4.9.2" - resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.9.2.tgz#77c1adaea020c3f9e2db8aad8ea78d235c83659d" - integrity sha512-m3/AACnBBzK/kMTcxWHcZFPrw/eQuY4Df1TxvIWfWM2x7mRqBQCqKEd96oCUa9jkapLBaFfRce33eGDb4Pr7YQ== + version "4.10.0" + resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.10.0.tgz#37c1d69c8d85214c5a65e589378f53aec64dab31" + integrity sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w== dependencies: "@discoveryjs/json-ext" "^0.5.0" - "@webpack-cli/configtest" "^1.1.1" - "@webpack-cli/info" "^1.4.1" - "@webpack-cli/serve" "^1.6.1" + "@webpack-cli/configtest" "^1.2.0" + "@webpack-cli/info" "^1.5.0" + "@webpack-cli/serve" "^1.7.0" colorette "^2.0.14" commander "^7.0.0" - execa "^5.0.0" + cross-spawn "^7.0.3" fastest-levenshtein "^1.0.12" import-local "^3.0.2" interpret "^2.2.0" @@ -3405,9 +3316,9 @@ webpack-sources@^3.2.3: integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w== webpack@^5.70.0: - version "5.72.1" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.72.1.tgz#3500fc834b4e9ba573b9f430b2c0a61e1bb57d13" - integrity sha512-dXG5zXCLspQR4krZVR6QgajnZOjW2K/djHvdcRaDQvsjV9z9vaW6+ja5dZOYbqBBjF6kGXka/2ZyxNdc+8Jung== + version "5.73.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.73.0.tgz#bbd17738f8a53ee5760ea2f59dce7f3431d35d38" + integrity sha512-svjudQRPPa0YiOYa2lM/Gacw0r6PvxptHj4FuEKQ2kX05ZLkjbVc5MnPs6its5j7IZljnIqSVo/OsY2X0IpHGA== dependencies: "@types/eslint-scope" "^3.7.3" "@types/estree" "^0.0.51" @@ -3434,15 +3345,6 @@ webpack@^5.70.0: watchpack "^2.3.1" webpack-sources "^3.2.3" -whatwg-url@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" - integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg== - dependencies: - lodash.sortby "^4.7.0" - tr46 "^1.0.1" - webidl-conversions "^4.0.2" - which@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" @@ -3465,7 +3367,7 @@ wildcard@^2.0.0: wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== write-file-atomic@^4.0.1: version "4.0.1"