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 2556fc2d54d..5452e7a2db8 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
@@ -1,6 +1,7 @@
class ContentBlockManager::ContentBlock::DocumentsController < ContentBlockManager::BaseController
def index
- @content_block_documents = ContentBlockManager::ContentBlock::Document.live
+ @filters = params_filters
+ @content_block_documents = ContentBlockManager::ContentBlock::Document::DocumentFilter.new(@filters).documents
end
def show
@@ -23,4 +24,12 @@ def new_document_options_redirect
redirect_to content_block_manager.new_content_block_manager_content_block_document_path, flash: { error: "You must select a block type" }
end
end
+
+private
+
+ def params_filters
+ params.slice(:title)
+ .permit!
+ .to_h
+ end
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 99975c640b5..2ecfd2a72ea 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
@@ -1,6 +1,8 @@
module ContentBlockManager
module ContentBlock
class Document < ApplicationRecord
+ include Scopes::SearchableByTitle
+
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
new file mode 100644
index 00000000000..e44f3dcc909
--- /dev/null
+++ b/lib/engines/content_block_manager/app/models/content_block_manager/content_block/document/document_filter.rb
@@ -0,0 +1,14 @@
+module ContentBlockManager
+ class ContentBlock::Document::DocumentFilter
+ def initialize(filters = {})
+ @filters = filters
+ end
+
+ def documents
+ documents = ContentBlock::Document
+ documents = documents.live
+ documents = documents.with_title(@filters[:title]) if @filters[:title].present?
+ documents
+ end
+ end
+end
diff --git a/lib/engines/content_block_manager/app/models/content_block_manager/content_block/document/scopes/searchable_by_title.rb b/lib/engines/content_block_manager/app/models/content_block_manager/content_block/document/scopes/searchable_by_title.rb
new file mode 100644
index 00000000000..aa9badfc4f1
--- /dev/null
+++ b/lib/engines/content_block_manager/app/models/content_block_manager/content_block/document/scopes/searchable_by_title.rb
@@ -0,0 +1,18 @@
+module ContentBlockManager
+ module ContentBlock::Document::Scopes::SearchableByTitle
+ extend ActiveSupport::Concern
+
+ included do
+ scope :with_title,
+ lambda { |keywords|
+ split_keywords = keywords.split
+ pattern = ""
+ split_keywords.map do |k|
+ escaped_word = Regexp.escape(k)
+ pattern += "(?=.*#{escaped_word})"
+ end
+ where("title REGEXP :pattern", pattern:)
+ }
+ 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
new file mode 100644
index 00000000000..9205f293098
--- /dev/null
+++ b/lib/engines/content_block_manager/app/views/content_block_manager/content_block/documents/_filter_options.html.erb
@@ -0,0 +1,17 @@
+<%= form_with url: content_block_manager.content_block_manager_content_block_documents_path, method: :get do %>
+ <%= render "govuk_publishing_components/components/input", {
+ label: {
+ text: "Title",
+ bold: true,
+ },
+ hint: 'For example, "driving standards"',
+ name: "title",
+ id: "title_filter",
+ value: !@filters.nil? && @filters[:title],
+ } %>
+
+ <%= 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 d9bf6ae6485..ba03c68400f 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
@@ -11,9 +11,13 @@
-
- <% @content_block_documents.each do |content_block_document| %>
- <%= render ContentBlockManager::ContentBlock::Document::Index::SummaryCardComponent.new(content_block_document:) %>
- <% end %>
+
+ <%= render "filter_options" %>
+
+
+
<%= pluralize(@content_block_documents.count, "result") %>
+ <% @content_block_documents.each do |content_block_document| %>
+ <%= render ContentBlockManager::ContentBlock::Document::Index::SummaryCardComponent.new(content_block_document:) %>
+ <% end %>
diff --git a/lib/engines/content_block_manager/features/search_for_object.feature b/lib/engines/content_block_manager/features/search_for_object.feature
new file mode 100644
index 00000000000..6977dd461f4
--- /dev/null
+++ b/lib/engines/content_block_manager/features/search_for_object.feature
@@ -0,0 +1,18 @@
+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 a schema "email_address" exists with the following fields:
+ | email_address |
+ And an email address content block has been created
+ And an email address content block has been created with the title "example search title"
+
+ 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
+ When I enter the title "example search"
+ 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
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 753bde0a7fc..c1a32dcbcda 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
@@ -37,6 +37,10 @@
click_button "Cancel"
end
+When("I click to view results") do
+ click_button "View results"
+end
+
Then("I should see all the schemas listed") do
@schemas.values.each do |schema|
expect(page).to have_content(schema.name)
@@ -183,6 +187,25 @@
@content_blocks.push(@content_block)
end
+Given("an email address content block has been created with the title {string}") do |title|
+ @content_blocks ||= []
+ @email_address = "foo@example.com"
+ organisation = create(:organisation)
+ document = create(:content_block_document, :email_address, title:)
+ @content_block = create(
+ :content_block_edition,
+ :email_address,
+ document:,
+ details: { email_address: @email_address },
+ creator: @user,
+ organisation:,
+ )
+ ContentBlockManager::ContentBlock::Edition::HasAuditTrail.acting_as(@user) do
+ @content_block.publish!
+ end
+ @content_blocks.push(@content_block)
+end
+
When("I visit the page for the content block") do
visit content_block_manager.content_block_manager_content_block_edition_path(@content_block)
end
@@ -214,6 +237,14 @@
end
end
+Then("I should see the content block with title {string} returned") do |title|
+ expect(page).to have_selector(".govuk-summary-card__title", text: title)
+end
+
+Then("{string} content blocks are returned") do |count|
+ assert_text "#{count} #{'result'.pluralize(count.to_i)}"
+end
+
When("I click to view the document") do
@schema = @schemas[@content_block.document.block_type]
click_link href: content_block_manager.content_block_manager_content_block_document_path(@content_block.document)
@@ -445,6 +476,10 @@ def should_show_edit_form_for_email_address_content_block(document_title, email_
fill_in_date_and_time_field(past_date)
end
+When("I enter the title {string}") do |title|
+ fill_in "Title", with: title
+end
+
Then("the edition should have been scheduled successfully") do
@schema = @schemas[@content_block.document.block_type]
assert_text "#{@schema.name} scheduled successfully"
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
new file mode 100644
index 00000000000..87cb47b1fb6
--- /dev/null
+++ b/lib/engines/content_block_manager/test/unit/app/models/content_block_edition/document/document_filter_test.rb
@@ -0,0 +1,26 @@
+require "test_helper"
+
+class ContentBlockManager::DocumentFilterTest < ActiveSupport::TestCase
+ extend Minitest::Spec::DSL
+
+ describe "documents" do
+ describe "when no filters are given" do
+ it "returns live documents" do
+ document_scope_mock = mock
+ ContentBlockManager::ContentBlock::Document.expects(:live).returns(document_scope_mock)
+ document_scope_mock.expects(:with_title).never
+
+ ContentBlockManager::ContentBlock::Document::DocumentFilter.new({}).documents
+ end
+ end
+
+ describe "when a title filter is given" do
+ it "returns live documents with keyword in title" do
+ document_scope_mock = mock
+ ContentBlockManager::ContentBlock::Document.expects(:live).returns(document_scope_mock)
+ document_scope_mock.expects(:with_title).returns([])
+ ContentBlockManager::ContentBlock::Document::DocumentFilter.new({ title: "ministry of example" }).documents
+ end
+ end
+ end
+end
diff --git a/lib/engines/content_block_manager/test/unit/app/models/content_block_edition/document/scopes/searchable_by_title_test.rb b/lib/engines/content_block_manager/test/unit/app/models/content_block_edition/document/scopes/searchable_by_title_test.rb
new file mode 100644
index 00000000000..7d6162a2111
--- /dev/null
+++ b/lib/engines/content_block_manager/test/unit/app/models/content_block_edition/document/scopes/searchable_by_title_test.rb
@@ -0,0 +1,21 @@
+require "test_helper"
+
+class ContentBlockManager::SearchableByTitleTest < ActiveSupport::TestCase
+ extend Minitest::Spec::DSL
+
+ describe ".with_title" do
+ test "should find documents with title containing keyword" do
+ document_with_first_keyword = create(:content_block_document, :email_address, title: "klingons and such")
+ _edition_with_first_keyword = create(:content_block_edition, :email_address, document: document_with_first_keyword)
+ _document_without_first_keyword = create(:content_block_document, :email_address, title: "this document is about muppets")
+ assert_equal [document_with_first_keyword], ContentBlockManager::ContentBlock::Document.with_title("klingons")
+ end
+
+ test "should find documents with title containing keywords not in order" do
+ document_with_first_keyword = create(:content_block_document, :email_address, title: "klingons and such")
+ _edition_with_first_keyword = create(:content_block_edition, :email_address, document: document_with_first_keyword)
+ _document_without_first_keyword = create(:content_block_document, :email_address, title: "muppets and such")
+ assert_equal [document_with_first_keyword], ContentBlockManager::ContentBlock::Document.with_title("such klingons")
+ end
+ end
+end