Body → Part: Customized title A-Z
Context
The context is provided in the Epic &2 and Table of contents building user stories in #1458 (closed).
NCBI did an analysis of their TOCs to find out what automatic ordering cases could be developed to reduce the need for users to manually order books. Each new ordering option is a separate issue linked below -- each to be developed in the priority order specified.
Proposal
Extend the options supported by including:
Book division | Ordering rule |
---|---|
Body → Part (optional) | Customised title A-Z |
See Tab 2 of BCMS_TOC_Chapters_Sorting_Anaysis for details on the metadata nodes that are relevant to get the order values.
Sample content
Final Rendered TOC Example: https://www.ncbi.nlm.nih.gov/books/NBK65083/
Note: the rendered example at end has one part not A-Z
Sample converted chapter XML file:
N/A - nothing to key off as parts are not currently files to process
Ordering spec
XML element used to order content and target to write in TOC.XML
N/A - nothing to key off as parts are not currently files to process
Example TOC.XML entry
<toc-div content-type="part">
<toc-title-group>
<title>Eczema</title>
</toc-title-group>
<toc-entry>
<title>Acetato de medroxiprogesterona de depósito (Depo Provera®)</title>
<nav-pointer><related-object document-id="depot-medroxyprogesterone-acetate-sp" document-type="chapter">
<?xml_file depot-medroxyprogesterone-acetate-sp.xml?>
</related-object></nav-pointer>
</toc-entry>
Design
Current UI
The following currently exist in the organisation Book Templates for chapter-processed books, which gets applied to Book Settings.
Design amendment
There is a design amendment needed to support additional part ordering options. When the 'Group chapters in parts' toggle is turned on, the user will see an addition dropdown to set the part ordering
Text for the dropdown:
A > Z
Acceptance criteria
[NCBI to provide]
Definition of ready
-
BCMS User Story / Context has been well defined -
The priority of the user story is specified and agreed -
Digital assets added (design, database scheme, mockups etc if relevant) -
Coko Technical Proposal approved by NCBI -
Testable Acceptance Criteria approved by NCBI -
Estimate of effort to complete (time or points) -
The issue has been broken down into development tasks (if necessary) -
Requirements Clarified -
The product owner and development team agree that the user story is ready for development -
NCBI adds “Dev_Ready”
Definition of done
-
All coding tasks are finished and implemented -
QA approved -
Deployed and tested on “ncbidev” (by Coko team) -
Deployed and tested on “ncbi” (by NCBI team) -
Acceptance Criteria Met
Implementation
Some background info for this to make sense :
We have two tables Divisions and BookComponents . A book has 3 divisions (Front , Body, Back) To each record there is an array field bookComponents that saves the id of the bookComponents that leave in the bookComponent table This is the field where we save the ordering of the bookComponents. The same happens for the BookComponents (Parts) that have other bookComponents under them, there is a field called bookComponents that keeps the order of the ids of other bookComponents (referenced to the same table).
So in our case this is the flow that is happening already:
- user opens the settings modal of a book and updates the order settings to the value he wants for example to
Arabic numeral label descending
. - That means will trigger an update to the settings of that Book which will in turns execute the the orderService functionality. (This works already nothing to change ) You can check that in this file : server/api/graphql/bookComponent/bookComponent.resolvers.js at line 524.
- By executing this Service an update will happen automatically for that specific Record (Model) and will update the list (in our above example that will update the bookComponents column of either the division or the bookComponent / part).
Order Service Overview
So For this issue to work we need to make use of the OrderService class. which is here server/services/orderService/orderService.js
. The orderService takes as arguments the model
(Book, BookComponent , etc), and based on the configuration we have implemented already in the Model does the ordering. So for example in the model BookComponent (server/models/bookComponent/bookComponent.js)
you will see a static function orderMappings
this takes care of the whole ordering . in That function we configure the identifiers of the Model the fields with the list we want to order (see above bookComponents field) and the field that should be checked for the ordering we want to do for each case (Arabic numeral, Title A-z, etc). Sometimes that field needs some manipulation before can be ordered and for that we have a custom function that we can run before the ordering, For example we want to order by Number 1,2,3, etc, but the field is in the following format: Part 1, Part 2, Part 3 etc.
This custom function is located in line 46 of the BookComponent Model (And this where we need to add the extra code for this feature to work).
What we need to add :
This the predicate function :
predicate: {
modelClass: Book,
idColumn: 'id',
foreignColumn: 'bookId',
field: book => {
const value = (book.settings.toc || {}).order_chapters_by || 'manual'
if (value === 'number')
return {
field: 'metadata.chapter_number',
type: 'Number',
value: v => (v ? v.replace(/\D/g, '') : 0),
}
if (value === 'title')
return {
field: 'title',
type: 'String',
value: v => {
return v === 'Untitled' ? null : v
},
}
return {
field: value,
type: 'String',
}
},
},
The value variable is the value that the user saves and wants to perform the ordering . So for example when the user saves the order as title
the service will trigger this function and will do the ordering based the return object
return {
field: 'title',
type: 'String',
value: v => {
return v === 'Untitled' ? null : v
},
}
and before performing the ordering will execute the value custom function that will normalize a little bit the values (example with Part 1, Part 2, etc.).
So all we need is to add at the field, the ordering cases that come from the ui (title, number) and return the field we want to compare for the ordering and the type.
Currently we support two Types at the OrderService 'String' , "Number" that will be enough for this issue.
Alternative approaches (if applicable)
Scheduling
- Milestone:
- Iteration:
- Dependencies: (list issue numbers if relevant)
- Development estimate (hours):