From 41565c9b8127a3be48a6f95a3809c6bc11209952 Mon Sep 17 00:00:00 2001 From: ChrisBAshton Date: Tue, 26 May 2026 14:45:38 +0100 Subject: [PATCH] POC: Create way of publishing a Navigation object The Navigation content type is a StandardEdition here, but when we do this for real we may model it differently. The two important things to note: - `details.menu_items`: hardcoded payload describing the _structure_ of the navigation (e.g. its nesting, which menu items are highlighted etc). - `links.navigation_items`: hardcoded payload describing the _content_ of the navigation (JSON array of content IDs representing the documents that form the Navigation. For now these inputs expect JSON and content IDs. When we do it for real, we wouldn't have these fields - we'd have some way of choosing/reordering child documents etc, and inferring the details and links from that. Note that we've dropped the requirement to specify a base path prefix or rendering app in the settings, here. We do still want to enforce that most of the time, so should consider only loosening it if a different property, `routeless_document: true` or something, is set. --- .../navigation.json | 59 +++++++++++++++++++ .../payload_builder/block_content.rb | 7 +++ .../configurable_document_links.rb | 14 +++++ public/configurable-document-type.schema.json | 10 ++-- 4 files changed, 86 insertions(+), 4 deletions(-) create mode 100644 app/models/configurable_document_types/navigation.json diff --git a/app/models/configurable_document_types/navigation.json b/app/models/configurable_document_types/navigation.json new file mode 100644 index 00000000000..e8d43560bd1 --- /dev/null +++ b/app/models/configurable_document_types/navigation.json @@ -0,0 +1,59 @@ +{ + "key": "navigation", + "title": "Navigation", + "description": "Spiking a navigation object. In the future this would likely live as a separate artefact in a tab on a given configurable document type. But this spike allows us to hard code a blob of JSON and send to Publishing API without having to worry about the lifecycle of the associated edition.", + "forms": { + "documents": { + "fields": { + "menu_items": { + "title": "Menu items", + "description": "JSON hash to be sent as part of the Navigation's `details` - for spike purposes only. The intention is to use this to describe the _structure_ of the navigation (e.g. nesting).", + "block": "default_textarea", + "attribute_path": ["block_content", "menu_items"], + "translatable": false + }, + "navigation_items": { + "title": "Linked navigation documents", + "description": "JSON hash of content IDs of documents to be linked to this navigation document as `links.navigation_items` in the Publishing API payload. Should map to the same menu items referenced in the `menu_items` field. For spike purposes only.", + "block": "default_textarea", + "attribute_path": ["block_content", "navigation_items"], + "translatable": false + } + } + } + }, + "schema": { + "attributes": { + "menu_items": { + "type": "string" + }, + "navigation_items": { + "type": "string" + } + } + }, + "presenters": { + "publishing_api": { + "details": { + "menu_items": "parsed_as_hash" + }, + "links": [ + "navigation_items" + ] + } + }, + "settings": { + "publishing_api_schema_name": "shared_navigation", + "publishing_api_document_type": "shared_navigation", + "send_change_history": false, + "file_attachments_enabled": false, + "images": { + "enabled": false + }, + "organisations": null, + "backdating_enabled": false, + "history_mode_enabled": false, + "taxon_required": false, + "translations_enabled": false + } +} \ No newline at end of file diff --git a/app/presenters/publishing_api/payload_builder/block_content.rb b/app/presenters/publishing_api/payload_builder/block_content.rb index 854278f9429..76d8c509620 100644 --- a/app/presenters/publishing_api/payload_builder/block_content.rb +++ b/app/presenters/publishing_api/payload_builder/block_content.rb @@ -28,6 +28,13 @@ def raw(attribute) item.block_content&.public_send(attribute) end + def parsed_as_hash(attribute) + content = item.block_content&.public_send(attribute) + return nil if content.nil? + + JSON.parse(content) + end + def govspeak(attribute) content = item.block_content&.public_send(attribute) return nil if content.nil? diff --git a/app/presenters/publishing_api/payload_builder/configurable_document_links.rb b/app/presenters/publishing_api/payload_builder/configurable_document_links.rb index 91176f5a92b..28161a3f474 100644 --- a/app/presenters/publishing_api/payload_builder/configurable_document_links.rb +++ b/app/presenters/publishing_api/payload_builder/configurable_document_links.rb @@ -52,5 +52,19 @@ def self.worldwide_organisations(item) def self.government(item) { government: [item.government&.content_id].compact } end + + def self.navigation_items(item) + content = item.block_content["navigation_items"] + return nil if content.nil? + + # TODO: simplify. This originally was going to be an array of objects but is now just a list of content IDs + # e.g. + # [ + # "05c902c3-8272-4940-be0c-2c71e36e538d" + # ] + # All we're doing is parsing the JSON above, but we could probably make this + # a comma separated list, or even better, use the array / add-another component + { navigation_items: JSON.parse(content) } + end end end diff --git a/public/configurable-document-type.schema.json b/public/configurable-document-type.schema.json index e3bbbdab28e..1c5ca2e13a1 100644 --- a/public/configurable-document-type.schema.json +++ b/public/configurable-document-type.schema.json @@ -285,6 +285,7 @@ "govspeak", "rfc3339_date", "image", + "parsed_as_hash", "raw", "social_media_links" ] @@ -302,6 +303,7 @@ "type": "string", "description": "The builder methods to use for populating the links object when presenting to the Publishing API.", "enum": [ + "navigation_items", "ministerial_role_appointments", "topical_events", "world_locations", @@ -345,7 +347,8 @@ "history", "topical_event", "news_article", - "case_study" + "case_study", + "shared_navigation" ] }, "publishing_api_document_type": { @@ -358,7 +361,8 @@ "world_news_story", "history", "topical_event", - "case_study" + "case_study", + "shared_navigation" ] }, "rendering_app": { @@ -467,10 +471,8 @@ } }, "required": [ - "base_path_prefix", "publishing_api_schema_name", "publishing_api_document_type", - "rendering_app", "images", "send_change_history", "organisations",