diff --git a/CHANGELOG.md b/CHANGELOG.md index ac990c776b..ca4c5f0c8a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ useful summary for people upgrading their application, not a replication of the commit log. +## Unreleased + +* Use the first organisation to generate breadcrumbs, if no parent linked ([PR #4270](https://github.com/alphagov/govuk_publishing_components/pull/4270)) + ## 44.7.0 * Contents list add margin_bottom option ([PR #4333](https://github.com/alphagov/govuk_publishing_components/pull/4333)) diff --git a/app/views/govuk_publishing_components/components/docs/contextual_breadcrumbs.yml b/app/views/govuk_publishing_components/components/docs/contextual_breadcrumbs.yml index 7045bc65ff..bc96261b1f 100644 --- a/app/views/govuk_publishing_components/components/docs/contextual_breadcrumbs.yml +++ b/app/views/govuk_publishing_components/components/docs/contextual_breadcrumbs.yml @@ -4,11 +4,12 @@ body: | This is a complex component that calls other components. For more accurate preview with real data, see the [contextual navigation preview][preview]. - There are 3 main variants of the component: + There are 4 main variants of the component: - Step by step, which uses the [step by step header][header] - Parent breadcrumb, which uses the `parent` link of the page with the [breadcrumbs component][breadcrumbs] - Taxon breadcrumb, which uses the `taxons` link of the page with the [breadcrumbs component][breadcrumbs] + - Organisation breadcrumb, which uses the `organisations` link of the page with the [breadcrumbs component][breadcrumbs] It must always used [together with the contextual sidebar][sidebar] and [footer]. diff --git a/lib/govuk_publishing_components.rb b/lib/govuk_publishing_components.rb index 2f0cb6c4b0..55e6ab342b 100644 --- a/lib/govuk_publishing_components.rb +++ b/lib/govuk_publishing_components.rb @@ -24,6 +24,7 @@ require "govuk_publishing_components/presenters/page_with_step_by_step_navigation" require "govuk_publishing_components/presenters/public_layout_helper" require "govuk_publishing_components/presenters/content_breadcrumbs_based_on_ancestors" +require "govuk_publishing_components/presenters/content_breadcrumbs_based_on_organisations" require "govuk_publishing_components/presenters/content_breadcrumbs_based_on_taxons" require "govuk_publishing_components/presenters/checkboxes_helper" require "govuk_publishing_components/presenters/select_helper" diff --git a/lib/govuk_publishing_components/presenters/breadcrumb_selector.rb b/lib/govuk_publishing_components/presenters/breadcrumb_selector.rb index e301df2e35..f4594034d4 100644 --- a/lib/govuk_publishing_components/presenters/breadcrumb_selector.rb +++ b/lib/govuk_publishing_components/presenters/breadcrumb_selector.rb @@ -55,6 +55,11 @@ def options(navigation) step_by_step: false, breadcrumbs: navigation.breadcrumbs, } + elsif navigation.content_is_a_corporate_information_page? && navigation.content_has_related_organisations? + { + step_by_step: false, + breadcrumbs: navigation.organisation_breadcrumbs, + } elsif navigation.use_taxon_breadcrumbs? { step_by_step: false, diff --git a/lib/govuk_publishing_components/presenters/content_breadcrumbs_based_on_organisations.rb b/lib/govuk_publishing_components/presenters/content_breadcrumbs_based_on_organisations.rb new file mode 100644 index 0000000000..a03f308400 --- /dev/null +++ b/lib/govuk_publishing_components/presenters/content_breadcrumbs_based_on_organisations.rb @@ -0,0 +1,36 @@ +module GovukPublishingComponents + module Presenters + # @private + class ContentBreadcrumbsBasedOnOrganisations + def self.call(content_item) + new(content_item).breadcrumbs + end + + def initialize(content_item) + @content_item = ContentItem.new(content_item) + end + + def breadcrumbs + [ + { title: "Home", url: "/" }, + { title: "Organisations", url: "/government/organisations" }, + *organisation_breadcrumbs_items, + ] + end + + private + + attr_reader :content_item + + def organisation_breadcrumbs_items + first_related_organisation = ContentItem.new(content_item.related_organisations.first) + return [] unless first_related_organisation.present? + + [{ + title: first_related_organisation.title, + url: first_related_organisation.base_path, + }] + end + end + end +end diff --git a/lib/govuk_publishing_components/presenters/contextual_navigation.rb b/lib/govuk_publishing_components/presenters/contextual_navigation.rb index 419d850480..04936877c2 100644 --- a/lib/govuk_publishing_components/presenters/contextual_navigation.rb +++ b/lib/govuk_publishing_components/presenters/contextual_navigation.rb @@ -33,6 +33,10 @@ def taxon_breadcrumbs @taxon_breadcrumbs ||= ContentBreadcrumbsBasedOnTaxons.call(content_item) end + def organisation_breadcrumbs + @organisation_breadcrumbs ||= ContentBreadcrumbsBasedOnOrganisations.call(content_item) + end + def breadcrumbs breadcrumbs_based_on_ancestors end @@ -72,6 +76,10 @@ def content_has_curated_related_items? content_item.dig("links", "ordered_related_items").present? && content_item.dig("links", "parent").present? end + def content_has_related_organisations? + ContentItem.new(content_item).related_organisations.present? + end + def content_is_tagged_to_a_live_taxon? content_item.dig("links", "taxons").to_a.any? { |taxon| taxon["phase"] == "live" } end @@ -80,6 +88,10 @@ def content_is_a_specialist_document? content_item["schema_name"] == "specialist_document" end + def content_is_a_corporate_information_page? + content_item["schema_name"] == "corporate_information_page" + end + def content_is_a_html_publication? content_item["document_type"] == "html_publication" end diff --git a/spec/components/contextual_breadcrumbs_spec.rb b/spec/components/contextual_breadcrumbs_spec.rb index 1fe0851c5f..28ffd825e0 100644 --- a/spec/components/contextual_breadcrumbs_spec.rb +++ b/spec/components/contextual_breadcrumbs_spec.rb @@ -97,6 +97,22 @@ def set_live_taxons(content_item) assert_select ".gem-c-breadcrumbs.gem-c-breadcrumbs--inverse" end + it "renders parent-based breadcrumbs if the content item is a corporate information page with a parent" do + content_item = example_document_for("corporate_information_page", "corporate_information_page_complaints") + render_component(content_item:) + assert_select "a", text: "Home" + assert_select "a", text: "Department of Health" + assert_select "a", text: "About us" + end + + it "renders organisation breadcrumbs if the content item is a corporate information page with no parent but with a linked organisation" do + content_item = example_document_for("corporate_information_page", "best-practice-about-page") + render_component(content_item:) + assert_select "a", text: "Home" + assert_select "a", text: "Organisations" + assert_select "a", text: "Intellectual Property Office" + end + it "renders no taxon breadcrumbs if they are not live" do content_item = example_document_for("guide", "guide") content_item = remove_mainstream_browse(content_item) diff --git a/spec/lib/govuk_publishing_components/presenters/breadcrumb_selector_spec.rb b/spec/lib/govuk_publishing_components/presenters/breadcrumb_selector_spec.rb new file mode 100644 index 0000000000..a75ca414c0 --- /dev/null +++ b/spec/lib/govuk_publishing_components/presenters/breadcrumb_selector_spec.rb @@ -0,0 +1,89 @@ +require "spec_helper" + +RSpec.describe GovukPublishingComponents::Presenters::BreadcrumbSelector do + subject do + described_class.new( + content_item, + request, + prioritise_taxon_breadcrumbs, + disable_ga4, + ) + end + let(:example) { %w[guide guide] } + let(:content_item) { example_document_for(example.first, example.second) } + let(:path) { content_item["base_path"] } + let(:query_parameters) { {} } + let(:request) { instance_double("ActionDispatch::Request", path:, query_parameters:) } + let(:prioritise_taxon_breadcrumbs) { false } + let(:disable_ga4) { false } + + def example_document_for(schema_name, example_name) + GovukSchemas::Example.find(schema_name, example_name:) + end + + describe "#initialize" do + it "does not raise exception" do + expect { subject }.not_to raise_error + end + end + + describe "#breadcrumbs" do + context "when content item is corporate information page with parent" do + let(:example) { %w[corporate_information_page corporate_information_page_complaints] } + + it "returns breadcrumbs based on ancestors" do + expect(subject.breadcrumbs).to eq([ + { title: "Home", url: "/" }, + { title: "Department of Health", url: "/government/organisations/department-of-health" }, + { title: "About us", url: "/government/organisations/department-of-health/about" }, + ]) + end + end + + context "when content item is corporate information page without parent but with organisation" do + let(:example) { %w[corporate_information_page best-practice-about-page] } + + it "returns breadcrumbs based on organisation" do + expect(subject.breadcrumbs).to eq([ + { title: "Home", url: "/" }, + { title: "Organisations", url: "/government/organisations" }, + { title: "Intellectual Property Office", url: "/government/organisations/intellectual-property-office" }, + ]) + end + end + + context "when content item is corporate information page without parent, organisations but with taxon" do + let(:content_item) do + item = example_document_for("corporate_information_page", "best-practice-about-page") + item.dig("links", "organisations").clear + item["links"]["taxons"] = [{ + "base_path" => "/corporate-information", + "title" => "Corporate information", + "phase" => "live", + }] + item + end + + it "returns breadcrumbs based on taxons" do + expect(subject.breadcrumbs).to eq([ + { title: "Home", url: "/", is_page_parent: false }, + { title: "Corporate information", url: "/corporate-information", is_page_parent: true }, + ]) + end + end + + context "when content item is corporate information page without parent, organisations and taxons" do + let(:content_item) do + item = example_document_for("corporate_information_page", "best-practice-about-page") + item.dig("links", "organisations").clear + item + end + + it "returns default breadcrumbs" do + expect(subject.breadcrumbs).to eq([ + { title: "Home", url: "/" }, + ]) + end + end + end +end diff --git a/spec/lib/govuk_publishing_components/presenters/content_breadcrumbs_based_on_organisations_spec.rb b/spec/lib/govuk_publishing_components/presenters/content_breadcrumbs_based_on_organisations_spec.rb new file mode 100644 index 0000000000..71df0d944e --- /dev/null +++ b/spec/lib/govuk_publishing_components/presenters/content_breadcrumbs_based_on_organisations_spec.rb @@ -0,0 +1,25 @@ +require "spec_helper" + +RSpec.describe GovukPublishingComponents::Presenters::ContentBreadcrumbsBasedOnOrganisations do + subject { described_class.new(content_item) } + let(:content_item) { GovukSchemas::Example.find("document_collection", example_name: "document_collection") } + + describe "#initialize" do + it "does not raise exception" do + expect { subject }.not_to raise_error + end + end + + describe "#breadcrumbs" do + it "returns breadcrumbs based on organisation" do + expect(subject.breadcrumbs).to eq([ + { title: "Home", url: "/" }, + { title: "Organisations", url: "/government/organisations" }, + { + title: "Driver and Vehicle Standards Agency", + url: "/government/organisations/driver-and-vehicle-standards-agency", + }, + ]) + end + end +end diff --git a/spec/lib/govuk_publishing_components/presenters/contextual_navigation_spec.rb b/spec/lib/govuk_publishing_components/presenters/contextual_navigation_spec.rb new file mode 100644 index 0000000000..1a38fbc734 --- /dev/null +++ b/spec/lib/govuk_publishing_components/presenters/contextual_navigation_spec.rb @@ -0,0 +1,74 @@ +require "spec_helper" + +RSpec.describe GovukPublishingComponents::Presenters::ContextualNavigation do + subject { described_class.new(content_item, request) } + let(:example) { %w[guide guide] } + let(:content_item) { example_document_for(example.first, example.second) } + let(:path) { content_item["base_path"] } + let(:query_parameters) { {} } + let(:request) { instance_double("ActionDispatch::Request", path:, query_parameters:) } + + def example_document_for(schema_name, example_name) + GovukSchemas::Example.find(schema_name, example_name:) + end + + describe "#initialize" do + it "does not raise exception" do + expect { subject }.not_to raise_error + end + end + + describe "#organisation_breadcrumbs" do + it "calls ContentBreadcrumbsBasedOnOrganisation" do + called_class = GovukPublishingComponents::Presenters::ContentBreadcrumbsBasedOnOrganisations + expect(called_class).to receive(:call) + .with(content_item) + .and_return([]) + subject.organisation_breadcrumbs + end + end + + describe "#content_has_related_organisations?" do + context "when content item is linked to no organisations" do + let(:example) { %w[homepage homepage_with_popular_links_on_govuk] } + + it "returns false" do + expect(subject.content_has_related_organisations?).to be(false) + end + end + + context "when content item is only linked to world organisations" do + let(:example) { %w[worldwide_corporate_information_page worldwide_corporate_information_page] } + + it "returns false" do + expect(subject.content_has_related_organisations?).to be(false) + end + end + + context "when content item is linked to at least 1 normal organisation" do + let(:example) { %w[document_collection document_collection] } + + it "returns true" do + expect(subject.content_has_related_organisations?).to be(true) + end + end + end + + describe "#content_is_a_corporate_information_page?" do + context "when content item is corporate information page" do + let(:example) { %w[corporate_information_page corporate_information_page] } + + it "returns true" do + expect(subject.content_is_a_corporate_information_page?).to be(true) + end + end + + context "when content item is not corporate information page" do + let(:example) { %w[guide guide] } + + it "returns false" do + expect(subject.content_is_a_corporate_information_page?).to be(false) + end + end + end +end