Strapi: How to create a service to manage help documents?

exFabrica
7 min readApr 19, 2022

--

Welcome back!

Our data is now ready to be imported into the “Help” collection. We need to create a new service to manage the create, read, update and delete operations (C.R.U.D). Let’s go!

Collection update

The first step is to update the “Help” collection “schema.json” to add some useful properties. Open it in “api/src/plugins/awesome-help/server/content-types/help” and add these properties:

the new “Schema.json“
  • “contentType” property represents the crawled Content-Type, for example: “api::article.article”.
  • “path” property defines the current path of the crawled field. This is a computed field.
  • “helpContent” property will contain your contextual help text.
  • “fieldName” property is the name of the crawled field.
  • “containerType” property defines the current container type of the crawled field (see below for values).
  • “zoneName” property defines the current zone name of the crawled field.
  • “componentName” property defines the component name of the crawled field.

To understand how the “parser” service works, let’s take a simple example:

“title” field in Article collection

The “title” field will be parsed by the “parser” service like :

  • contentType: “api::article.article”
  • fieldName: “title”
  • containerType: “default”
  • zoneName: null
  • component: null
  • path : “api::article.article/title” (computed field)

Let’s take a more complex example:

“metaTile” field in Article/seo collection

The “metaTitle” field will be parsed by the “parser” service like :

  • contentType: “api::article.article”
  • fieldName: “metaTitle”
  • containerType: “component” (this is a component inside the Content-Type)
  • zoneName: null
  • component: “seo” (the name of the component)
  • path : “api::article.article/seo/metaTitle” (computed field)

Finally, let’s take a full complex example:

The “label” field in Zone block inside “relatedArticles” component inside “header” component

The “label” field will be parsed by the “parser” service like :

  • contentType: “api::article.article”
  • fieldName: “label”
  • containerType: “nestedComponentInComponentInZone” (this is a component inside a component inside a zone)
  • zoneName: “blocks”
  • component: “header” (the name of the component)
  • path : “api::article.article/blocks/related-articles/header/label” (computed field)

The “containerType” field uses different values to target fields:

  • “default”: the field is present at the root of Content-Type,
  • “component”: the field is present in a component at the root of Content-Type
  • “componentInZone”: the field is present in a zone component.
  • “nestedComponentInComponentInZone”: the field is present in nested component in a zone component.

The parser doesn’t treat more complex imbrication. The maximum of field detection is inside zone/component/component.

Help Service

In “api/src/plugins/awesome-help/server/services”, open the file “help.js”. If you remember, inside, we have already created a “findMany” function. Take the code bellow and paste-it into the file:

Help Service

We create a new constant “query” to directly reference the “query” service instance.

strapi.db.query(‘plugin::awesome-help.help’);

This instance can request the Strapi database to make data request.

Notice the update of “findMany” function: we add a default sort on the query request with this instruction before each query call to sort the result by “Content-Type”:

params[“orderBy”] = “contentType”;

All other functions are self-documented and we use directly the “query” service to make the targeted call:

  • “findOne” gets only one help entity,
  • “count” counts help entities,
  • “createMany” creates many Help entities in the same call,
  • “create” creates one help entity,
  • “update” updates one help entity,
  • “deleteAll” deletes all help entities (notice the construction of the where condition),
  • “deleteOne” deletes one help entity.

For the Admin UI part, we need to expose only two functions: “findMany” and “update”. The first one to populate the list and second to update entities from the modal window.

The updated controller code:

Help Controller

Like the service references the “query” instance object, we add a constant to reference the “Help” service. Notice the error management in the “update” function with this instruction:

ctx.throw(500, err);

The updated route code:

Help Route

The route needs to be updated: the type of route needs to be change from “content-api” to “admin” to be called from admin UI.

The help API is done!

Parser service

We have updated the “Parser” service:

Parser Service updated

We made some refactoring/renaming to maximize the single responsibility of each function. A function with a good name is better than 10 lines of comments. And finally, we add some new functions:

  • “checkStructureHasChanged” checks if the Strapi Content-Type structure has changed.
  • “checkFieldsToDelete”: checks if some old Content-Type fields need to be deleted.
  • “checkFieldsToCreate”: checks if new Content-Type fields need to be created.
  • “synchronize”: synchronizes the Strapi Content-Type structure from stored items with new crawled ones (with the help of “checkFieldsToDelete” and “checkFieldsToDelete” functions).
  • “mapHelpEntitiesFromAnalysedResults”: maps the Content-Type analysis objects to “Help” entities objects.
  • “createHelpEntities”: creates in Strapi DB the new “Help” entities. We used the new “Help” service “createMany” functions to store item into DB.
  • “getPath”: this tool function creates the relative path of the field to memorize it into “Help” entities.

If you look the update of the main function “parse”: we crawl the Content-Type fields and we store them into “Help” collection.

Now two functions are exposed through the “Parser” service: “parse” and “checkStructureHasChanged”.

Later in this story, we’ll use the new “checkStructureHasChanged” to make some cool stuffs.

We also updated the “Parser” controller and the “Parser” route to expose the new function “checkStructureHasChanged”.

Finally, “Help” API and “Parser” API are now ready to be used by the Admin UI: we need to jump into Admin API part to update the UI and use real API calls!

Admin UI

The first actions to do is to update the “Parser” API proxy with the “check” function and to create the new “Help” API proxy.

Parser Proxy update

Open the “api/src/plugins/awesome-help/admin/src/pages/HomePage/index.js” and put the code bellow:

Homepage update

We add “useEffect” hook to:

  • Get all Help entities from help collection and fill the REACT state: results with the “setResults” function.
  • Check if the Strapi structure has changed. In this case, a <BOX> panel displays a warning message.

The “handleSubmit” function is also updated to call “parse” function of “Parser” API and displays the result into the <HelpTable> component with the affectation of REACT state results with the “setResults” function.

<HelpTable> component update:

HelpTable update

We implemented a new function “refreshDataGrid” to refresh the DataGrid after a “Help” entity update.

The “handleSave” use the “Help” proxy to update the “Help” entity from the <ModalForm> component. Notice the use of “toggleNotification” Strapi function to make UI feedback.

It’s time to test the new UI! Compile the project and launch it with:

yarn admin

Open Awesome Help plugin and click on “Scan your Strapi internal structure”:

Before scanning
After scanning

The DataGrid is now populated with all discovered Content-Types fields.

Click on the “edit” button of any line, fill the “Contextual help content” field and “Save”.

The ModalForm component in action
The “help” entity is now saved in Strapi database!

Great job! Now, the “Help” entity is stored into Strapi database. To check, go to Content Manager and click on “Help” collection and check if your change is also present in this screen!

We also need to check that if a content manager/developer changes the structure of Strapi then the changes are applied to the collection.

Go to “Content-Type” builder and select the “Article” collection. Add a field with “Add another field”:

Adding a field in ContentType Article

Select “Text” field and name it “myTextField”.

the Strapi field modal creation

You can add multiple fields, as you want.

Now go to “Awesome Help” plugin:

Strapi Structure changed!

You are notified that Strapi structure has changed. Click, again, “Scan your Strapi internal structure” button.

My new field are here!

Return on the “Content builder” and remove the new fields. If you return on the plugin, the structure change will be detected!

Mission complete!

We finalize the “Help” and the “Parser” APIs, the Strapi structure is now analyzed and stored and we can add contextual help! We can think about the next part : How to create a set of components and inject them to Strapi Admin website?

Back to previous article: How to craw all Content-Types and get text or numeric properties?

Back to the table of contents: A Strapi V4 plugin from scratch to production

And don’t forget our GIT to get the code: https://github.com/ExFabrica/strapi-stories/tree/develop/part-5

See U!

--

--