diff --git a/db/migrate/20250226161012_add_event_details_to_versions.rb b/db/migrate/20250226161012_add_event_details_to_versions.rb
new file mode 100644
index 00000000000..9c04012c55f
--- /dev/null
+++ b/db/migrate/20250226161012_add_event_details_to_versions.rb
@@ -0,0 +1,15 @@
+class AddEventDetailsToVersions < ActiveRecord::Migration[8.0]
+ def up
+ change_table :content_block_versions, bulk: true do |t|
+ t.string :updated_embedded_object_type
+ t.string :updated_embedded_object_name
+ end
+ end
+
+ def down
+ change_table :content_block_versions, bulk: true do |t|
+ t.remove :updated_embedded_object_type
+ t.remove :updated_embedded_object_name
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 39e6c4780d1..9a0290494f7 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema[8.0].define(version: 2025_02_20_131003) do
+ActiveRecord::Schema[8.0].define(version: 2025_02_26_161012) do
create_table "assets", charset: "utf8mb4", collation: "utf8mb4_unicode_ci", force: :cascade do |t|
t.string "asset_manager_id", null: false
t.string "variant", null: false
@@ -250,6 +250,8 @@
t.datetime "created_at", precision: nil, null: false
t.text "state", size: :medium
t.json "field_diffs"
+ t.string "updated_embedded_object_type"
+ t.string "updated_embedded_object_name"
t.index ["item_id"], name: "index_content_block_versions_on_item_id"
t.index ["item_type"], name: "index_content_block_versions_on_item_type"
end
diff --git a/lib/engines/content_block_manager/app/components/content_block_manager/content_block/document/show/document_timeline/timeline_item_component.html.erb b/lib/engines/content_block_manager/app/components/content_block_manager/content_block/document/show/document_timeline/timeline_item_component.html.erb
index e767301a4bb..771c72d2375 100644
--- a/lib/engines/content_block_manager/app/components/content_block_manager/content_block/document/show/document_timeline/timeline_item_component.html.erb
+++ b/lib/engines/content_block_manager/app/components/content_block_manager/content_block/document/show/document_timeline/timeline_item_component.html.erb
@@ -12,7 +12,16 @@
<%= date %>
- <% if details_of_changes.present? %>
+ <% if version.is_embedded_update? %>
+
+ <% new_subschema_item_details.each do |field_name, value| %>
+ -
+ <%= field_name %>:
+ <%= value %>
+
+ <% end %>
+
+ <% elsif details_of_changes.present? %>
<%= render "govuk_publishing_components/components/details", {
title: "Details of changes",
diff --git a/lib/engines/content_block_manager/app/components/content_block_manager/content_block/document/show/document_timeline/timeline_item_component.rb b/lib/engines/content_block_manager/app/components/content_block_manager/content_block/document/show/document_timeline/timeline_item_component.rb
index 0dd0b0af749..230e75b0b3a 100644
--- a/lib/engines/content_block_manager/app/components/content_block_manager/content_block/document/show/document_timeline/timeline_item_component.rb
+++ b/lib/engines/content_block_manager/app/components/content_block_manager/content_block/document/show/document_timeline/timeline_item_component.rb
@@ -13,16 +13,27 @@ def initialize(version:, schema:, is_first_published_version:, is_latest:)
attr_reader :version, :schema, :is_first_published_version, :is_latest
def title
- case version.state
- when "published"
+ if version.is_embedded_update?
+ "#{updated_subschema_id.humanize.singularize} created"
+ elsif version.state == "published"
is_first_published_version ? "#{version.item.block_type.humanize} created" : version.state.capitalize
- when "scheduled"
+ elsif version.state == "scheduled"
"Scheduled for publishing on #{version.item.scheduled_publication.to_fs(:long_ordinal_with_at)}"
else
"#{version.item.block_type.humanize} #{version.state}"
end
end
+ def updated_subschema_id
+ version.updated_embedded_object_type
+ end
+
+ def new_subschema_item_details
+ version.field_diffs.dig("details", updated_subschema_id, version.updated_embedded_object_name).map do |field_name, diff|
+ [field_name.humanize, diff.new_value]
+ end
+ end
+
def date
tag.time(
version.created_at.to_fs(:long_ordinal_with_at),
diff --git a/lib/engines/content_block_manager/app/controllers/content_block_manager/content_block/editions/embedded_objects_controller.rb b/lib/engines/content_block_manager/app/controllers/content_block_manager/content_block/editions/embedded_objects_controller.rb
index 96281722f56..e344855b984 100644
--- a/lib/engines/content_block_manager/app/controllers/content_block_manager/content_block/editions/embedded_objects_controller.rb
+++ b/lib/engines/content_block_manager/app/controllers/content_block_manager/content_block/editions/embedded_objects_controller.rb
@@ -59,6 +59,8 @@ def publish
object_name: params[:object_name],
)
else
+ @content_block_edition.updated_embedded_object_type = @subschema.block_type
+ @content_block_edition.updated_embedded_object_name = params[:object_name]
ContentBlockManager::PublishEditionService.new.call(@content_block_edition)
flash[:notice] = "#{@subschema.name.singularize} created"
redirect_path = content_block_manager.content_block_manager_content_block_document_path(@content_block_edition.document)
diff --git a/lib/engines/content_block_manager/app/models/content_block_manager/content_block/edition.rb b/lib/engines/content_block_manager/app/models/content_block_manager/content_block/edition.rb
index d492a6c82eb..566edf5dd54 100644
--- a/lib/engines/content_block_manager/app/models/content_block_manager/content_block/edition.rb
+++ b/lib/engines/content_block_manager/app/models/content_block_manager/content_block/edition.rb
@@ -38,10 +38,13 @@ def first_class_details
def clone_edition(creator:)
new_edition = dup
- new_edition.state = "draft"
- new_edition.organisation = lead_organisation
- new_edition.creator = creator
-
+ new_edition.assign_attributes(
+ state: "draft",
+ organisation: lead_organisation,
+ creator: creator,
+ change_note: nil,
+ internal_change_note: nil,
+ )
new_edition
end
diff --git a/lib/engines/content_block_manager/app/models/content_block_manager/content_block/edition/has_audit_trail.rb b/lib/engines/content_block_manager/app/models/content_block_manager/content_block/edition/has_audit_trail.rb
index e90b6105ede..05885f4b2a4 100644
--- a/lib/engines/content_block_manager/app/models/content_block_manager/content_block/edition/has_audit_trail.rb
+++ b/lib/engines/content_block_manager/app/models/content_block_manager/content_block/edition/has_audit_trail.rb
@@ -19,6 +19,8 @@ def self.acting_as(actor)
after_update :record_update
end
+ attr_accessor :updated_embedded_object_type, :updated_embedded_object_name
+
private
def record_create
@@ -30,7 +32,13 @@ def record_update
unless draft?
user = Current.user
state = try(:state)
- versions.create!(event: "updated", user:, state:, field_diffs: generate_diff)
+ versions.create!(
+ event: "updated",
+ user:, state:,
+ field_diffs: generate_diff,
+ updated_embedded_object_type:,
+ updated_embedded_object_name:
+ )
end
end
end
diff --git a/lib/engines/content_block_manager/app/models/content_block_manager/content_block/version.rb b/lib/engines/content_block_manager/app/models/content_block_manager/content_block/version.rb
index d5b6a6695cd..551facdfe42 100644
--- a/lib/engines/content_block_manager/app/models/content_block_manager/content_block/version.rb
+++ b/lib/engines/content_block_manager/app/models/content_block_manager/content_block/version.rb
@@ -10,6 +10,10 @@ class Version < ApplicationRecord
def field_diffs
self[:field_diffs] ? ContentBlock::DiffItem.from_hash(self[:field_diffs]) : {}
end
+
+ def is_embedded_update?
+ updated_embedded_object_type && updated_embedded_object_name
+ end
end
end
end
diff --git a/lib/engines/content_block_manager/features/step_definitions/embedded_object_steps.rb b/lib/engines/content_block_manager/features/step_definitions/embedded_object_steps.rb
index 29814da2b77..963a32f01a2 100644
--- a/lib/engines/content_block_manager/features/step_definitions/embedded_object_steps.rb
+++ b/lib/engines/content_block_manager/features/step_definitions/embedded_object_steps.rb
@@ -43,6 +43,10 @@
@details.keys.each do |k|
assert_equal edition.details[object_type.parameterize.pluralize][key][k], @details[k]
end
+
+ version = edition.versions.order("created_at asc").first
+ assert_equal version.updated_embedded_object_type, object_type.pluralize
+ assert_equal version.updated_embedded_object_name, @object_name
end
Then("I should see errors for the required {string} fields") do |object_type|
diff --git a/lib/engines/content_block_manager/test/components/content_block/document/show/document_timeline/timeline_item_component_test.rb b/lib/engines/content_block_manager/test/components/content_block/document/show/document_timeline/timeline_item_component_test.rb
index 223541c076f..b1bc435d8cf 100644
--- a/lib/engines/content_block_manager/test/components/content_block/document/show/document_timeline/timeline_item_component_test.rb
+++ b/lib/engines/content_block_manager/test/components/content_block/document/show/document_timeline/timeline_item_component_test.rb
@@ -230,4 +230,56 @@ class ContentBlockManager::ContentBlock::Document::Show::DocumentTimeline::Timel
render_inline component
end
end
+
+ describe "when the version is an embedded update" do
+ let(:subschema) { stub(:subschema, id: "embedded_schema", name: "Embedded schema") }
+ let(:schema) { stub(:schema, subschemas: [subschema]) }
+
+ let(:field_diffs) do
+ {
+ "details" => {
+ "embedded_schema" => {
+ "something" => {
+ "field1" => ContentBlockManager::ContentBlock::DiffItem.new(previous_value: nil, new_value: "Field 1 value"),
+ "field2" => ContentBlockManager::ContentBlock::DiffItem.new(previous_value: nil, new_value: "Field 2 value"),
+ },
+ },
+ },
+ }
+ end
+
+ let(:version) do
+ build_stubbed(
+ :content_block_version,
+ event: "created",
+ whodunnit: user.id,
+ state: "published",
+ created_at: 4.days.ago,
+ item: content_block_edition,
+ field_diffs:,
+ updated_embedded_object_type: "embedded_schema",
+ updated_embedded_object_name: "something",
+ )
+ end
+
+ before do
+ schema.stubs(:subschema).with("embedded_schema").returns(subschema)
+ end
+
+ it "renders the correct title" do
+ render_inline component
+
+ assert_selector ".timeline__title", text: "Embedded schema created"
+ end
+
+ it "renders the details of the updated object" do
+ render_inline component
+
+ assert_selector ".timeline__embedded-item-list .timeline__embedded-item-list__item:nth-child(1) .timeline__embedded-item-list__key", text: "Field1:"
+ assert_selector ".timeline__embedded-item-list .timeline__embedded-item-list__item:nth-child(1) .timeline__embedded-item-list__value", text: "Field 1 value"
+
+ assert_selector ".timeline__embedded-item-list .timeline__embedded-item-list__item:nth-child(2) .timeline__embedded-item-list__key", text: "Field2:"
+ assert_selector ".timeline__embedded-item-list .timeline__embedded-item-list__item:nth-child(2) .timeline__embedded-item-list__value", text: "Field 2 value"
+ end
+ end
end
diff --git a/lib/engines/content_block_manager/test/unit/app/models/content_block_edition/has_audit_trail_test.rb b/lib/engines/content_block_manager/test/unit/app/models/content_block_edition/has_audit_trail_test.rb
index 45338f578c8..6ee9505ff13 100644
--- a/lib/engines/content_block_manager/test/unit/app/models/content_block_edition/has_audit_trail_test.rb
+++ b/lib/engines/content_block_manager/test/unit/app/models/content_block_edition/has_audit_trail_test.rb
@@ -49,6 +49,27 @@ class ContentBlockManager::HasAuditTrailTest < ActiveSupport::TestCase
assert_equal "scheduled", version.state
end
+ it "adds event details if provided" do
+ Current.user = user
+ edition = create(
+ :content_block_edition,
+ creator: user,
+ document: create(:content_block_document, :email_address),
+ )
+ edition.expects(:generate_diff).returns({})
+ edition.updated_embedded_object_type = "something"
+ edition.updated_embedded_object_name = "here"
+
+ assert_changes -> { edition.versions.count }, from: 1, to: 2 do
+ edition.publish!
+ end
+
+ version = edition.versions.first
+
+ assert_equal edition.updated_embedded_object_type, version.updated_embedded_object_type
+ assert_equal edition.updated_embedded_object_name, version.updated_embedded_object_name
+ end
+
it "does not record a version when updating an existing draft" do
edition = create(
:content_block_edition,
diff --git a/lib/engines/content_block_manager/test/unit/app/models/content_block_edition_test.rb b/lib/engines/content_block_manager/test/unit/app/models/content_block_edition_test.rb
index 3333b36739d..bcc1fef66bf 100644
--- a/lib/engines/content_block_manager/test/unit/app/models/content_block_edition_test.rb
+++ b/lib/engines/content_block_manager/test/unit/app/models/content_block_edition_test.rb
@@ -242,7 +242,9 @@ class ContentBlockManager::ContentBlockEditionTest < ActiveSupport::TestCase
:content_block_edition, :email_address,
title: "Some title",
details: { "my" => "details" },
- state: "published"
+ state: "published",
+ change_note: "Something",
+ internal_change_note: "Something else"
)
creator = create(:user)
@@ -254,6 +256,8 @@ class ContentBlockManager::ContentBlockEditionTest < ActiveSupport::TestCase
assert_equal new_edition.creator, creator
assert_equal new_edition.title, content_block_edition.title
assert_equal new_edition.details, content_block_edition.details
+ assert_equal new_edition.change_note, nil
+ assert_equal new_edition.internal_change_note, nil
end
end
diff --git a/lib/engines/content_block_manager/test/unit/app/models/content_block_version_test.rb b/lib/engines/content_block_manager/test/unit/app/models/content_block_version_test.rb
index 3de7d71f34e..4c425a977bf 100644
--- a/lib/engines/content_block_manager/test/unit/app/models/content_block_version_test.rb
+++ b/lib/engines/content_block_manager/test/unit/app/models/content_block_version_test.rb
@@ -71,4 +71,17 @@ class ContentBlockManager::ContentBlockVersionTest < ActiveSupport::TestCase
assert_equal ({}), content_block_version.field_diffs
end
end
+
+ describe "#is_embedded_update?" do
+ it "returns false by default" do
+ assert_not content_block_version.is_embedded_update?
+ end
+
+ it "returns true when updated_embedded_object_type and updated_embedded_object_name are set" do
+ content_block_version.updated_embedded_object_type = "something"
+ content_block_version.updated_embedded_object_name = "something"
+
+ assert content_block_version.is_embedded_update?
+ end
+ end
end