department-of-veterans-affairs / va.gov-cms

Editor-centered management for Veteran-centered content.
https://prod.cms.va.gov
GNU General Public License v2.0
99 stars 69 forks source link

[SPIKE] Facility menus #8693

Closed timcosgrove closed 2 years ago

timcosgrove commented 2 years ago

Description

Spike to dive a little deeper into how facility menus are referenced and output into Metalsmith/content-build pages, so we know better how to proceed for next-build.

Acceptance Criteria

CMS Team

Please check the team(s) that will do this work.

timcosgrove commented 2 years ago

How this currently works:

  1. content-build pulls the entityLabel string of fieldOffice (or equivalent) for a given page, i.e. 'VA Hudson Valley health care' (https://github.com/department-of-veterans-affairs/content-build/blob/main/src/site/stages/build/drupal/page.js#L229)
  2. content-build scans the entire graphQL response to try and find a top-level item in the JSON object that has a name with that string, ie. someTopLevelObject.name == 'VA Hudson Valley health care'. It assumes that there will only be one of these, and that that item will be a menu object. It is dependent on the string matching exactly. (https://github.com/department-of-veterans-affairs/content-build/blob/main/src/site/stages/build/drupal/page.js#L234)
  3. The page can then use that facility sidebar menu data in its render. (https://github.com/department-of-veterans-affairs/content-build/blob/main/src/site/stages/build/drupal/page.js#L243)

(added links to where in content-build this menu selection happens. In this function page is the json structure of the current page being rendered; contentData is the entire GraphQL response.

So in a sense, the facility sidebar menus are already tied to a given VAMC/system's pages through field_office. It's just, it is dependent on there being a menu object that happens to have that same name. As an example,

  1. This page has an office connected to it: https://www.va.gov/northern-california-health-care/programs/covid-19-vaccines/
  2. That office name is 'VA Northern California health care'
  3. There also happens to be a menu that has the name 'VA Northern California health care'.
  4. This string is used to tie that menu to those facility pages.
timcosgrove commented 2 years ago

One hiccup is that, Drupal itself does not tie a menu entity and its associated menu link content entities in a properly referenced way. For example, if we add a reference to a menu as a field on a content type, JSON:API returns this type of structure:

"field_system_menu": {
  "data": {
    "type": "menu--menu",
    "id": "518f7bfb-cdaa-4da3-be5c-a408accd2213",
    "meta": {
      "drupal_internal__target_id": "va-alexandria-health-care"
    }
  },
  "links": {
    "related": {
      "href": "https://va-gov-cms.ddev.site/jsonapi/node/health_care_region_page/178b8006-d7f0-4afc-a15f-1d4b021cbb2f/field_system_menu?resourceVersion=id%3A657872"
    },
    "self": {
      "href": "https://va-gov-cms.ddev.site/jsonapi/node/health_care_region_page/178b8006-d7f0-4afc-a15f-1d4b021cbb2f/relationships/field_system_menu?resourceVersion=id%3A657872"
    }
  }
},

There is not a way for Drupal to make the jump to retrieve the actual menu links. We can take the machine name of the menu from the above response, and use that to find the menu links and retrieve them via a second API call.

One way around this is to use JSON:API Extras' concept of an Enhancer to augment the JSON:API response with the data we need. Enhancers are plugins which take Drupal data and modify it prior to being output in the JSON:API response. Here are examples included with the module: https://git.drupalcode.org/project/jsonapi_extras/-/tree/8.x-3.x/src/Plugin/jsonapi/FieldEnhancer

Given JSON:API output which includes a reference to a specific menu, we can use an Enhancer plugin to retrieve the menu links for that menu and then provide them as part of the JSON:API response.

timcosgrove commented 2 years ago

Some of the code in this block plugin could most likely be refactored to provide the menu link tree to the enhancer: https://github.com/department-of-veterans-affairs/va.gov-cms/blob/main/docroot/modules/custom/va_gov_backend/src/Plugin/Block/SidebarMenusBlock.php

Meaning, refactor the code that retrieves and processes the menu tree into its own files, and make use of it both in this block and in a JSON:API enhancer.

timcosgrove commented 2 years ago
  1. Create an Entity Reference field to menu entities on the VAMC System type (health_care_region_page). Once this is in prod, it should be a mob session task to assign the appropriate menu to each system.
  2. Attempt to grab the menu via next-drupal. See https://github.com/chapter-three/next-drupal/blob/f49b42a1fd7d3f7666622e430dbdb41b7cfdf28b/packages/next-drupal/src/client.ts#L1128 for functionality that may retrieve the menu tree given a menu name.

If 2 is a non starter, there is an alternate route:

  1. Create a JSON:API enhancer which takes an entity reference field like above and renders out the full menu tree as a JSON:API structure. See this comment above for code that can be leveraged and extended for this. The end result should be that the JSON:API response for a VAMC System node contains the full menu tree when the menu is added as a JSON:API include.
  2. Ensure that nodes which reference VAMC System (i.e. nearly all Facility nodes) can load this menu tree via JSON:API. This may just be a matter of confirming that the include mechanism works correctly.
timcosgrove commented 2 years ago

https://github.com/department-of-veterans-affairs/va.gov-cms/issues/9520 for the first part of this.