Action and Group Overriding
Suppose you have two different roles, Manager and Employee, for which you are designing a menu system. The menus will look much the same but with a few key differences. For example, you might have a reports folder that contains different versions of the same report depending on the user. You could define the menus like this:
<
ModuleUiMetaModel
>
<
WebInfo
>
<
WebAction
name
=
"PhoneBook"
>
<
URL
>/oms/public/phonebook.html</
URL
>
</
WebAction
>
<
WebAction
name
=
"PhoneBookForManagers"
>
<
URL
>/oms/public/phonebookformanager.html</
URL
>
</
WebAction
>
<
WebAction
name
=
"ReportA"
>
<!-- omitted -->
</
WebAction
>
<
WebAction
name
=
"ReportB"
>
<!-- omitted -->
</
WebAction
>
<
WebActionGroup
name
=
"Reports"
>
<
WebActionRef
name
=
"PhoneBook"
/> <!-- default version -->
<
WebActionRef
name
=
"ReportA"
/>
<
WebActionRef
name
=
"ReportB"
/>
</
WebActionGroup
>
<
WebActionGroup
name
=
"ReportsForManagers"
>
<
WebActionRef
name
=
"PhoneBookForManagers"
/> <!-- manager version -->
<
WebActionRef
name
=
"ReportA"
/>
<
WebActionRef
name
=
"ReportB"
/>
</
WebActionGroup
>
<
RoleTypeUiConfig
>
<
RoleTypeRef
>
<
CustomRoleTypeName
>Employee</
CustomRoleTypeName
>
</
RoleTypeRef
>
<
WebActionGroupRef
name
=
"Reports"
/>
</
RoleTypeUiConfig
>
<
RoleTypeUiConfig
>
<
RoleTypeRef
>
<
CustomRoleTypeName
>Manager</
CustomRoleTypeName
>
</
RoleTypeRef
>
<
WebActionGroupRef
name
=
"ReportsForManagers"
/>
</
RoleTypeUiConfig
>
</
WebInfo
>
</
ModuleUiMetaModel
>
You can easily see how a situation like this can become difficult to maintain. Currently, the only difference between the two WebActionGroups is one report.
The UI Meta Model allows for you to define an action and then define one or more "variations" for that action which will be resolved based upon the user requesting the menu. As an example, we could define the base "PhoneBook" report and then define a variation that will only be used by the Manager role as in the following example:
<
ModuleUiMetaModel
>
<
WebInfo
>
<
WebAction
name
=
"PhoneBook"
>
<
URL
>/oms/public/phonebook.html</
URL
>
</
WebAction
>
<
WebAction
name
=
"ReportA"
>
<!-- omitted -->
</
WebAction
>
<
WebAction
name
=
"ReportB"
>
<!-- omitted -->
</
WebAction
>
<!-- custom phonebook report for managers -->
<
WebActionVariation
name
=
"PhoneBook"
>
<
Context
property
=
"RoleName"
value
=
"Manager"
/>
<
URL
>/oms/public/phonebookformanager.html</
URL
>
</
WebActionVariation
>
<
WebActionGroup
name
=
"Reports"
>
<
WebActionRef
name
=
"PhoneBook"
/>
<
WebActionRef
name
=
"ReportA"
/>
<
WebActionRef
name
=
"ReportB"
/>
</
WebActionGroup
>
<
RoleTypeUiConfig
>
<
RoleTypeRef
>
<
CustomRoleTypeName
>Employee</
CustomRoleTypeName
>
</
RoleTypeRef
>
<
WebActionGroupRef
name
=
"Reports"
/>
</
RoleTypeUiConfig
>
<
RoleTypeUiConfig
>
<
RoleTypeRef
>
<
CustomRoleTypeName
>Manager</
CustomRoleTypeName
>
</
RoleTypeRef
>
<
WebActionGroupRef
name
=
"Reports"
/>
</
RoleTypeUiConfig
>
</
WebInfo
>
</
ModuleUiMetaModel
>
This allows us to maintain a single "Reports" folder which is used in both RoleTypeUiConfig. With this configuration, we could define additional variations based on many different properties (in ascending order of specificity): RoleName, RoleTypeName, EntName, OrgName, or even as specific as ValueChainId.
What if we wanted to add another report that only managers should get? Without any kind of variation at the WebActionGroup level, you would end up with a UI Meta Model which looks like this:
<
ModuleUiMetaModel
>
<
WebInfo
>
<
WebAction
name
=
"PhoneBook"
>
<!-- omitted -->
</
WebAction
>
<
WebAction
name
=
"ReportA"
>
<!-- omitted -->
</
WebAction
>
<
WebAction
name
=
"ReportB"
>
<!-- omitted -->
</
WebAction
>
<!-- manager-only report -->
<
WebAction
name
=
"MyEmployeesReport"
>
<!-- omitted -->
</
WebAction
>
<!-- custom phonebook report for managers -->
<
WebActionVariation
name
=
"PhoneBook"
>
<
Context
property
=
"RoleName"
value
=
"Manager"
/>
<
URL
>/oms/public/phonebookformanager.html</
URL
>
</
WebActionVariation
>
<
WebActionGroup
name
=
"Reports"
>
<
WebActionRef
name
=
"PhoneBook"
/>
<
WebActionRef
name
=
"ReportA"
/>
<
WebActionRef
name
=
"ReportB"
/>
</
WebActionGroup
>
<
WebActionGroup
name
=
"ReportsForManagers"
>
<
WebActionRef
name
=
"PhoneBook"
/>
<
WebActionRef
name
=
"ReportA"
/>
<
WebActionRef
name
=
"ReportB"
/>
<
WebActionRef
name
=
"MyEmployeesReport"
/>
</
WebActionGroup
>
<
RoleTypeUiConfig
>
<
RoleTypeRef
>
<
CustomRoleTypeName
>Employee</
CustomRoleTypeName
>
</
RoleTypeRef
>
<
WebActionGroupRef
name
=
"Reports"
/>
</
RoleTypeUiConfig
>
<
RoleTypeUiConfig
>
<
RoleTypeRef
>
<
CustomRoleTypeName
>Manager</
CustomRoleTypeName
>
</
RoleTypeRef
>
<
WebActionGroupRef
name
=
"ReportsForManagers"
/>
</
RoleTypeUiConfig
>
</
WebInfo
>
</
ModuleUiMetaModel
>
Again, we are back in a situation where you would need to define a separate WebActionGroup for each role when the only difference is one additional report.
Fortunately, you can also define variation on WebActionGroups, as the next example shows:
<
ModuleUiMetaModel
>
<
WebInfo
>
<
WebAction
name
=
"PhoneBook"
>
<!-- omitted -->
</
WebAction
>
<
WebAction
name
=
"ReportA"
>
<!-- omitted -->
</
WebAction
>
<
WebAction
name
=
"ReportB"
>
<!-- omitted -->
</
WebAction
>
<!-- manager-only report -->
<
WebAction
name
=
"MyEmployeesReport"
>
<!-- omitted -->
</
WebAction
>
<!-- custom phonebook report for managers -->
<
WebActionVariation
name
=
"PhoneBook"
>
<
Context
property
=
"RoleName"
value
=
"Manager"
/>
<
URL
>/oms/public/phonebookformanager.html</
URL
>
</
WebActionVariation
>
<
WebActionGroup
name
=
"Reports"
>
<
WebActionRef
name
=
"PhoneBook"
/>
<
WebActionRef
name
=
"ReportA"
/>
<
WebActionRef
name
=
"ReportB"
/>
</
WebActionGroup
>
<
WebActionGroupVariation
name
=
"Reports"
>
<
Context
property
=
"RoleName"
value
=
"Manager"
/>
<
WebActionRef
name
=
"PhoneBook"
/>
<
WebActionRef
name
=
"ReportA"
/>
<
WebActionRef
name
=
"ReportB"
/>
<
WebActionRef
name
=
"MyEmployeesReport"
/>
</
WebActionGroupVariation
>
<
RoleTypeUiConfig
>
<
RoleTypeRef
>
<
CustomRoleTypeName
>Employee</
CustomRoleTypeName
>
</
RoleTypeRef
>
<
WebActionGroupRef
name
=
"Reports"
/>
</
RoleTypeUiConfig
>
<
RoleTypeUiConfig
>
<
RoleTypeRef
>
<
CustomRoleTypeName
>Manager</
CustomRoleTypeName
>
</
RoleTypeRef
>
<
WebActionGroupRef
name
=
"Reports"
/>
</
RoleTypeUiConfig
>
</
WebInfo
>
</
ModuleUiMetaModel
>
Note that when defining WebActionGroupVariations, you can include any child elements you would normally include in a WebActionGroup, including WebActionRefs, WebActionGroups, WebActionGroupRefs, and MenuDividers.
With this new variation, we can have one WebActionGroup which contains different actions based on which user is looking at it. Additionally, you can see that both variations, the default, and the Manager version, contain a WebActionRef to an action that also has a variation. All of these variations will be resolved when the UI requests the menu; all variations will be resolved to the most specific variation. This allows for a high degree of flexibility and reuse when you define your menus.
WebActionGroupInjection
WebActionGroupInjection is a better version of WebActionGroupVariation. Using WebActionGroupInjection, developers can add (inject) menus in existing WebActionGroups:
<
WebActionGroupInjection
name
=
"Reports"
>
<
Context
property
=
"RoleName"
value
=
"Manager"
/>
<
WebActionRef
name
=
"MyEmployeesReport"
/>
</
WebActionGroupInjection
>
With this configuration, the MyEmployeesReport will be added as the last menu in the Reports menu group for the Manager role. If a menu needs to be added in between menu lists, then use the following:
<
WebActionGroupInjection
name
=
"Reports"
>
<
Context
property
=
"RoleName"
value
=
"Manager"
/>
<
WebActionRef
name
=
"MyEmployeesReport"
insertBefore
=
"ReportB"
/>
</
WebActionGroupInjection
>
In the above example, the MyEmployeesReport is added before the ReportB menu.
Unlike WebActionGroupVariation, multiple modules can define WebActionGroupInjection for the same WebActionGroup, and all qualified injections are applied. Qualified injections are WebActionGroupInjection which contain <Context> information that is more specific for the logged-in user.
WebActionGroupVariation and WebActionGroupInjection can be specified in the module that declares the WebActionGroup or can be added in modules depending upon the WebActionGroup the module contains.
The following table lists the supported values for the Property attribute in <Context>:
Value |
Description |
RoleName |
Specifies the name of the role. For example, CarrierTransportationManager. |
RoleTypeName |
Specifies the role type name. For example, TMS.TRANSPORTATION_MANAGER. |
EntName |
Specifies the enterprise name of the used role. |
OrgName |
Specifies the organization name of the used role. |
ValueChainId |
Specifies the value chain id of the used role. |