Overview
The goal is to implement a flexible and configurable menu that can be displayed in a specified order based on configuration settings. Currently, the order of menu entries (both top-level and sub-level) is determined by the sequence in which openIMIS modules are loaded on the frontend. This configuration will be integrated into a larger global configuration that is loaded during app initialization. Moreover, the functionality should allow the creation of entirely new menu entries. However, submenus can only be linked to existing ones that are predefined within the application, ensuring consistency with the application’s internal structure.
The aim is to enhance the current implementation of menu entry population by introducing a new property called POSITION for both the MainMenuComponent and individual menu entries (referred to as submenus). Currently, the order of menu entries cannot be modified by non-technical users; only technical users can adjust it by altering the order of modules in the openimis.json file (assembly frontend - openimis-fe_js). The proposed change will enable non-technical implementers to configure the menu order easily and intuitively. Additionally, the functionality will include the possibility to create entirely new menu entries, while submenus can only be linked to existing ones within the application, ensuring seamless integration.
Strategy
Component MainMenuCompoment (Openimis-fe-core_js)
The additional property should be added. It might be called ‘menuId’
class MainMenuContribution extends Component { state = { expanded: false, anchorRef: React.createRef(), }; <......> MainMenuContribution.propTypes = { header: PropTypes.string.isRequired, entries: PropTypes.array.isRequired, history: PropTypes.object.isRequired, // additional property after applying the idea menuId: PropTypes.object.isRequired, };
Above, the definition of this component is provided. Header: Contains all information about the main menu entry that will be added to the navigation bar. Entries: Represents all subitems of the main menu element (see the "Entries" section below).
Components are typically added to the application through contribution points. In
index.js
, the appropriate contribution should be declared as follows:'core.MainMenu': [GrievanceMainMenu],
In
'core.MainMenu'
, theMainMenu
component is added to the entire list of menu items that are processed within theRequireAuth.js
component (see further details in another section related to this).Examples of extensions of the
MainMenuComponent
can be found in applications such as'GrievanceMainMenu'
.In
'core.MainMenu'
, theMainMenu
component is added to the entire list of menu items that are processed within theRequireAuth.js
component (see further details in another section related to this).Examples of extensions of the
MainMenuComponent
can be found in applications such as'GrievanceMainMenu'
.To establish a connection between
id
from the configuration file and the source code, additional adjustments should be implemented in eachMainMenu
entry, such asClaimMainMenu
. Here's an example of how it should be structured:
return ( <MainMenuContribution {...this.props} header={formatMessage(this.props.intl, "claim", "mainMenu")} icon={<ScreenShare />} entries={entries} menuId="ClaimMainMenu" /> );
Entries array (all modules)
An entry is defined with a root, along with associated permissions and an icon that represents the type of functionality it provides.
Structure after change:
The new sorting mechanism based on the
position
field should be implemented before processing the display of elements. This logic must be applied prior to the existing expression responsible for rendering elements in theMainMenuComponent
.Moreover, we need to relocate some entries and assign
id
s from specificMainMenu
definitions into theindex.js
file of their respective modules. This will allow them to be globally accessible via the modules manager, enabling the flexibility to move subitems from oneMainMenu
to another. For example, in theclaim
module'sindex.js
."claim.MainMenu": [ { text: <FormattedMessage module="claim" id="menu.healthFacilityClaims" />, icon: <Keyboard />, route: "/claim/healthFacilities", id: "claim.healthFacilityClaims", filter: (rights) => rights.some((r) => r >= RIGHT_CLAIMREVIEW && r <= RIGHT_PROCESS), }, { text: <FormattedMessage module="claim" id="menu.reviews" />, icon: <Assignment />, route: "/claim/reviews", id: "claim.reviews", filter: (rights) => rights.some((r) => r >= RIGHT_CLAIMREVIEW && r <= RIGHT_PROCESS), }, ],
Additionally, a
filter
must also be added to ensure permissions are correctly applied, allowing menu items to be displayed only for users with specific roles.
RequireAuth.js (openimis-fe-core_js)
Currently, on line 320, the main menu items are added through a contribution point.
{isAppBarMenu && ( <Hidden smDown implementation="css"> <Contributions {...others} menuVariant="AppBar" contributionKey={MAIN_MENU_CONTRIBUTION_KEY}> <div onClick={setOpen.off} /> </Contributions> </Hidden> )}
MAIN_MENU_CONTRIBUTION_KEY=core.MainMenu
The goal is to introduce a new component called
MainMenuBar
(withinopenimis-fe_core
), which will handle the preprocessing of all loaded main menu items. This component will be responsible for sorting the menu items based on theirposition
property before rendering them. Moreover here the new menu entry could be created when there is no matching ids of menu.
const MainMenuBar = () => { const menuList = modulesManager.getContribs(MAIN_MENU_CONTRIBUTION_KEY); const sortedMenuList = sort(menuList); return sortedMenulist.map((component) => <Here rendering>)) }
Render is processed by this code:
<Here rendering> should be replaced by this line:
The new
Navbar
component should be integrated intoRequireAuth
as a replacement for the existing code responsible for displaying menu items. This will streamline the handling of menu item processing and ensure they are sorted based on theirposition
property.Please keep in mind the necessary adjustments for rendering when the
MenuLeft=True
option is enabled in the configuration.
Structure of Config for prioritization of items in menu:
the exact name of the menu component must be specified, and the position should be assigned as a numeric value (e.g., 1, 2, 3, 4, etc.).
When the
id
does not match an existingMainMenu
component, a new menu entry must be created to ensure proper integration and functionality. This allows for the dynamic addition of menu entries when no matching component is found.For Menu Entries: The same structure and approach should be applied to menu entries.
Code Implementation: In the code, ensure prioritization is applied based on the configuration integer like position: 1.
We should compare the string name of the component instead of the object itself, as comparing objects may not produce the expected results. Therefore, we need to make changes at the
index.js
level in each module where we attach a specificMainMenu
to thecore.MainMenu
contribution, such as:
"core.MainMenu": [{ name: 'ClaimMainMenu', component: ClaimMainMenu }],
where name matches the id from configuration.
Additional function in modulesManager.js in openimis-fe_js (assembly)
getMenuEntries() { <To-impplement> } -
The implementation should be added here. The function will be responsible for fetching all menu entries within the system. Ideally, it should retrieve all keys containing .MainMenu except for core.MainMenu and extract the values from those keys. Based on this collection, we should generate a list of available entries within the system.
Summary - what need to do in achieve goal
Define Configuration Structure:
Design the structure of the configuration to store menu priorities at the database level. Ensure this configuration is exposed to the frontend through the backend using GraphQL.
{ "menus": [ { "position": 2 "name": "Dashboard", "icon": "dashboard-icon", "description": "Main dashboard", "submenus": [ { "position":"0", "id": "insuree.listInsuree" }, { "position":"1", "id": "insuree.listFamily" } ] }, { "postion": 1, "name": "Dashboard", "icon": "dashboard-icon", "description": "Main dashboard", "submenus": [ { "position":"0", "id": "insuree.listInsuree" }, { "position":"1", "id": "insuree.listFamily" } ] } ] }
Add Position Properties:
Introduce aposition
property for bothMainMenuComponent
and menuentries
(submenus).Add menuId property for MainMenuContribution: Introduce a
menuId
property forMainMenuComponent
in order to link config with existing MainMenu’s definitions.Update MainMenuContribution Logic:
Modify the logic in theMainMenuContribution
component to process menu entries and subitems based on the newposition
property. Implement sorting logic accordingly.Adjust Logic in RequireAuth.js:
Revise theRequireAuth.js
file to include a new component responsible for sorting menu contributions (calledMainMenu
). Ensure all contributions are loaded only after the sorting operation. Extend this logic to handle submenu items withinentries
arrays too and make them flexible in terms of moving between different MainMenu entries.Integrate Position Configuration:
Implement logic to process priorities from the configuration and compare them to user-defined values (by string).Add Mechanism to pull all entries: mechanism need to be added to pull all entries to enable moving them between various MainMenu entries.
Documentation : Ensure that all mechanisms related to configuring priorities and the sorting logic are thoroughly explained in all relevant documentation. This includes the user guide, technical documentation such as the README file, and the openIMIS wiki on Confluence. Providing clear and comprehensive details in these resources will help users and developers understand and implement the functionality effectively.
Testing:
Thoroughly test the solution across various scenarios to ensure correct behavior and reliability