Navigation between objects
Prerequisite: You must be familiar with the Syntax used in Tutorials and have already created an extension.
In this tutorial, we will add on some objects detail, 2 buttons allowing to navigate to the previous and to the next object.
-
The scope of objects in which you can navigate is defined by
-
one (code) which must be the same as the value of the current object, for eg. Navigate within the persons of the same organization
-
a single attribute filter (filter), for eg, Navigate only on active persons
-
an order (order), for eg Navigate using the person's email alphabetic order
-
Configuration
Navigation between objects can be enabled in iTop.
For each class you can only define a single navigation rule:
-
code optional must be a valid scalar attribute code for the class. It defines the group in which the navigation will be proposed, all objects having the same value as the displayed object for this field.
-
filter optional allow to reduce the objects on which we will navigate, for example reducing the list to the active one only.
-
code mandatory attribute code
-
operator optional default:
=
egal.>
,>=
,<
,<=
,!=
are supported -
value optional default:
''
empty string
-
-
order optional default:
id
. It's a scalar attribute code of the class. It defines the order in which you will navigate on the objects. For now it supposes that the values are unique on that field, duplicates are ignored/skipped.
- Configuration
-
$MySettings = array( // shortcut_actions: Actions that are available as direct buttons next to the "Actions" menu // default: 'UI:Menu:Modify,UI:Menu:New' 'shortcut_actions' => 'UI:previous:object,UI:next:object,UI:Menu:Modify,UI:Menu:New', ... $MyModuleSettings = array( 'combodo-object-navigation' => array( 'classes' => array( 'UserRequest' => array( // Must be a valid class name 'code' => 'org_id', // Must be a code attribute of the class 'filter'=> array('code'=>'status','value'=>'closed','operator'=>'!='), ), 'WorkOrder' => array( 'code' => 'ticket_id', 'filter'=> array('code'=>'status','value'=>'closed','operator'=>'!='), 'order' => 'start_date', ), 'Team' => array( 'code' => 'org_id', 'filter'=> array('code'=>'status','value'=>'active'), 'order'=>'name', ), 'Person' => array( 'code' => 'org_id', 'filter'=> array('code'=>'status','value'=>'active'), 'order'=>'name', ), ) );
Extension code
- main.php
-
class ObjectNavigationMenuExtension implements iPopupMenuExtension { // Classes for which we want a navigation, and for each the attributecode which must be fixed (identical to current object) static public function GetConfig() { return MetaModel::GetModuleSetting('combodo-object-navigation', 'classes', array()); } public static function EnumItems($iMenuId, $param) { $aResult = array(); $aClassCode = static::GetConfig(); switch($iMenuId) { case iPopupMenuExtension::MENU_OBJDETAILS_ACTIONS: // Console only $sClass = get_class($param); if (array_key_exists($sClass, $aClassCode)) { $sAttCode = $aClassCode[$sClass]['code']; $sOrder = array_key_exists('order', $aClassCode[$sClass]) ? $aClassCode[$sClass]['order'] :'id'; $sOrderValue = ($sOrder === 'id') ? $param->GetKey() : $param->Get($sOrder); $bFilter = false; if (array_key_exists('filter', $aClassCode[$sClass])) { $sFilterCode = array_key_exists('code', $aClassCode[$sClass]['filter']) ? $aClassCode[$sClass]['filter']['code'] : ''; $sFilterValue = array_key_exists('value', $aClassCode[$sClass]['filter']) ? $aClassCode[$sClass]['filter']['value'] : ''; $sFilterOperator = array_key_exists('operator', $aClassCode[$sClass]['filter']) ? $aClassCode[$sClass]['filter']['operator'] : '='; $bFilter = MetaModel::IsValidAttCode($sClass, $sFilterCode); } foreach ( ['>','<'] AS $sOperator) { $bAsc = ($sOperator === '>') ? true : false; $oSearch = new DBObjectSearch($sClass); if (MetaModel::IsValidAttCode($sClass, $sAttCode)) $oSearch->AddCondition($sAttCode, $param->Get($sAttCode), '='); if (($sOrder === 'id') || MetaModel::IsValidAttCode($sClass, $sOrder)) $oSearch->AddCondition($sOrder, $sOrderValue, $sOperator); if ($bFilter) $oSearch->AddCondition($sFilterCode, $sFilterValue, $sFilterOperator); $oSet = new DBObjectSet($oSearch, array($sOrder => $bAsc),[],null,3); // $oSet->OptimizeColumnLoad(array($sClass => array('id'))); $oObj = $oSet->Fetch(); if (is_object($oObj)) { if ($sOperator === '>') { $oItem = new URLButtonItem( 'UI:next:object', 'Next', utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=details&class='.get_class($oObj).'&id='.$oObj->GetKey(), '_top' ); $oItem->SetIconClass('fas fa-caret-right'); $oItem->SetTooltip("Switch to the next logical object"); } elseif ($sOperator === '<') { $oItem = new URLButtonItem( 'UI:previous:object', 'Previous', utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=details&class='.get_class($oObj).'&id='.$oObj->GetKey(), '_top' ); $oItem->SetIconClass('fas fa-caret-left'); $oItem->SetTooltip("Switch to the previous logical object"); } $aResult[] = $oItem; } } } break; } return $aResult; } }
latest/customization/nextobject.txt
· Last modified: 2025/05/20 16:14 by 127.0.0.1