diff --git a/lib/engines/content_block_manager/app/components/content_block_manager/content_block/document/index/filter_options_component.html.erb b/lib/engines/content_block_manager/app/components/content_block_manager/content_block/document/index/filter_options_component.html.erb new file mode 100644 index 00000000000..9522d6b46be --- /dev/null +++ b/lib/engines/content_block_manager/app/components/content_block_manager/content_block/document/index/filter_options_component.html.erb @@ -0,0 +1,35 @@ +<%= form_with url: helpers.content_block_manager.content_block_manager_content_block_documents_path, method: :get do %> + <%= render "govuk_publishing_components/components/input", { + label: { + text: "Keyword", + bold: true, + }, + hint: 'For example, "driving standards"', + name: "keyword", + id: "keyword_filter", + value: !@filters.nil? && @filters[:keyword], + } %> + + <%= render "govuk_publishing_components/components/checkboxes", { + heading: "Content block type", + heading_size: "s", + no_hint_text: true, + id: "block_type", + name: "block_type[]", + items: items_for_block_type, + } %> + + <%= render "components/select_with_search", { + id: "lead_organisation", + name: "lead_organisation", + label: "Lead organisation", + heading_size: "s", + include_blank: true, + options: options_for_lead_organisation, + } %> + + <%= render "govuk_publishing_components/components/button", { + text: "View results", + margin_bottom: 4, + } %> +<% end %> diff --git a/lib/engines/content_block_manager/app/components/content_block_manager/content_block/document/index/filter_options_component.rb b/lib/engines/content_block_manager/app/components/content_block_manager/content_block/document/index/filter_options_component.rb new file mode 100644 index 00000000000..ee44f71154d --- /dev/null +++ b/lib/engines/content_block_manager/app/components/content_block_manager/content_block/document/index/filter_options_component.rb @@ -0,0 +1,28 @@ +class ContentBlockManager::ContentBlock::Document::Index::FilterOptionsComponent < ViewComponent::Base + include ActionView::Helpers::RecordTagHelper + def initialize(filters:) + @filters = filters + end + +private + + def items_for_block_type + ContentBlockManager::ContentBlock::Schema.valid_schemas.map do |schema_name| + { + label: schema_name.humanize, + value: schema_name, + checked: !@filters.nil? && @filters[:block_type]&.include?(schema_name), + } + end + end + + def options_for_lead_organisation + helpers.taggable_organisations_container.map do |name, id| + { + text: name, + value: id, + selected: !@filters.nil? && @filters[:lead_organisation] == id.to_s, + } + end + end +end diff --git a/lib/engines/content_block_manager/app/controllers/content_block_manager/content_block/documents_controller.rb b/lib/engines/content_block_manager/app/controllers/content_block_manager/content_block/documents_controller.rb index 9e4185d8e76..3a24f7cb273 100644 --- a/lib/engines/content_block_manager/app/controllers/content_block_manager/content_block/documents_controller.rb +++ b/lib/engines/content_block_manager/app/controllers/content_block_manager/content_block/documents_controller.rb @@ -28,7 +28,7 @@ def new_document_options_redirect private def params_filters - params.slice(:keyword) + params.slice(:keyword, :block_type, :lead_organisation) .permit! .to_h end diff --git a/lib/engines/content_block_manager/app/models/content_block_manager/content_block/document.rb b/lib/engines/content_block_manager/app/models/content_block_manager/content_block/document.rb index afe2424b5d4..dd877073bb0 100644 --- a/lib/engines/content_block_manager/app/models/content_block_manager/content_block/document.rb +++ b/lib/engines/content_block_manager/app/models/content_block_manager/content_block/document.rb @@ -2,6 +2,7 @@ module ContentBlockManager module ContentBlock class Document < ApplicationRecord include Scopes::SearchableByKeyword + include Scopes::SearchableByLeadOrganisation extend FriendlyId friendly_id :title, use: :slugged, slug_column: :content_id_alias, routes: :default diff --git a/lib/engines/content_block_manager/app/models/content_block_manager/content_block/document/document_filter.rb b/lib/engines/content_block_manager/app/models/content_block_manager/content_block/document/document_filter.rb index c2bb05713fd..ba30dd275e9 100644 --- a/lib/engines/content_block_manager/app/models/content_block_manager/content_block/document/document_filter.rb +++ b/lib/engines/content_block_manager/app/models/content_block_manager/content_block/document/document_filter.rb @@ -8,6 +8,8 @@ def documents documents = ContentBlock::Document documents = documents.live documents = documents.with_keyword(@filters[:keyword]) if @filters[:keyword].present? + documents = documents.where(block_type: @filters[:block_type]) if @filters[:block_type].present? + documents = documents.with_lead_organisation(@filters[:lead_organisation]) if @filters[:lead_organisation].present? documents end end diff --git a/lib/engines/content_block_manager/app/models/content_block_manager/content_block/document/scopes/searchable_by_lead_organisation.rb b/lib/engines/content_block_manager/app/models/content_block_manager/content_block/document/scopes/searchable_by_lead_organisation.rb new file mode 100644 index 00000000000..6bc1cb1897d --- /dev/null +++ b/lib/engines/content_block_manager/app/models/content_block_manager/content_block/document/scopes/searchable_by_lead_organisation.rb @@ -0,0 +1,12 @@ +module ContentBlockManager + module ContentBlock::Document::Scopes::SearchableByLeadOrganisation + extend ActiveSupport::Concern + + included do + scope :with_lead_organisation, + lambda { |id| + joins(latest_edition: :edition_organisation).where("content_block_edition_organisations.organisation_id = :id", id:) + } + end + end +end diff --git a/lib/engines/content_block_manager/app/views/content_block_manager/content_block/documents/_filter_options.html.erb b/lib/engines/content_block_manager/app/views/content_block_manager/content_block/documents/_filter_options.html.erb deleted file mode 100644 index ad99cf2b49b..00000000000 --- a/lib/engines/content_block_manager/app/views/content_block_manager/content_block/documents/_filter_options.html.erb +++ /dev/null @@ -1,17 +0,0 @@ -<%= form_with url: content_block_manager.content_block_manager_content_block_documents_path, method: :get do %> - <%= render "govuk_publishing_components/components/input", { - label: { - text: "Keyword", - bold: true, - }, - hint: 'For example, "driving standards"', - name: "keyword", - id: "keyword_filter", - value: !@filters.nil? && @filters[:keyword], - } %> - - <%= render "govuk_publishing_components/components/button", { - text: "View results", - margin_bottom: 4, - } %> -<% end %> diff --git a/lib/engines/content_block_manager/app/views/content_block_manager/content_block/documents/index.html.erb b/lib/engines/content_block_manager/app/views/content_block_manager/content_block/documents/index.html.erb index ba03c68400f..7e8f26b99fb 100644 --- a/lib/engines/content_block_manager/app/views/content_block_manager/content_block/documents/index.html.erb +++ b/lib/engines/content_block_manager/app/views/content_block_manager/content_block/documents/index.html.erb @@ -12,7 +12,11 @@
- <%= render "filter_options" %> + <%= render( + ContentBlockManager::ContentBlock::Document::Index::FilterOptionsComponent.new( + filters: @filters, + ), + ) %>

<%= pluralize(@content_block_documents.count, "result") %>

diff --git a/lib/engines/content_block_manager/features/search_for_object.feature b/lib/engines/content_block_manager/features/search_for_object.feature index e2ef49bf02d..102cde00df6 100644 --- a/lib/engines/content_block_manager/features/search_for_object.feature +++ b/lib/engines/content_block_manager/features/search_for_object.feature @@ -2,18 +2,23 @@ Feature: Search for a content object Background: Given the content block manager feature flag is enabled Given I am a GDS admin - And the organisation "Ministry of Example" exists + And the organisation "Department of Placeholder" exists And a schema "email_address" exists with the following fields: | email_address | + And a schema "postal_address" exists with the following fields: + | an_address | And an email address content block has been created And an email address content block has been created with the following email address and title: - | title | "example search title" | - | email_address | "ministry@justice.com" | + | title | example search title | + | email_address | ministry@justice.com | + And a "postal_address" type of content block has been created with fields: + | an_address | ABC123 | + | organisation | Department of Placeholder | Scenario: GDS Editor searches for a content object by keyword in title When I visit the Content Block Manager home page Then I should see the details for all documents - And "2" content blocks are returned + And "3" content blocks are returned When I enter the keyword "example search" And I click to view results Then I should see the content block with title "example search title" returned @@ -22,8 +27,24 @@ Feature: Search for a content object Scenario: GDS Editor searches for a content object by keyword in details When I visit the Content Block Manager home page Then I should see the details for all documents - And "2" content blocks are returned + And "3" content blocks are returned When I enter the keyword "ministry justice" And I click to view results Then I should see the content block with title "example search title" returned - And "1" content blocks are returned \ No newline at end of file + And "1" content blocks are returned + + Scenario: GDS Editor searches for a content object by block type + When I visit the Content Block Manager home page + Then I should see the details for all documents + And "3" content blocks are returned + When I check the block type "Email address" + And I click to view results + And "2" content blocks are returned + + Scenario: GDS Editor searches for a content object by lead organisation + When I visit the Content Block Manager home page + Then I should see the details for all documents + And "3" content blocks are returned + When I select the lead organisation "Department of Placeholder" + And I click to view results + And "1" content blocks are returned diff --git a/lib/engines/content_block_manager/features/step_definitions/content_block_manager_steps.rb b/lib/engines/content_block_manager/features/step_definitions/content_block_manager_steps.rb index 6ad8ed550b7..63ea4e4c0b2 100644 --- a/lib/engines/content_block_manager/features/step_definitions/content_block_manager_steps.rb +++ b/lib/engines/content_block_manager/features/step_definitions/content_block_manager_steps.rb @@ -187,6 +187,19 @@ @content_blocks.push(@content_block) end +Given("a {string} type of content block has been created with fields:") do |block_type, table| + fields = table.rows_hash + organisation_name = fields.delete("organisation") + organisation = Organisation.where(name: organisation_name).first + create( + :content_block_edition, + block_type.to_sym, + organisation:, + details: fields, + creator: @user, + ) +end + Given("an email address content block has been created with the following email address and title:") do |table| fields = table.rows_hash @content_blocks ||= [] @@ -435,6 +448,14 @@ def should_show_edit_form_for_email_address_content_block(document_title, email_ choose "Publish the change now" end +Then("I check the block type {string}") do |checkbox_name| + check checkbox_name +end + +Then("I select the lead organisation {string}") do |organisation| + select organisation, from: "lead_organisation" +end + When("I revisit the edit page") do @content_block = @content_block.document.latest_edition visit_edit_page diff --git a/lib/engines/content_block_manager/test/components/content_block/document/index/filter_options_component_test.rb b/lib/engines/content_block_manager/test/components/content_block/document/index/filter_options_component_test.rb new file mode 100644 index 00000000000..37bb8a0ab06 --- /dev/null +++ b/lib/engines/content_block_manager/test/components/content_block/document/index/filter_options_component_test.rb @@ -0,0 +1,47 @@ +require "test_helper" + +class ContentBlockManager::ContentBlock::Document::Index::FilterOptionsComponentTest < ViewComponent::TestCase + test "adds value of keyword to text input from filter" do + render_inline(ContentBlockManager::ContentBlock::Document::Index::FilterOptionsComponent.new( + filters: { keyword: "ministry defense" }, + )) + + assert_selector "input[name='keyword'][value='ministry defense']" + end + + test "renders checkbox items for all valid schemas" do + ContentBlockManager::ContentBlock::Schema.expects(:valid_schemas).returns(%w[email_address postal_address]) + render_inline(ContentBlockManager::ContentBlock::Document::Index::FilterOptionsComponent.new( + filters: {}, + )) + + assert_selector "input[type='checkbox'][name='block_type[]'][value='email_address']" + assert_selector "input[type='checkbox'][name='block_type[]'][value='postal_address']" + end + + test "checks checkbox items if checked in filters" do + ContentBlockManager::ContentBlock::Schema.expects(:valid_schemas).returns(%w[email_address postal_address]) + render_inline(ContentBlockManager::ContentBlock::Document::Index::FilterOptionsComponent.new( + filters: { block_type: %w[email_address] }, + )) + + assert_selector "input[type='checkbox'][name='block_type[]'][value='email_address'][checked]" + assert_selector "input[type='checkbox'][name='block_type[]'][value='postal_address']" + end + + test "selects organisation if selected in filters" do + helper_mock = mock + ContentBlockManager::ContentBlock::Document::Index::FilterOptionsComponent.any_instance.stubs(:helpers).returns(helper_mock) + helper_mock.stubs(:content_block_manager).returns(helper_mock) + helper_mock.stubs(:content_block_manager_content_block_documents_path).returns("path") + helper_mock.stubs(:taggable_organisations_container).returns( + [["Department of Placeholder", 1], ["Ministry of Example", 2]], + ) + render_inline(ContentBlockManager::ContentBlock::Document::Index::FilterOptionsComponent.new( + filters: { lead_organisation: "2" }, + )) + + assert_selector "select[name='lead_organisation']" + assert_selector "option[selected='selected'][value=2]" + end +end diff --git a/lib/engines/content_block_manager/test/unit/app/models/content_block_edition/document/document_filter_test.rb b/lib/engines/content_block_manager/test/unit/app/models/content_block_edition/document/document_filter_test.rb index 5aaa7da7bc4..b0f02eace43 100644 --- a/lib/engines/content_block_manager/test/unit/app/models/content_block_edition/document/document_filter_test.rb +++ b/lib/engines/content_block_manager/test/unit/app/models/content_block_edition/document/document_filter_test.rb @@ -9,6 +9,8 @@ class ContentBlockManager::DocumentFilterTest < ActiveSupport::TestCase document_scope_mock = mock ContentBlockManager::ContentBlock::Document.expects(:live).returns(document_scope_mock) document_scope_mock.expects(:with_keyword).never + document_scope_mock.expects(:where).never + document_scope_mock.expects(:with_lead_organisation).never ContentBlockManager::ContentBlock::Document::DocumentFilter.new({}).documents end @@ -22,5 +24,36 @@ class ContentBlockManager::DocumentFilterTest < ActiveSupport::TestCase ContentBlockManager::ContentBlock::Document::DocumentFilter.new({ keyword: "ministry of example" }).documents end end + + describe "when a block type is given" do + it "returns live documents of the type given" do + document_scope_mock = mock + ContentBlockManager::ContentBlock::Document.expects(:live).returns(document_scope_mock) + document_scope_mock.expects(:where).with(block_type: %w[email_address]).returns([]) + ContentBlockManager::ContentBlock::Document::DocumentFilter.new({ block_type: %w[email_address] }).documents + end + end + + describe "when a lead organisation id is given" do + it "returns live documents with lead org given" do + document_scope_mock = mock + ContentBlockManager::ContentBlock::Document.expects(:live).returns(document_scope_mock) + document_scope_mock.expects(:with_lead_organisation).with("123").returns([]) + ContentBlockManager::ContentBlock::Document::DocumentFilter.new({ lead_organisation: "123" }).documents + end + end + + describe "when block types, keyword and organisation is given" do + it "returns live documents with the filters given" do + document_scope_mock = mock + ContentBlockManager::ContentBlock::Document.expects(:live).returns(document_scope_mock) + document_scope_mock.expects(:with_keyword).with("ministry of example").returns(document_scope_mock) + document_scope_mock.expects(:where).with(block_type: %w[email_address]).returns(document_scope_mock) + document_scope_mock.expects(:with_lead_organisation).with("123").returns([]) + ContentBlockManager::ContentBlock::Document::DocumentFilter.new( + { block_type: %w[email_address], keyword: "ministry of example", lead_organisation: "123" }, + ).documents + end + end end end diff --git a/lib/engines/content_block_manager/test/unit/app/models/content_block_edition/document/scopes/searchable_by_lead_organisation_test.rb b/lib/engines/content_block_manager/test/unit/app/models/content_block_edition/document/scopes/searchable_by_lead_organisation_test.rb new file mode 100644 index 00000000000..3950b086423 --- /dev/null +++ b/lib/engines/content_block_manager/test/unit/app/models/content_block_edition/document/scopes/searchable_by_lead_organisation_test.rb @@ -0,0 +1,20 @@ +require "test_helper" + +class ContentBlockManager::SearchableByLeadOrganisationTest < ActiveSupport::TestCase + extend Minitest::Spec::DSL + + describe ".with_lead_organisation" do + test "finds documents with lead organisation on latest edition" do + matching_organisation = create(:organisation, id: "1234") + document_with_org = create(:content_block_document, :email_address) + _edition_with_org = create(:content_block_edition, + :email_address, + document: document_with_org, + organisation: matching_organisation) + document_without_org = create(:content_block_document, :email_address) + _edition_without_org = create(:content_block_edition, :email_address, document: document_without_org) + _document_without_latest_edition = create(:content_block_document, :email_address) + assert_equal [document_with_org], ContentBlockManager::ContentBlock::Document.with_lead_organisation("1234") + end + end +end