Selaa lähdekoodia

- New implementation of the menus: menus are built on the fly and no longer stored in the database...

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@482 a333f486-631f-4898-b8df-5754b55c2be0
dflaven 15 vuotta sitten
vanhempi
commit
4c21be4555

+ 43 - 55
application/itopwebpage.class.inc.php

@@ -174,7 +174,46 @@ EOF
 			}
 			}
 		}
 		}
 		");
 		");
-		$this->DisplayMenu();
+		
+		// Add the standard menus
+		/*
+		 * +--------------------+
+		 * | Welcome            |
+		 * +--------------------+
+		 * 		Welcome To iTop
+		 * +--------------------+
+		 * | Tools              |
+		 * +--------------------+
+		 * 		CSV Import
+		 * +--------------------+
+		 * | Admin Tools        | << Only present if the user is an admin
+		 * +--------------------+
+		 *		User Accounts
+		 *		Profiles
+		 *		Notifications
+		 *		Run Queries
+		 *		Export
+		 *		Data Model
+		 *		Universal Search
+		 */
+		$oWelcomeMenu = new MenuGroup('UI:WelcomeMenu', 0 /* fRank */);
+		new TemplateMenuNode('UI:WelcomeMenu', '../business/templates/welcome_menu.html', $oWelcomeMenu->GetIndex() /* oParent */, 1 /* fRank */);
+		
+		$oToolsMenu = new MenuGroup('UI:AdvancedToolsMenu', 2 /* fRank */);
+		new WebPageMenuNode('UI:CSVImportMenu', '../pages/csvimport.php', $oToolsMenu->GetIndex(), 1 /* fRank */);
+
+		if (userRights::IsAdministrator())
+		{
+			// Add the admin menus
+			$oAdminMenu = new MenuGroup('UI:AdminToolsMenu', 999 /* fRank */);
+			new OQLMenuNode('UI:UserAccountsMenu', 'UI:UserAccountsMenu:Title', 'SELECT URP_Users', $oAdminMenu->GetIndex(), 1 /* fRank */);
+			new OQLMenuNode('UI:ProfilesMenu', 'UI:ProfilesMenu:Title', 'SELECT URP_Profiles', $oAdminMenu->GetIndex(), 2 /* fRank */);
+			new TemplateMenuNode('UI:NotificationsMenu', '../business/templates/notifications_menu.html', $oAdminMenu->GetIndex(), 3 /* fRank */);
+			new WebPageMenuNode('UI:RunQueriesMenu', '../pages/run_query.php', $oAdminMenu->GetIndex(), 8 /* fRank */);
+			new WebPageMenuNode('UI:ExportMenu', '../webservices/export.php', $oAdminMenu->GetIndex(), 9 /* fRank */);
+			new WebPageMenuNode('UI:DataModelMenu', '../pages/schema.php', $oAdminMenu->GetIndex(), 10 /* fRank */);
+			new WebPageMenuNode('UI:UniversalSearchMenu', '../pages/UniversalSearch.php', $oAdminMenu->GetIndex(), 11 /* fRank */);
+		}
 	}
 	}
 	
 	
 	public function AddToMenu($sHtml)
 	public function AddToMenu($sHtml)
@@ -222,62 +261,10 @@ EOF
 		$oContext = new UserContext();
 		$oContext = new UserContext();
 		// Display the menu
 		// Display the menu
 		$oAppContext = new ApplicationContext();
 		$oAppContext = new ApplicationContext();
-		$iActiveNodeId = utils::ReadParam('menu', '');
+		$iActiveNodeId = ApplicationMenu::GetActiveNodeId();
 		$iAccordionIndex = 0;
 		$iAccordionIndex = 0;
-		
-		// 1) Application defined menus
-		$oSearchFilter = $oContext->NewFilter("menuNode");
-		$oSearchFilter->AddCondition('parent_id', 0, '=');
-		$oSearchFilter->AddCondition('type', 'application', '=');
-		// There may be more criteria added later to have a specific menu based on the user's profile
-		$oSet = new CMDBObjectSet($oSearchFilter, array('rank' => true));
-		while ($oRootMenuNode = $oSet->Fetch())
-		{
-			$bResult = $oRootMenuNode->DisplayMenu($this, 'application', $oAppContext->GetAsHash(), true, $iActiveNodeId);
-			if ($bResult)
-			{
-				$this->add_ready_script("$('#accordion').accordion('activate', $iAccordionIndex)");
-			}
-			$iAccordionIndex++;
-		}
-		
-		// 2) User defined menus (Bookmarks)
-		$oSearchFilter = $oContext->NewFilter("menuNode");
-		$oSearchFilter->AddCondition('parent_id', 0, '=');
-		$oSearchFilter->AddCondition('type', 'user', '=');
-		$oSearchFilter->AddCondition('user_id', UserRights::GetUserId(), '=');
-		// There may be more criteria added later to have a specific menu based on the user's profile
-		$oSet = new CMDBObjectSet($oSearchFilter, array('rank' => true));
-		while ($oRootMenuNode = $oSet->Fetch())
-		{
-			$oRootMenuNode->DisplayMenu($this, 'user', $oAppContext->GetAsHash(), true, $iActiveNodeId);
-			if ($bResult)
-			{
-				$this->add_ready_script("$('#accordion').accordion('activate', $iAccordionIndex)");
-			}
-			$iAccordionIndex++;
-		}
-		
-		// 3) Administrator menu
-		if (userRights::IsAdministrator())
-		{
-			$oSearchFilter = $oContext->NewFilter("menuNode");
-			$oSearchFilter->AddCondition('parent_id', 0, '=');
-			$oSearchFilter->AddCondition('type', 'administrator', '=');
-			// There may be more criteria added later to have a specific menu based on the user's profile
-			$oSet = new CMDBObjectSet($oSearchFilter, array('rank' => true));
-			while ($oRootMenuNode = $oSet->Fetch())
-			{
-				$oRootMenuNode->DisplayMenu($this, 'administrator', $oAppContext->GetAsHash(), true, $iActiveNodeId);
-				if ($bResult)
-				{
-					$this->add_ready_script("$('#accordion').accordion('activate', $iAccordionIndex)");
-				}
-				$iAccordionIndex++;
-			}
-		}
 
 
-		$this->AddToMenu("</ul>\n");
+		ApplicationMenu::DisplayMenu($this, $oAppContext->GetAsHash(), $iActiveNodeId);
     }
     }
 
 
 	/**
 	/**
@@ -285,6 +272,7 @@ EOF
 	 */
 	 */
     public function output()
     public function output()
     {
     {
+		$this->DisplayMenu(); // Compute the menu
         foreach($this->a_headers as $s_header)
         foreach($this->a_headers as $s_header)
         {
         {
             header($s_header);
             header($s_header);

+ 363 - 179
application/menunode.class.inc.php

@@ -15,7 +15,7 @@
 //   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 //   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
 
 /**
 /**
- * Persistent class menuNode
+ * Construction and display of the application's main menu
  *
  *
  * @author      Erwan Taloc <erwan.taloc@combodo.com>
  * @author      Erwan Taloc <erwan.taloc@combodo.com>
  * @author      Romain Quetiez <romain.quetiez@combodo.com>
  * @author      Romain Quetiez <romain.quetiez@combodo.com>
@@ -23,231 +23,415 @@
  * @license     http://www.opensource.org/licenses/gpl-3.0.html LGPL
  * @license     http://www.opensource.org/licenses/gpl-3.0.html LGPL
  */
  */
 
 
-require_once('../core/attributedef.class.inc.php');
-require_once('../core/filterdef.class.inc.php');
-require_once('../core/stimulus.class.inc.php');
-require_once('../core/MyHelpers.class.inc.php');
+require_once('../application/utils.inc.php');
+require_once('../application/template.class.inc.php');
 
 
-require_once('../core/cmdbsource.class.inc.php');
-require_once('../core/sqlquery.class.inc.php');
-
-require_once('../core/dbobject.class.php');
-require_once('../core/dbobjectsearch.class.php');
-require_once('../core/dbobjectset.class.php');
-
-require_once('../application/displayblock.class.inc.php');
 
 
 /**
 /**
- * This class manages en entries in the menu tree on the left of the iTop pages
+ * This class manipulates, stores and displays the navigation menu used in the application
+ * In order to improve the modularity of the data model and to ease the update/migration
+ * between evolving data models, the menus are no longer stored in the database, but are instead
+ * built on the fly each time a page is loaded.
+ * The application's menu is organized into top-level groups with, inside each group, a tree of menu items.
+ * Top level groups do not display any content, they just expand/collapse.
+ * Sub-items drive the actual content of the page, they are based either on templates, OQL queries or full (external?) web pages.
+ *
+ * Example:
+ * Here is how to insert the following items in the application's menu:
+ *   +----------------------------------------+
+ *   | Configuration Management Group         | >> Top level group
+ *   +----------------------------------------+
+ *		+ Configuration Management Overview     >> Template based menu item
+ *		+ Contacts								>> Template based menu item
+ *			+ Persons							>> Plain list (OQL based)
+ *			+ Teams								>> Plain list (OQL based)
+ *
+ * // Create the top-level group. fRank = 1, means it will be inserted after the group '0', which is usually 'Welcome'
+ * $oConfigMgmtMenu = new MenuGroup('UI:ConfigurationManagementMenu', 1);
+ * // Create an entry, based on a custom template, for the Configuration management overview, under the top-level group
+ * new TemplateMenuNode('UI:ConfigurationManagementMenu', '../business/templates/configuration_management_menu.html', $oConfigMgmtMenu->GetIndex(), 0);
+ * // Create an entry (template based) for the overview of contacts
+ * $oContactsMenu = new TemplateMenuNode('UI:ContactsMenu', '../business/templates/configuration_management_menu.html',$oConfigMgmtMenu->GetIndex(), 1);
+ * // Plain list of persons
+ * new OQLMenuNode('UI:PersonsMenu', 'UI:PersonsMenu:Title', 'SELECT bizPerson', $oContactsMenu->GetIndex(), 0);
+ * // Plain list of teams
+ * new OQLMenuNode('UI:TeamsMenu', 'UI:TeamsMenu:Title', 'SELECT bizTeam', $oContactsMenu->GetIndex(), 1);
+ *
  */
  */
-class menuNode extends DBObject
+ 
+class ApplicationMenu
 {
 {
-	public static function Init()
-	{
-		$aParams = array
-		(
-			"category" => "gui",
-			"key_type" => "autoincrement",
-			"name_attcode" => "name",
-			"state_attcode" => "",
-			"reconc_keys" => array(),
-			"db_table" => "priv_menunode",
-			"db_key_field" => "id",
-			"db_finalclass_field" => "",
-		);
-		MetaModel::Init_Params($aParams);
-//		MetaModel::Init_AddAttribute(new AttributeExternalKey("change", array("allowed_values"=>null, "sql"=>"changeid", "targetclass"=>"CMDBChange", "jointype"=>"closed")));
-//		MetaModel::Init_AddAttribute(new AttributeExternalField("date", array("allowed_values"=>null, "extkey_attcode"=>"change", "target_attcode"=>"date")));
-		MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributeString("label", array("allowed_values"=>null, "sql"=>"label", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributeString("hyperlink", array("allowed_values"=>null, "sql"=>"hyperlink", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributeString("icon_path", array("allowed_values"=>null, "sql"=>"icon_path", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributeText("template", array("allowed_values"=>null, "sql"=>"template", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributeEnum("type", array("allowed_values"=>new ValueSetEnum('application,user,administrator'), "sql"=>"type", "default_value"=>"application", "is_null_allowed"=>false, "depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributeInteger("rank", array("allowed_values"=>null, "sql"=>"rank", "default_value" => 999, "is_null_allowed"=>false, "depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributeExternalKey("parent_id", array("allowed_values"=>null, "sql"=>"parent_id", "targetclass"=>"menuNode", "is_null_allowed"=>true, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributeExternalField("parent_name", array("allowed_values"=>null, "extkey_attcode"=>"parent_id", "target_attcode"=>"name")));
-		MetaModel::Init_AddAttribute(new AttributeInteger("user_id", array("allowed_values"=>null, "sql"=>"user_id", "default_value" => 0, "is_null_allowed"=>false, "depends_on"=>array())));
-
-		MetaModel::Init_SetZListItems('details', array('parent_id', 'name', 'label', 'hyperlink', 'template', 'rank', 'type')); // Attributes to be displayed for the complete details
-		MetaModel::Init_SetZListItems('list', array('parent_id', 'label', 'rank', 'type')); // Attributes to be displayed for a list
-	}
+	static $aRootMenus = array();
+	static $aMenusIndex = array();
 	
 	
-	public function IsVisible()
+	/**
+	 * Main function to add a menu entry into the application, can be called during the definition
+	 * of the data model objects
+	 */
+	static public function InsertMenu(MenuNode $oMenuNode, $iParentIndex = -1, $fRank)
 	{
 	{
-		return true;
+		$index = count(self::$aMenusIndex);
+		self::$aMenusIndex[$index] = array( 'node' => $oMenuNode, 'children' => array());
+		if ($iParentIndex == -1)
+		{
+			self::$aRootMenus[] = array ('rank' => $fRank, 'index' => $index);
+		}
+		else
+		{
+			self::$aMenusIndex[$iParentIndex]['children'][] = array ('rank' => $fRank, 'index' => $index);
+		}
+		return $index;
 	}
 	}
 	
 	
-	public function GetMenuName()
-	{
-		return Dict::S($this->Get('name'));
-	}
-
-	public function GetMenuIcon()
-	{
-		return $this->Get('icon_path');
-	}
-
-	public function GetMenuLabel()
+	/**
+	 * Entry point to display the whole menu into the web page, used by iTopWebPage
+	 */
+	static public function DisplayMenu(iTopWebPage $oPage, $aExtraParams)
 	{
 	{
-		return Dict::S($this->Get('label'));
+		// Sort the root menu based on the rank
+		usort(self::$aRootMenus, array('ApplicationMenu', 'CompareOnRank'));
+		$iAccordion = 0;
+		$iActiveMenu = ApplicationMenu::GetActiveNodeId();
+		foreach(self::$aRootMenus as $aMenu)
+		{
+			$oMenuNode = self::GetMenuNode($aMenu['index']);
+			$oPage->AddToMenu('<h3><a href="'.$oMenuNode->GetHyperlink($aExtraParams).'">'.$oMenuNode->GetTitle().'</a></h3>');
+			$oPage->AddToMenu('<div>');
+			$aChildren = self::GetChildren($aMenu['index']);
+			if (count($aChildren) > 0)
+			{
+				$oPage->AddToMenu('<ul>');
+				$bActive = self::DisplaySubMenu($oPage, $aChildren, $aExtraParams, $iActiveMenu);
+				$oPage->AddToMenu('</ul>');
+				if ($bActive)
+				{
+					$oPage->add_ready_script("$('#accordion').accordion('activate', $iAccordion);");
+				}
+			}
+			$oPage->AddToMenu('</div>');
+			$iAccordion++;
+		}
 	}
 	}
 	
 	
-	public function GetMenuLink($aExtraParams)
+	/**
+	 * Handles the display of the sub-menus (called recursively if necessary)
+	 * @return true if the currently selected menu is one of the submenus
+	 */
+	static protected function DisplaySubMenu($oPage, $aMenus, $aExtraParams, $iActiveMenu = -1)
 	{
 	{
-		$aExtraParams['menu'] = $this->GetKey(); // Make sure we overwrite the current menu id (if any)
-		$aParams = array();
-		foreach($aExtraParams as $sName => $sValue)
+		// Sort the menu based on the rank
+		$bActive = false;
+		usort($aMenus, array('ApplicationMenu', 'CompareOnRank'));
+		foreach($aMenus as $aMenu)
 		{
 		{
-			$aParams[] = urlencode($sName)."=".urlencode($sValue);
+			$index = $aMenu['index'];
+			$oMenu = self::GetMenuNode($index);
+			$oPage->AddToMenu('<li><a href="'.$oMenu->GetHyperlink($aExtraParams).'">'.$oMenu->GetTitle().'</a></li>');
+			$aCurrentMenu = self::$aMenusIndex[$index];
+			$aChildren = self::GetChildren($index);
+			if ($iActiveMenu == $index)
+			{
+				$bActive = true;
+			}
+			if (count($aChildren) > 0)
+			{
+				$oPage->AddToMenu('<ul>');
+				$bActive |= self::DisplaySubMenu($oPage, $aChildren, $aExtraParams, $iActiveMenu);
+				$oPage->AddToMenu('</ul>');
+			}
 		}
 		}
-		return $this->Get('hyperlink')."?".implode("&", $aParams);
+		return $bActive;
 	}
 	}
-
-	public function GetChildNodesSet($sType = null)
+	/**
+	 * Helper function to sort the menus based on their rank
+	 */
+	static public function CompareOnRank($a, $b)
 	{
 	{
-		$aParams = array();
-
-		if ($sType == 'user')
+		$result = 1;
+		if ($a['rank'] == $b['rank'])
 		{
 		{
-			$sSelectChilds = 'SELECT menuNode AS m WHERE m.parent_id = :parent AND type = :type AND m.user_id = :user';
-			$aParams = array('parent' => $this->GetKey(), 'type' => $sType, 'user' => UserRights::GetUserId());
+			$result = 0;
 		}
 		}
-		elseif ($sType != null)
+		if ($a['rank'] < $b['rank'])
 		{
 		{
-			$sSelectChilds = 'SELECT menuNode AS m WHERE m.parent_id = :parent AND type = :type';
-			$aParams = array('parent' => $this->GetKey(), 'type' => $sType);
+			$result = -1;
 		}
 		}
-		else
-		{
-			$sSelectChilds = 'SELECT menuNode AS m WHERE m.parent_id = :parent';
-			$aParams = array('parent' => $this->GetKey());
-		}
-		$oSearchFilter = DBObjectSearch::FromOQL($sSelectChilds);
-		$oSet = new CMDBObjectSet($oSearchFilter, array('rank' => true), $aParams);
-		return $oSet;
+		return $result;
 	}
 	}
-
-	public function RenderContent(WebPage $oPage, $aExtraParams = array())
+	
+	/**
+	 * Helper function to retrieve the MenuNodeObject based on its ID
+	 */
+	static public function GetMenuNode($index)
 	{
 	{
-		$sTemplate = $this->Get('template');
-		$oTemplate = new DisplayTemplate($sTemplate);
-		$oTemplate->Render($oPage, $aExtraParams);
-		//$this->ProcessTemplate($sTemplate, $oPage, $aExtraParams);
+		return isset(self::$aMenusIndex[$index]) ? self::$aMenusIndex[$index]['node'] : null;
 	}
 	}
 	
 	
-	public function DisplayMenu(iTopWebPage $oP, $sType, $aExtraParams, $bRootLevel = true, $iActiveNodeId = -1)
+	/**
+	 * Helper function to get the list of child(ren) of a menu
+	 */
+	static protected function GetChildren($index)
 	{
 	{
-		$bActive = false;
-		if ($bRootLevel)
-		{
-			$oP->AddToMenu("<h3><a href=\"".$this->GetMenuLink($aExtraParams)."\" title=\"".$this->GetMenuLabel()."\">".$this->GetMenuName()."</a></h3>\n");
-			$oP->AddToMenu("\n<div>\n");
-			$oP->AddToMenu("<p><a href=\"".$this->GetMenuLink($aExtraParams)."\" title=\"".$this->GetMenuLabel()."\">".$this->GetMenuLabel()."</a></p>\n");
-			$oSet = $this->GetChildNodesSet($sType);
-			if ($oSet->Count() > 0)
-			{
-				$oP->AddToMenu("\n<ul>\n");
-				while($oChildNode = $oSet->Fetch())
-				{
-					$bActive |= $oChildNode->DisplayMenu($oP, $sType, $aExtraParams, false /* ! RootLevel */, $iActiveNodeId);
-				}
-				$oP->AddToMenu("</ul>\n");
-			}
-			$oP->AddToMenu("\n</div>\n");
-		}
-		else
+		return self::$aMenusIndex[$index]['children'];
+	}
+	
+	/**
+	 * Helper function to get the ID of a menu based on its name
+	 * @param string $sTitle Title of the menu (as passed when creating the menu)
+	 * @return integer ID of the menu, or -1 if not found
+	 */
+	static public function GetMenuIndexByTitle($sTitle)
+	{
+		$index = -1;
+		foreach(self::$aMenusIndex as $aMenu)
 		{
 		{
-			$oP->AddToMenu("<li><a href=\"".$this->GetMenuLink($aExtraParams)."\" title=\"".$this->GetMenuLabel()."\">".$this->GetMenuName()."</a>");
-			$oSet = $this->GetChildNodesSet($sType);
-			if ($oSet->Count() > 0)
+			if ($aMenu['node']->GetTitle() == $sTitle)
 			{
 			{
-				$oP->AddToMenu("\n<ul>\n");
-				while($oChildNode = $oSet->Fetch())
-				{
-					$bActive |= $oChildNode->DisplayMenu($oP, $sType, $aExtraParams, false /* ! RootLevel */, $iActiveNodeId);
-				}
-				$oP->AddToMenu("</ul>\n");
+				$id = $aMenu['node']->GetIndex();
+				break;
 			}
 			}
-			$oP->AddToMenu("</li>\n");
 		}
 		}
-		$bResult = ($iActiveNodeId == $this->GetKey()) | $bActive;
-		return $bResult;
-	}
-	static public function DisplayCreationForm(WebPage $oP, $sClass, $sFilter, $aExtraParams = array())
-	{
-		$oFilter = DBObjectSearch::unserialize($sFilter);
-		$oP->p('Create a new menu item for: '.$oFilter->__DescribeHTML());
-		$oP->add('<form action="UniversalSearch.php" method="post">');
-		$oP->add('<input type="hidden" name="operation" value="add_menu">');
-		$oP->add('<input type="hidden" name="filter" value="'.$sFilter.'">');
-		$oP->add('<input type="hidden" name="class" value="'.$sClass.'">');
-		$oP->p('Menu Label: <input type="text" name="label" size="30">');
-		$oP->p('Description: <input type="text" name="description" size="30">');
-		$oP->add('<p>Insert after: <select name="previous_node_id">');
-		$aNodes = self::GetMenuAsArray(null, 'user');
-		foreach($aNodes as $aNodeDesc)
-		{
-			$oP->add('<option value="'.$aNodeDesc['id'].'">'.str_repeat('&nbsp;&nbsp;&nbsp;', $aNodeDesc['depth']).$aNodeDesc['label'].'</option>');
-		}
-		$oP->add('</select></p>');
-		$oP->p('<input type="checkbox" name="child_item" value="1"> Create as a child menu item');
-		$oP->p('<input type="submit" value=" Ok "> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<input type="button" class="jqmClose" value="Cancel">');
-		$oP->add('</form>');
+		return $index;
 	}
 	}
 	
 	
-	static public function GetMenuAsArray($oRootNode = null, $sType = 'application', $iDepth = 0)
+	/**
+	 * Retrieves the currently active menu (if any, otherwise the first menu is the default)
+	 * @return MenuNode or null if there is no menu at all !
+	 */
+	static public function GetActiveNodeId()
 	{
 	{
-		$aNodes = array();
-		if (is_object($oRootNode))
+		$iMenuIndex = utils::ReadParam('menu', -1);
+		
+		if ($iMenuIndex  == -1)
 		{
 		{
-			$oChildSet = $oRootNode->GetChildNodesSet($sType);
-			while($oNode = $oChildSet->Fetch())
-			{
-				$aNodes[] = array('depth' => $iDepth, 'id' => $oNode->GetKey(), 'label' => $oNode->GetName());
-				$aNodes = array_merge($aNodes, self::GetMenuAsArray($oNode, $sType, $iDepth+1));
-			}
+			// Make sure the root menu is sorted on 'rank'
+			usort(self::$aRootMenus, array('ApplicationMenu', 'CompareOnRank'));
+			$oFirstGroup = self::GetMenuNode(self::$aRootMenus[0]['index']);
+			$oMenuNode = self::GetMenuNode(self::$aMenusIndex[$oFirstGroup->GetIndex()]['children'][0]['index']);
+			$iMenuIndex = $oMenuNode->GetIndex();
 		}
 		}
-		else
+		return $iMenuIndex;
+	}	
+}
+
+/**
+ * Root class for all the kind of node in the menu tree, data model providers are responsible for instantiating
+ * MenuNodes (i.e instances from derived classes) in order to populate the application's menu. Creating an objet
+ * derived from MenuNode is enough to have it inserted in the application's main menu.
+ * The class iTopWebPage, takes care of 3 items:
+ * +--------------------+
+ * | Welcome            |
+ * +--------------------+
+ * 		Welcome To iTop
+ * +--------------------+
+ * | Tools              |
+ * +--------------------+
+ * 		CSV Import
+ * +--------------------+
+ * | Admin Tools        |
+ * +--------------------+
+ *		User Accounts
+ *		Profiles
+ *		Notifications
+ *		Run Queries
+ *		Export
+ *		Data Model
+ *		Universal Search
+ *
+ * All the other menu items must constructed along with the various data model modules
+ */
+abstract class MenuNode
+{
+	protected $sTitle;
+	protected $index = null;
+	
+	/**
+	 * Create a menu item and inserts it into the application's main menu
+	 * @param string $sTitle Title of the menu (will be looked-up in the dictionnary, for translation)
+	 * @param integer $iParentIndex ID of the parent menu, pass -1 for top level (group) items
+	 * @param float $fRank Number used to order the list, any number will do, but for a given level (i.e same parent) all menus are sorted based on this value
+	 * @return MenuNode
+	 */
+	public function __construct($sTitle, $iParentIndex = -1, $fRank = 0)
+	{
+		$this->sTitle = $sTitle;
+		$this->index = ApplicationMenu::InsertMenu($this, $iParentIndex, $fRank);
+	}
+	
+	public function GetTitle()
+	{
+		return Dict::S($this->sTitle);
+	}
+	
+	public function GetLabel()
+	{
+		return Dict::S($this->sTitle);
+	}
+	
+	public function GetIndex()
+	{
+		return $this->index;
+	}
+	
+	public function GetHyperlink($aExtraParams)
+	{
+		$aExtraParams['menu'] = $this->GetIndex();
+		return $this->AddParams('../pages/UI.php?menu=', $aExtraParams);
+	}
+	
+	public abstract function RenderContent(WebPage $oPage, $aExtraParams = array());
+	
+	protected function AddParams($sHyperlink, $aExtraParams)
+	{
+		if (count($aExtraParams) > 0)
 		{
 		{
-			$oSearchFilter = new DbObjectSearch("menuNode");
-			$oSearchFilter->AddCondition('parent_id', 0, '=');
-			if ($sType != null)
+			$aQuery = array();
+			$sSeparator = '?';
+			if (strpos($sHyperlink, '?') !== false)
 			{
 			{
-				$oSearchFilter->AddCondition('type', $sType, '=');
-				if ($sType == 'user')
-				{
-				    $oSearchFilter->AddCondition('user_id', UserRights::GetUserId(), '=');
-				}
+				$sSeparator = '&';
 			}
 			}
-			$oRootSet = new CMDBObjectSet($oSearchFilter, array('rank' => true));
-			while($oNode = $oRootSet->Fetch())
+			foreach($aExtraParams as $sName => $sValue)
 			{
 			{
-				$aNodes[] = array('depth' => $iDepth, 'id' => $oNode->GetKey(), 'label' => $oNode->GetName());
-				$aNodes = array_merge($aNodes, self::GetMenuAsArray($oNode, $sType, $iDepth+1));
+				$aQuery[] = urlencode($sName).'='.urlencode($sValue);
 			}
 			}
+			$sHyperlink .= $sSeparator.implode('&', $aQuery);
 		}
 		}
-		return $aNodes;
+		return $sHyperlink;
 	}
 	}
+}
+
+/**
+ * This class implements a top-level menu group. A group is just a container for sub-items
+ * it does not display a page by itself
+ */
+class MenuGroup extends MenuNode
+{
+	/**
+	 * Create a top-level menu group and inserts it into the application's main menu
+	 * @param string $sTitle Title of the menu (will be looked-up in the dictionnary for translation)
+	 * @param float $fRank Number used to order the list, the groups are sorted based on this value
+	 * @return MenuGroup
+	 */
+	public function __construct($sTitle, $fRank)
+	{
+		parent::__construct($sTitle, -1 /* no parent, groups are at root level */, $fRank);
+	}
+	
+	public function RenderContent(WebPage $oPage, $aExtraParams = array())
+	{
+		assert(false); // Shall never be called, groups do not display any content
+	}
+}
+
+/**
+ * This class defines a menu item which content is based on a custom template.
+ * Note the template can be either a local file or an URL !
+ */
+class TemplateMenuNode extends MenuNode
+{
+	protected $sTemplateFile;
+	
 	/**
 	/**
-	 * Returns a set of all the nodes following the current node in the tree
-	 * (i.e. nodes with the same parent but with a greater rank)
+	 * Create a menu item based on a custom template and inserts it into the application's main menu
+	 * @param string $sTitle Title of the menu (will be looked-up in the dictionnary for translation)
+	 * @param string $sTemplateFile Path (or URL) to the file that will be used as a template for displaying the page's content
+	 * @param integer $iParentIndex ID of the parent menu
+	 * @param float $fRank Number used to order the list, any number will do, but for a given level (i.e same parent) all menus are sorted based on this value
+	 * @return MenuNode
 	 */
 	 */
-	public function GetNextNodesSet($sType = 'application')
+	public function __construct($sTitle, $sTemplateFile, $iParentIndex, $fRank = 0)
 	{
 	{
-		$oSearchFilter = new DBObjectSearch("menuNode");
-		$oSearchFilter->AddCondition('parent_id', $this->Get('parent_id'));
-		$oSearchFilter->AddCondition('rank', $this->Get('rank'), '>');
-		if ($sType != null)
+		parent::__construct($sTitle, $iParentIndex, $fRank);
+		$this->sTemplateFile = $sTemplateFile;
+	}
+	
+	public function RenderContent(WebPage $oPage, $aExtraParams = array())
+	{
+		$sTemplate = @file_get_contents($this->sTemplateFile);
+		if ($sTemplate !== false)
 		{
 		{
-			$oSearchFilter->AddCondition('type', $sType, '=');
-			if ($sType == 'user')
-			{
-			    $oSearchFilter->AddCondition('user_id', UserRights::GetUserId(), '=');
-			}
+			$oTemplate = new DisplayTemplate($sTemplate);
+			$oTemplate->Render($oPage, $aExtraParams);
+		}
+		else
+		{
+			$oPage->p("Error: failed to load template file: '{$this->sTemplateFile}'"); // No need to translate ?
 		}
 		}
-		$oSet = new DBObjectSet($oSearchFilter, array('rank'=> true)); // Order by rank (true means ascending)
-		return $oSet;
+	}
+}
+
+/**
+ * This class defines a menu item that uses a standard template to display a list of items therefore it allows
+ * only two parameters: the page's title and the OQL expression defining the list of items to be displayed
+ */
+class OQLMenuNode extends MenuNode
+{
+	protected $sPageTitle;
+	protected $sOQL;
+	
+	/**
+	 * Create a menu item based on an OQL query and inserts it into the application's main menu
+	 * @param string $sTitle Title of the menu (will be looked-up in the dictionnary for translation)
+	 * @param string $sPageTitle Title displayed into the page's content (will be looked-up in the dictionnary for translation)
+	 * @param integer $iParentIndex ID of the parent menu
+	 * @param float $fRank Number used to order the list, any number will do, but for a given level (i.e same parent) all menus are sorted based on this value
+	 * @return MenuNode
+	 */
+	public function __construct($sTitle, $sPageTitle, $sOQL, $iParentIndex, $fRank = 0)
+	{
+		parent::__construct($sTitle, $iParentIndex, $fRank);
+		$this->sPageTitle = $sPageTitle;
+		$this->sOQL = $sOQL;
+	}
+	
+	public function RenderContent(WebPage $oPage, $aExtraParams = array())
+	{
+		// The standard template used for all such pages: a (closed) search form at the top and a list of results at the bottom
+		$sTemplate = <<<EOF
+<itopblock BlockClass="DisplayBlock" type="search" asynchronous="false" encoding="text/oql">$this->sOQL</itopblock>
+<p class="page-header"><itopstring>$this->sPageTitle</itopstring></p>
+<itopblock BlockClass="DisplayBlock" type="list" asynchronous="false" encoding="text/oql">$this->sOQL</itopblock>
+EOF;
+		$oTemplate = new DisplayTemplate($sTemplate);
+		$oTemplate->Render($oPage, $aExtraParams);
+	}
+}
+
+/**
+ * This class defines a menu that points to any web page. It takes only two parameters:
+ * - The hyperlink to point to
+ * - The name of the menu
+ * Note: the parameter menu=xxx (where xxx is the id of the menu itself) will be added to the hyperlink
+ * in order to make it the active one, if the target page is based on iTopWebPage and therefore displays the menu
+ */
+class WebPageMenuNode extends MenuNode
+{
+	protected $sHyperlink;
+	
+	/**
+	 * Create a menu item that points to any web page (not only UI.php)
+	 * @param string $sTitle Title of the menu (will be looked-up in the dictionnary for translation)
+	 * @param string $sHyperlink URL to the page to load. Use relative URL if you want to keep the application portable !
+	 * @param integer $iParentIndex ID of the parent menu
+	 * @param float $fRank Number used to order the list, any number will do, but for a given level (i.e same parent) all menus are sorted based on this value
+	 * @return MenuNode
+	 */
+	public function __construct($sTitle, $sHyperlink, $iParentIndex, $fRank = 0)
+	{
+		parent::__construct($sTitle, $iParentIndex, $fRank);
+		$this->sHyperlink = $sHyperlink;
+	}
+
+	public function GetHyperlink($aExtraParams)
+	{
+		$aExtraParams['menu'] = $this->GetIndex();
+		return $this->AddParams( $this->sHyperlink, $aExtraParams);
+	}
+	
+	public function RenderContent(WebPage $oPage, $aExtraParams = array())
+	{
+		assert(false); // Shall never be called, the external web page will handle the display by itself
 	}
 	}
 }
 }
 ?>
 ?>

+ 61 - 44
business/itop.business.class.inc.php

@@ -37,48 +37,6 @@ define('STANDARD_STATUSES', 'production,implementation,obsolete');
  */
  */
 MetaModel::RegisterRelation("impacts");
 MetaModel::RegisterRelation("impacts");
 
 
-class classetest extends cmdbObject
-{
-
-	public static function Init()
-	{
-		$aParams = array
-		(
-			"category" => "bizmodel,searchable",
-			"key_type" => "automincrement",
-			"name_attcode" => "name",
-			"state_attcode" => "",
-			"reconc_keys" => array("name"),
-			"db_table" => "myclasstable",
-			"db_key_field" => "id",
-			"db_finalclass_field" => "",
-			"display_template" => "",
-		);
-		MetaModel::Init_Params($aParams);
-		//MetaModel::Init_InheritAttributes();
-
-		MetaModel::Init_AddAttribute(new AttributeString("aaaa", array("allowed_values"=>null, "sql"=>"mysqlcolumn_to_be_defined", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributeText("b", array("allowed_values"=>null, "sql"=>"mysqlcolumn_to_be_defined", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributeEmailAddress("c", array("allowed_values"=>null, "sql"=>"mysqlcolumn_to_be_defined", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributeIPAddress("d", array("allowed_values"=>null, "sql"=>"mysqlcolumn_to_be_defined", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributePassword("e", array("allowed_values"=>null, "sql"=>"mysqlcolumn_to_be_defined", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributeEnum("f", array("allowed_values"=>null, "sql"=>"mysqlcolumn_to_be_defined", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributeInteger("g", array("allowed_values"=>null, "sql"=>"mysqlcolumn_to_be_defined", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributeBoolean("h", array("allowed_values"=>null, "sql"=>"mysqlcolumn_to_be_defined", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributeDateTime("i", array("allowed_values"=>null, "sql"=>"mysqlcolumn_to_be_defined", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributeDate("j", array("allowed_values"=>null, "sql"=>"mysqlcolumn_to_be_defined", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributeBlob("k", array("depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributePropertySet("l", array("allowed_values"=>null, "sql"=>"mysqlcolumn_to_be_defined", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributeTable("m", array("allowed_values"=>null, "sql"=>"mysqlcolumn_to_be_defined", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributeExternalKey("n", array("targetclass"=>"bizOrganization", "jointype"=>null, "allowed_values"=>null, "sql"=>"mysqlcolumn_to_be_defined", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributeExternalField("o", array("allowed_values"=>null, "extkey_attcode"=>"n", "target_attcode"=>"name", "is_null_allowed"=>true, "depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("p", array("linked_class"=>"class_to_be_defined", "ext_key_to_me"=>"attribute_to_be_defined", "ext_key_to_remote"=>"attribute_to_be_defined", "allowed_values"=>null, "count_min"=>1, "count_max"=>0, "depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributeOQL("q", array("allowed_values"=>null, "sql"=>"mysqlcolumn_to_be_defined", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributeClass("r", array("class_category"=>"bizmodel", "more_values"=>"myvalue1,myvalue2,myvalue3", "sql"=>"mysqlcolumn_to_be_defined", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributeTemplateString("s", array("allowed_values"=>null, "sql"=>"mysqlcolumn_to_be_defined", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
-		MetaModel::Init_AddAttribute(new AttributeTemplateText("t", array("allowed_values"=>null, "sql"=>"mysqlcolumn_to_be_defined", "default_value"=>"", "is_null_allowed"=>true, "depends_on"=>array())));
-	}
-}
 
 
 ////////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////////
 /**
 /**
@@ -159,7 +117,7 @@ class logRealObject extends cmdbAbstractObject
 			"db_table" => "objects",
 			"db_table" => "objects",
 			"db_key_field" => "id",
 			"db_key_field" => "id",
 			"db_finalclass_field" => "obj_class",
 			"db_finalclass_field" => "obj_class",
-			"display_template" => "../business/templates/default.html",
+			"icon" => "../images/tar.png",
 		);
 		);
 		MetaModel::Init_Params($aParams);
 		MetaModel::Init_Params($aParams);
 		MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
 		MetaModel::Init_AddAttribute(new AttributeString("name", array("allowed_values"=>null, "sql"=>"name", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
@@ -175,6 +133,18 @@ class logRealObject extends cmdbAbstractObject
 		MetaModel::Init_SetZListItems('advanced_search', array('name', 'status', 'org_id')); // Criteria of the advanced search form
 		MetaModel::Init_SetZListItems('advanced_search', array('name', 'status', 'org_id')); // Criteria of the advanced search form
 	}
 	}
 	
 	
+	public static function GetRelationQueries($sRelCode)
+	{
+		switch ($sRelCode)
+		{
+		case "impacts":
+			$aRels = array(
+				"owner" => array("sQuery"=>"SELECT bizPerson AS p JOIN lnkContactRealObject AS l1 ON l1.contact_id = p.id WHERE l1.object_id = :this->id", "bPropagate"=>true, "iDistance"=>3),
+			);
+			return array_merge($aRels, parent::GetRelationQueries($sRelCode));
+		}
+	}
+
 	public function Generate(cmdbDataGenerator $oGenerator)
 	public function Generate(cmdbDataGenerator $oGenerator)
 	{
 	{
 		$this->Set('org_id', $oGenerator->GetOrganizationId());
 		$this->Set('org_id', $oGenerator->GetOrganizationId());
@@ -312,6 +282,8 @@ class bizTeam extends bizContact
 		MetaModel::Init_SetZListItems('advanced_search', array('name', 'status', 'org_id')); // Criteria of the advanced search form
 		MetaModel::Init_SetZListItems('advanced_search', array('name', 'status', 'org_id')); // Criteria of the advanced search form
 	}
 	}
 }
 }
+
+
 ////////////////////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////////////////////
 /**
 /**
 * n-n link between any Object and a contact
 * n-n link between any Object and a contact
@@ -1525,7 +1497,52 @@ class bizPatch extends logRealObject
 	}
 	}
 }
 }
 
 
-/*** Insert here all modules requires for ITOP application  ***/
+////////////////////////////////////////////////////////////////////////////////////
+// Menu:
+//   +----------------------------------------+
+//   | Configuration Management Group         |
+//   +----------------------------------------+
+//		+ Configuration Management Overview
+//		+ Contacts
+//			+ Persons
+//			+ Teams
+//		+ Configuration Items
+//			+ PCs
+//			+ Servers
+//			+ Network Devices
+//			+ Interfaces
+//			+ Circuits
+//			+ Applications
+//			+ Subnets
+//			+ Infra Groups
+//		+ Locations
+//		+ Documents
+////////////////////////////////////////////////////////////////////////////////////
+
+// Create the top-level group. fRank = 1, means it will be inserted after the group '0', which is usually 'Welcome'
+$oConfigMgmtMenu = new MenuGroup('UI:ConfigurationManagementMenu', 1 /* fRank */);
+// Create an entry, based on a custom template, for the Configuration management overview, under the top-level group
+new TemplateMenuNode('UI:ConfigurationManagementMenu', '../business/templates/configuration_management_menu.html', $oConfigMgmtMenu->GetIndex(), 0 /* fRank */);
+// Create an entry (template based) for the overview of contacts
+$oContactsMenu = new TemplateMenuNode('UI:ContactsMenu', '../business/templates/configuration_management_menu.html',$oConfigMgmtMenu->GetIndex(), 1 /* fRank */);
+	// Plain list of persons
+	new OQLMenuNode('UI:PersonsMenu', 'UI:PersonsMenu:Title', 'SELECT bizPerson', $oContactsMenu->GetIndex(), 0 /* fRank */);
+	// Plain list of teams
+	new OQLMenuNode('UI:TeamsMenu', 'UI:TeamsMenu:Title', 'SELECT bizTeam', $oContactsMenu->GetIndex(), 1 /* fRank */);
+// Create an entry (template based) to provide an overview of all the 'infrastructure' CIs
+$oConfigItemsMenu = new TemplateMenuNode('UI:ConfigurationItemsMenu', '../business/templates/configuration_items_menu.html',$oConfigMgmtMenu->GetIndex(), 2 /* fRank */);
+// Quick and dirty way to add in one pass an entry for a few classes of CIs... good enough for testing, but not compatible with the localization
+$index = 0;
+foreach( array('bizPC', 'bizServer', 'bizNetworkDevice', 'bizInterface', 'bizCircuit', 'bizApplication', 'bizSubnet', 'bizInfraGroup') as $sClass)
+{
+	new OQLMenuNode($sClass,$sClass, 'SELECT '.$sClass, $oConfigItemsMenu->GetIndex(), $index++ /* fRank */);
+}
+// Add an entry (plain list) for locations
+new OQLMenuNode('UI:LocationsMenu', 'UI:LocationsMenu:Title', 'SELECT bizLocation', $oConfigMgmtMenu->GetIndex(), 3 /* fRank */);
+// Last but not least, add an entry (plain list) for documents
+new OQLMenuNode('UI:DocumentsMenu', 'UI:DocumentsMenu:Title', 'SELECT bizDocument', $oConfigMgmtMenu->GetIndex(), 4 /* fRank */);
+
+/*** Insert here all modules required for the whole iTop application  ***/
 
 
 require_once('incidentMgmt.business.php');
 require_once('incidentMgmt.business.php');
 require_once('ServiceMgmt.business.php');
 require_once('ServiceMgmt.business.php');

+ 1 - 1
business/templates/person.html

@@ -13,7 +13,7 @@
 		<itopblock blockclass="DisplayBlock" type="links" link_attr="contact_id" object_id="$id$" target_attr="object_id" encoding="text/oql">SELECT lnkContactRealObject WHERE contact_id = $id$</itopblock>	
 		<itopblock blockclass="DisplayBlock" type="links" link_attr="contact_id" object_id="$id$" target_attr="object_id" encoding="text/oql">SELECT lnkContactRealObject WHERE contact_id = $id$</itopblock>	
 	</itoptab>
 	</itoptab>
 	<itoptab name="Service_Calls">	
 	<itoptab name="Service_Calls">	
-		<itopblock blockclass="DisplayBlock"  type="list" encoding="text/oql">SELECT bizServiceCall WHERE caller_id = $id$</itopblock>	
+		<itopblock blockclass="DisplayBlock"  type="list" object_id="$id$" target_attr="caller_id" encoding="text/oql">SELECT bizServiceCall WHERE caller_id = $id$</itopblock>	
 	</itoptab>
 	</itoptab>
 
 
 	<itoptab name="Documents">
 	<itoptab name="Documents">

+ 5 - 34
pages/UI.php

@@ -364,45 +364,14 @@ try
 	require_once('../application/startup.inc.php');
 	require_once('../application/startup.inc.php');
 	$oContext = new UserContext();
 	$oContext = new UserContext();
 	$oAppContext = new ApplicationContext();
 	$oAppContext = new ApplicationContext();
-	$iActiveNodeId = utils::ReadParam('menu', '');
-
-	if (empty($iActiveNodeId) && !is_numeric($iActiveNodeId))
-	{
-		// No menu specified, let's get the default one:
-		// 1) It's a root menu item (parent_id == 0)
-		// 2) with the lowest rank
-		$oFilter = DBObjectSearch::FromOQL('SELECT menuNode AS M WHERE M.parent_id = 0');
-		if ($oFilter)
-		{
-			$oMenuSet = new CMDBObjectSet($oFilter);
-			while($oMenu = $oMenuSet->Fetch())
-			{
-				$aRanks[$oMenu->GetKey()] = $oMenu->Get('rank');
-			}
-			asort($aRanks); // sort by ascending rank: menuId => rank
-			$aKeys = array_keys($aRanks);
-			$iActiveNodeId = array_shift($aKeys); // Takes the first key, i.e. the menuId with the lowest rank
-		}
-	}
 	$currentOrganization = utils::ReadParam('org_id', '');
 	$currentOrganization = utils::ReadParam('org_id', '');
 	$operation = utils::ReadParam('operation', '');
 	$operation = utils::ReadParam('operation', '');
 
 
 	require_once('../application/loginwebpage.class.inc.php');
 	require_once('../application/loginwebpage.class.inc.php');
 	LoginWebPage::DoLogin(); // Check user rights and prompt if needed
 	LoginWebPage::DoLogin(); // Check user rights and prompt if needed
 
 
-
 	$oP = new iTopWebPage(Dict::S('UI:WelcomeToITop'), $currentOrganization);
 	$oP = new iTopWebPage(Dict::S('UI:WelcomeToITop'), $currentOrganization);
 
 
-	// From now on the context is limited to the the selected organization ??
-	if ($iActiveNodeId != -1)
-	{
-	    $oActiveNode = $oContext->GetObject('menuNode', $iActiveNodeId);
-	}
-	else
-	{
-	    $oActiveNode = null;
-	}
-
 	switch($operation)
 	switch($operation)
 	{
 	{
 		case 'details':
 		case 'details':
@@ -1331,10 +1300,12 @@ EOF
 		break;
 		break;
 	
 	
 		default:
 		default:
-		if (is_object($oActiveNode))
+		$oMenuNode = ApplicationMenu::GetMenuNode(ApplicationMenu::GetActiveNodeId());
+		if (is_object($oMenuNode))
 		{
 		{
-			$oActiveNode->RenderContent($oP, $oAppContext->GetAsHash());
-			$oP->set_title($oActiveNode->GetMenuLabel());
+		
+			$oMenuNode->RenderContent($oP, $oAppContext->GetAsHash());
+			$oP->set_title($oMenuNode->GetLabel());
 		}
 		}
 	}
 	}
 	////MetaModel::ShowQueryTrace();
 	////MetaModel::ShowQueryTrace();

+ 3 - 1
pages/UniversalSearch.php

@@ -64,7 +64,9 @@ foreach($aClassLabels as $sCurrentClass => $sLabel)
 	$sSelected = ($sCurrentClass == $sBaseClass) ? " SELECTED" : "";
 	$sSelected = ($sCurrentClass == $sBaseClass) ? " SELECTED" : "";
 	$oP->add("<option value=\"$sCurrentClass\" title=\"$sDescription\"$sSelected>$sLabel</option>");
 	$oP->add("<option value=\"$sCurrentClass\" title=\"$sDescription\"$sSelected>$sLabel</option>");
 }
 }
-$oP->add("</select></form>");
+$oP->add("</select>\n");
+$oP->add($oAppContext->GetForForm());
+$oP->add("</form>\n");
 
 
 try 
 try 
 {
 {

+ 0 - 819
setup/data/structure/1.menus.xml

@@ -1,819 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<Set>
-<menuNode alias="menuNode" id="1">
-<name>UI:AdminToolsMenu</name>
-<label>UI:AdminToolsMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;p&gt;&lt;/p&gt;
-&lt;p&gt;&lt;/p&gt;
-&lt;p style=&quot;text-align:center; font-family:Georgia, &apos;Times New Roman&apos;, Times, serif; font-size:32px;&quot;&gt;Administration tools&lt;/p&gt;
-&lt;p&gt;Tools accessible only to logins having the administrator profile&lt;/p&gt;
-</template>
-<type>administrator</type>
-<rank>1000</rank>
-<parent_id>0</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="15">
-<name>UI:AdvancedToolsMenu</name>
-<label>UI:AdvancedToolsMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;p&gt;&lt;/p&gt;
-&lt;p&gt;&lt;/p&gt;
-&lt;p style=&quot;text-align:center; font-family:Georgia, &apos;Times New Roman&apos;, Times, serif; font-size:32px;&quot;&gt;Tools for the iTop consultant&lt;/p&gt;
-&lt;p style=&quot;text-align:center; font-family:Georgia, &apos;Times New Roman&apos;, Times, serif; font-size:14px;&quot;&gt;&lt;i&gt;This section contains links to useful tools for extending or debugging iTop&lt;/i&gt;&lt;/p&gt;
-</template>
-<type>application</type>
-<rank>9</rank>
-<parent_id>0</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="16">
-<name>UI:ApplicationLogMenu</name>
-<label>UI:ApplicationLogMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path>../images/std_view.gif</icon_path>
-<template>&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;search&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT Event&lt;/itopblock&gt;
-&lt;p class=&quot;page-header&quot;&gt;&lt;itopstring&gt;UI:ApplicationLogMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT Event&lt;/itopblock&gt;
-</template>
-<type>administrator</type>
-<rank>2</rank>
-<parent_id>1</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="17">
-<name>UI:ApplicationsMenu</name>
-<label>UI:ApplicationsMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;search&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizApplication&lt;/itopblock&gt;
-&lt;p class=&quot;page-header&quot;&gt;&lt;itopstring&gt;UI:ApplicationsMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizApplication&lt;/itopblock&gt;
-</template>
-<type>application</type>
-<rank>999</rank>
-<parent_id>4</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="2">
-<name>UI:AuditMenu</name>
-<label>UI:AuditMenu+</label>
-<hyperlink>./audit.php</hyperlink>
-<icon_path></icon_path>
-<template></template>
-<type>application</type>
-<rank>4</rank>
-<parent_id>5</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="3">
-<name>UI:ChangeManagementMenu</name>
-<label>UI:ChangeManagementMenu+</label>
-<hyperlink>./UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;h1&gt;&lt;itopstring&gt;UI:ChangeManagementMenu:Title&lt;/itopstring&gt;&lt;/h1&gt;
-&lt;table border=&quot;0&quot; padding=&quot;5&quot; width=&quot;100%&quot;&gt;
-&lt;tr&gt;
-&lt;td class=&quot;dashboard&quot;&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;open_flash_chart&quot; parameters=&quot;chart_type:bars;group_by:type;chart_title:UI-ChangeManagementMenu-ChangesByType&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizChangeTicket&lt;/itopblock&gt;
-&lt;/td&gt;
-&lt;td class=&quot;dashboard&quot;&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;open_flash_chart&quot; parameters=&quot;chart_type:pie;group_by:ticket_status;chart_title:UI-ChangeManagementMenu-ChangesByStatus&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizChangeTicket&lt;/itopblock&gt;
-&lt;/td&gt;
-&lt;/tr&gt;&lt;tr&gt;
-&lt;td class=&quot;dashboard&quot;&gt;
-&lt;h2&gt;&lt;itopstring&gt;UI-ChangeManagementMenu-ChangesByWorkgroup&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;count&quot; parameters=&quot;group_by:workgroup_name&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizChangeTicket&lt;/itopblock&gt;
-&lt;/td&gt;
-&lt;td class=&quot;dashboard&quot;&gt;
-&lt;h2&gt;&lt;itopstring&gt;UI-ChangeManagementMenu-ChangesNotYetAssigned&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; parameters=&quot;dashboard:true&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizChangeTicket WHERE ticket_status = &apos;New&apos;&lt;/itopblock&gt;
-&lt;/td&gt;
-&lt;/tr&gt;
-&lt;/table&gt;</template>
-<type>application</type>
-<rank>7</rank>
-<parent_id>0</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="18">
-<name>UI:CircuitsMenu</name>
-<label>UI:CircuitsMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;search&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizCircuit&lt;/itopblock&gt;
-&lt;p class=&quot;page-header&quot;&gt;&lt;itopstring&gt;UI:CircuitsMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizCircuit&lt;/itopblock&gt;
-</template>
-<type>application</type>
-<rank>999</rank>
-<parent_id>4</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="19">
-<name>UI:ClosedChangesMenu</name>
-<label>UI:ClosedChangesMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;search&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizChangeTicket WHERE ticket_status = &apos;Closed&apos;&lt;/itopblock&gt;
-&lt;p class=&quot;page-header&quot;&gt;&lt;itopstring&gt;UI:ClosedChangesMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizChangeTicket WHERE ticket_status = &apos;Closed&apos;&lt;/itopblock&gt;
-</template>
-<type>application</type>
-<rank>5</rank>
-<parent_id>3</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="20">
-<name>UI:ClosedIncidentsMenu</name>
-<label>UI:ClosedIncidentsMenu+</label>
-<hyperlink>./UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;search&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizIncidentTicket WHERE ticket_status = &apos;Closed&apos;&lt;/itopblock&gt;
-&lt;p class=&quot;page-header&quot;&gt;&lt;itopstring&gt;UI:ClosedIncidentsMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizIncidentTicket WHERE ticket_status = &apos;Closed&apos;&lt;/itopblock&gt;
-</template>
-<type>application</type>
-<rank>5</rank>
-<parent_id>10</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="4">
-<name>UI:ConfigurationItemsMenu</name>
-<label>UI:ConfigurationItemsMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;h1&gt;&lt;itopstring&gt;UI:ConfigurationItemsMenu:Title&lt;/itopstring&gt;&lt;/h1&gt;
-&lt;table border=&quot;0&quot; padding=&quot;5&quot; class=&quot;layout&quot; width=&quot;100%&quot;&gt;
-&lt;tr&gt;
-&lt;td class=&quot;dashboard&quot;&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;open_flash_chart&quot; parameters=&quot;chart_type:pie;chart_title:UI-ConfigurationItemsMenu-ServersByCriticity;group_by:severity&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizServer&lt;/itopblock&gt;
-&lt;/td&gt;
-&lt;td class=&quot;dashboard&quot;&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;open_flash_chart&quot; parameters=&quot;chart_type:pie;chart_title:UI-ConfigurationItemsMenu-PCsByCriticity;group_by:severity&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizPC&lt;/itopblock&gt;
-&lt;/td&gt;
-&lt;/tr&gt;&lt;tr&gt;
-&lt;td class=&quot;dashboard&quot;&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;open_flash_chart&quot; parameters=&quot;chart_type:pie;chart_title:UI-ConfigurationItemsMenu-NWDevicesByCriticity;group_by:severity&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizNetworkDevice&lt;/itopblock&gt;
-&lt;/td&gt;
-&lt;td class=&quot;dashboard&quot;&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;open_flash_chart&quot; parameters=&quot;chart_type:pie;chart_title:UI-ConfigurationItemsMenu-ApplicationsByCriticity;group_by:severity&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizApplication&lt;/itopblock&gt;
-&lt;/td&gt;
-&lt;/tr&gt;
-&lt;/table&gt;</template>
-<type>application</type>
-<rank>2</rank>
-<parent_id>5</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="5">
-<name>UI:ConfigurationManagementMenu</name>
-<label>UI:ConfigurationManagementMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;h1&gt;&lt;itopstring&gt;UI:ConfigurationManagementMenu:Title&lt;/itopstring&gt;&lt;/h1&gt;
-&lt;table border=&quot;0&quot; padding=&quot;5&quot; class=&quot;layout&quot; width=&quot;100%&quot;&gt;
-&lt;tr&gt;
-&lt;td class=&quot;dashboard&quot;&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;open_flash_chart&quot; parameters=&quot;chart_type:pie;group_by:status;chart_title:UI-ConfigurationManagementMenu-InfraByStatus&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT logInfra&lt;/itopblock&gt;
-&lt;/td&gt;
-&lt;td class=&quot;dashboard&quot;&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;open_flash_chart&quot; parameters=&quot;chart_type:bars;group_by:finalclass;chart_title:UI-ConfigurationManagementMenu-InfraByType&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT logInfra&lt;/itopblock&gt;
-&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-&lt;td class=&quot;dashboard&quot;&gt;
-&lt;h2&gt;&lt;itopstring&gt;UI-ConfigurationManagementMenu-InfraByType&lt;/itopstring&gt;&lt;/h2&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;count&quot; parameters=&quot;group_by:finalclass&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT logInfra&lt;/itopblock&gt;
-&lt;/td&gt;
-&lt;td&gt;
-&amp;nbsp;
-&lt;/td&gt;
-&lt;/tr&gt;
-&lt;/table&gt;</template>
-<type>application</type>
-<rank>2</rank>
-<parent_id>0</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="6">
-<name>UI:ContactsMenu</name>
-<label>UI:ContactsMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;h1&gt;&lt;itopstring&gt;UI:ContactsMenu:Title&lt;/itopstring&gt;&lt;/h1&gt;
-&lt;table border=&quot;0&quot; padding=&quot;5&quot; class=&quot;layout&quot; width=&quot;100%&quot;&gt;
-&lt;tr&gt;
-&lt;td class=&quot;dashboard&quot;&gt;
-&lt;h2&gt;&lt;itopstring&gt;UI-ContactsMenu-ContactsByLocation&lt;/itopstring&gt;&lt;/h2&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;count&quot; parameters=&quot;group_by:location_name&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizContact&lt;/itopblock&gt;
-&lt;/td&gt;
-&lt;td class=&quot;dashboard&quot;&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;open_flash_chart&quot; parameters=&quot;chart_type:pie;chart_title:UI-ContactsMenu-ContactsByLocation;group_by:location_name&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizContact&lt;/itopblock&gt;
-&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-&lt;td class=&quot;dashboard&quot;&gt;
-&lt;h2&gt;&lt;itopstring&gt;UI-ContactsMenu-ContactsByType&lt;/itopstring&gt;&lt;/h2&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;count&quot; parameters=&quot;group_by:finalclass&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizContact&lt;/itopblock&gt;
-&lt;/td&gt;
-&lt;td class=&quot;dashboard&quot;&gt;
-&lt;h2&gt;&lt;itopstring&gt;UI-ContactsMenu-ContactsByStatus&lt;/itopstring&gt;&lt;/h2&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;count&quot; parameters=&quot;group_by:status&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizContact&lt;/itopblock&gt;
-&lt;/td&gt;
-&lt;/tr&gt;
-&lt;/table&gt;</template>
-<type>application</type>
-<rank>1</rank>
-<parent_id>5</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="21">
-<name>UI:ContractsMenu</name>
-<label>UI:ContractsMenu+</label>
-<hyperlink>./UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;search&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizContract&lt;/itopblock&gt;
-&lt;p class=&quot;page-header&quot;&gt;&lt;itopstring&gt;UI:ContractsMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizContract&lt;/itopblock&gt;
-</template>
-<type>application</type>
-<rank>2</rank>
-<parent_id>14</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="7">
-<name>UI:CSVImportMenu</name>
-<label>UI:CSVImportMenu+</label>
-<hyperlink>csvimport.php</hyperlink>
-<icon_path></icon_path>
-<template></template>
-<type>application</type>
-<rank>999</rank>
-<parent_id>15</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="8">
-<name>UI:DataModelMenu</name>
-<label>UI:DataModelMenu+</label>
-<hyperlink>schema.php</hyperlink>
-<icon_path></icon_path>
-<template></template>
-<type>administrator</type>
-<rank>1500</rank>
-<parent_id>1</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="22">
-<name>UI:DocumentsMenu</name>
-<label>UI:DocumentsMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;search&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizDocument&lt;/itopblock&gt;
-&lt;p class=&quot;page-header&quot;&gt;&lt;itopstring&gt;UI:DocumentsMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizDocument&lt;/itopblock&gt;
-</template>
-<type>application</type>
-<rank>6</rank>
-<parent_id>5</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="9">
-<name>UI:ExportMenu</name>
-<label>UI:ExportMenu+</label>
-<hyperlink>../webservices/export.php</hyperlink>
-<icon_path></icon_path>
-<template></template>
-<type>administrator</type>
-<rank>1001</rank>
-<parent_id>1</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="23">
-<name>UI:GroupingMenu</name>
-<label>UI:GroupingMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;search&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizInfraGroup&lt;/itopblock&gt;
-&lt;p class=&quot;page-header&quot;&gt;&lt;itopstring&gt;UI:GroupingMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizInfraGroup&lt;/itopblock&gt;
-</template>
-<type>application</type>
-<rank>3</rank>
-<parent_id>5</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="10">
-<name>UI:IncidentManagementMenu</name>
-<label>UI:IncidentManagementMenu+</label>
-<hyperlink>./UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;h1&gt;&lt;itopstring&gt;UI:IncidentManagementMenu:Title&lt;/itopstring&gt;&lt;/h1&gt;
-&lt;table border=&quot;0&quot; padding=&quot;5&quot; width=&quot;100%&quot;&gt;
-&lt;tr&gt;
-&lt;td class=&quot;dashboard&quot;&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;open_flash_chart&quot; parameters=&quot;chart_type:pie;group_by:type;chart_title:UI-IncidentManagementMenu-IncidentsByType&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizIncidentTicket&lt;/itopblock&gt;
-&lt;/td&gt;
-&lt;td class=&quot;dashboard&quot;&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;open_flash_chart&quot; parameters=&quot;chart_type:bars;group_by:ticket_status;chart_title:UI-IncidentManagementMenu-IncidentsByStatus&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizIncidentTicket&lt;/itopblock&gt;
-&lt;/td&gt;
-&lt;/tr&gt;&lt;tr&gt;
-&lt;td class=&quot;dashboard&quot;&gt;
-&lt;h2&gt;&lt;itopstring&gt;UI-IncidentManagementMenu-IncidentsByWorkgroup&lt;/itopstring&gt;&lt;/h2p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;count&quot; parameters=&quot;group_by:workgroup_name&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizIncidentTicket&lt;/itopblock&gt;
-&lt;/td&gt;
-&lt;td class=&quot;dashboard&quot;&gt;
-&lt;h2&gt;&lt;itopstring&gt;UI-IncidentManagementMenu-IncidentsNotYetAssigned&lt;/itopstring&gt;&lt;/h2p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; parameters=&quot;dashboard:true&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizIncidentTicket WHERE ticket_status = &apos;New&apos;&lt;/itopblock&gt;
-&lt;/td&gt;
-&lt;/tr&gt;
-&lt;/table&gt;</template>
-<type>application</type>
-<rank>5</rank>
-<parent_id>0</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="24">
-<name>UI:InterfacesMenu</name>
-<label>UI:InterfacesMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;search&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizInterface&lt;/itopblock&gt;
-&lt;p class=&quot;page-header&quot;&gt;&lt;itopstring&gt;UI:InterfacesMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizInterface&lt;/itopblock&gt;
-</template>
-<type>application</type>
-<rank>999</rank>
-<parent_id>4</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="25">
-<name>UI:KnownErrorsMenu</name>
-<label>UI:KnownErrorsMenu+</label>
-<hyperlink>./UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;search&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizKnownError&lt;/itopblock&gt;
-&lt;p class=&quot;page-header&quot;&gt;&lt;itopstring&gt;UI:KnownErrorsMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizKnownError&lt;/itopblock&gt;
-</template>
-<type>application</type>
-<rank>999</rank>
-<parent_id>10</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="26">
-<name>UI:LocationsMenu</name>
-<label>UI:LocationsMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;search&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizLocation&lt;/itopblock&gt;
-&lt;p class=&quot;page-header&quot;&gt;&lt;itopstring&gt;UI:LocationsMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizLocation&lt;/itopblock&gt;
-</template>
-<type>application</type>
-<rank>5</rank>
-<parent_id>5</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="27">
-<name>UI:MyChangesMenu</name>
-<label>UI:MyChangesMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;search&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizChangeTicket AS C WHERE C.agent_id = :current_contact_id&lt;/itopblock&gt;
-&lt;p class=&quot;page-header&quot;&gt;&lt;itopstring&gt;UI:MyChangesMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizChangeTicket AS C WHERE C.agent_id = :current_contact_id&lt;/itopblock&gt;
-</template>
-<type>application</type>
-<rank>1</rank>
-<parent_id>3</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="28">
-<name>UI:MyIncidentsMenu</name>
-<label>UI:MyIncidentsMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;search&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizIncidentTicket AS I WHERE I.agent_id = :current_contact_id&lt;/itopblock&gt;
-&lt;p class=&quot;page-header&quot;&gt;&lt;itopstring&gt;UI:MyIncidentsMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizIncidentTicket AS I WHERE I.agent_id = :current_contact_id&lt;/itopblock&gt;
-</template>
-<type>application</type>
-<rank>1</rank>
-<parent_id>10</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="29">
-<name>UI:MyServiceCallsMenu</name>
-<label>UI:MyServiceCallsMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;search&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizServiceCall AS SC WHERE SC.agent_id = :current_contact_id&lt;/itopblock&gt;
-&lt;p class=&quot;page-header&quot;&gt;&lt;itopstring&gt;UI:MyServiceCallsMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizServiceCall AS SC WHERE SC.agent_id = :current_contact_id&lt;/itopblock&gt;
-</template>
-<type>application</type>
-<rank>1</rank>
-<parent_id>13</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="30">
-<name>UI:NetworkDevicesMenu</name>
-<label>UI:NetworkDevicesMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;search&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizNetworkDevice&lt;/itopblock&gt;
-&lt;p class=&quot;page-header&quot;&gt;&lt;itopstring&gt;UI:NetworkDevicesMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizNetworkDevice&lt;/itopblock&gt;
-</template>
-<type>application</type>
-<rank>999</rank>
-<parent_id>4</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="11">
-<name>UI:NotificationsMenu</name>
-<label>UI:NotificationsMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;div class=&quot;page_header&quot; style=&quot;padding:0.5em;&quot;&gt;
-&lt;h1&gt;&lt;itopstring&gt;UI:NotificationsMenu:Title&lt;/itopstring&gt;&lt;/h1&gt;
-&lt;/div&gt;
-&lt;itoptoggle name=&quot;UI:NotificationsMenu:Help&quot; open=&quot;true&quot;&gt;
-&lt;div style=&quot;padding: 1em; font-size:1.25em;background:#E8F3CF;margin-top: 0.25em;&quot;&gt;
-&lt;img src=&quot;../images/bell.png&quot; style=&quot;margin-top: -60px; margin-right: 10px; float: right;&quot;&gt;
-&lt;itopstring&gt;UI:NotificationsMenu:HelpContent&lt;/itopstring&gt;
-&lt;/div&gt;
-&lt;/itoptoggle&gt;
-&lt;p&gt;&amp;nbsp;&lt;/p&gt;
-&lt;itoptabs&gt;
-	&lt;itoptab name=&quot;UI:NotificationsMenu:Triggers&quot;&gt;
-		&lt;h2&gt;&lt;itopstring&gt;UI:NotificationsMenu:AvailableTriggers&lt;/itopstring&gt;&lt;/h2&gt;
-		&lt;table style=&quot;border:0;border-spacing:10px;width:100%;&quot;&gt;
-		&lt;tr&gt;
-		&lt;td style=&quot;vertical-align:top;width:33%;padding:10px;background:#f8f8f8;&quot;&gt;
-		&lt;h3&gt;&lt;itopstring&gt;UI:NotificationsMenu:OnCreate&lt;/itopstring&gt;&lt;/h3&gt;
-		&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT TriggerOnObjectCreate&lt;/itopblock&gt;
-		&lt;/td&gt;
-		&lt;td style=&quot;vertical-align:top;width:33%;padding:10px;background:#f8f8f8;&quot;&gt;
-		&lt;h3&gt;&lt;itopstring&gt;UI:NotificationsMenu:OnStateEnter&lt;/itopstring&gt;&lt;/h3&gt;
-		&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT TriggerOnStateEnter&lt;/itopblock&gt;
-		&lt;/td&gt;
-		&lt;td style=&quot;vertical-align:top;width:33%;padding:10px;background:#f8f8f8;&quot;&gt;
-		&lt;h3&gt;&lt;itopstring&gt;UI:NotificationsMenu:OnStateLeave&lt;/itopstring&gt;&lt;/h3&gt;
-		&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT TriggerOnStateLeave&lt;/itopblock&gt;
-		&lt;/td&gt;
-		&lt;/tr&gt;
-		&lt;/table&gt;
-	&lt;/itoptab&gt;
-	&lt;itoptab name=&quot;UI:NotificationsMenu:Actions&quot;&gt;
-		&lt;h2&gt;&lt;itopstring&gt;UI:NotificationsMenu:AvailableActions&lt;/itopstring&gt;&lt;/h2&gt;
-		&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT ActionEmail&lt;/itopblock&gt;
-	&lt;/itoptab&gt;
-&lt;/itoptabs&gt;</template>
-<type>administrator</type>
-<rank>2</rank>
-<parent_id>1</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="31">
-<name>UI:OpenChangesMenu</name>
-<label>UI:OpenChangesMenu+</label>
-<hyperlink>./UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;search&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizChangeTicket WHERE ticket_status != &apos;Closed&apos;&lt;/itopblock&gt;
-&lt;p class=&quot;page-header&quot;&gt;&lt;itopstring&gt;UI:OpenChangesMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizChangeTicket WHERE ticket_status != &apos;Closed&apos;&lt;/itopblock&gt;
-</template>
-<type>application</type>
-<rank>3</rank>
-<parent_id>3</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="32">
-<name>UI:OpenIncidentsMenu</name>
-<label>UI:OpenIncidentsMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;search&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizIncidentTicket WHERE ticket_status != &apos;Closed&apos;&lt;/itopblock&gt;
-&lt;p class=&quot;page-header&quot;&gt;&lt;itopstring&gt;UI:OpenIncidentsMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizIncidentTicket WHERE ticket_status != &apos;Closed&apos;&lt;/itopblock&gt;
-</template>
-<type>application</type>
-<rank>3</rank>
-<parent_id>10</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="33">
-<name>UI:OpenServiceCallsMenu</name>
-<label>UI:OpenServiceCallsMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;search&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizServiceCall WHERE call_status != &apos;Closed&apos;&lt;/itopblock&gt;
-&lt;p class=&quot;page-header&quot;&gt;&lt;itopstring&gt;UI:OpenServiceCallsMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizServiceCall WHERE call_status != &apos;Closed&apos;&lt;/itopblock&gt;
-</template>
-<type>application</type>
-<rank>2</rank>
-<parent_id>13</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="34">
-<name>UI:PatchesMenu</name>
-<label>UI:PatchesMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;search&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizPatch&lt;/itopblock&gt;
-&lt;p class=&quot;page-header&quot;&gt;&lt;itopstring&gt;UI:PatchesMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizPatch&lt;/itopblock&gt;
-</template>
-<type>application</type>
-<rank>999</rank>
-<parent_id>4</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="35">
-<name>UI:PCsMenu</name>
-<label>UI:PCsMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;search&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizPC&lt;/itopblock&gt;
-&lt;p class=&quot;page-header&quot;&gt;&lt;itopstring&gt;UI:PCsMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizPC&lt;/itopblock&gt;
-</template>
-<type>application</type>
-<rank>999</rank>
-<parent_id>4</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="36">
-<name>UI:PersonsMenu</name>
-<label>UI:PersonsMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;search&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizPerson&lt;/itopblock&gt;
-&lt;p class=&quot;page-header&quot;&gt;&lt;itopstring&gt;UI:PersonsMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizPerson&lt;/itopblock&gt;
-</template>
-<type>application</type>
-<rank>7</rank>
-<parent_id>6</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="37">
-<name>UI:ProfilesMenu</name>
-<label>UI:ProfilesMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path>../images/std_view.gif</icon_path>
-<template>&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;search&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT URP_Profiles&lt;/itopblock&gt;
-&lt;p class=&quot;page-header&quot;&gt;&lt;itopstring&gt;UI:ProfilesMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT URP_Profiles&lt;/itopblock&gt;
-</template>
-<type>administrator</type>
-<rank>11</rank>
-<parent_id>45</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="12">
-<name>UI:RunQueriesMenu</name>
-<label>UI:RunQueriesMenu+</label>
-<hyperlink>./run_query.php</hyperlink>
-<icon_path></icon_path>
-<template></template>
-<type>administrator</type>
-<rank>1002</rank>
-<parent_id>1</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="38">
-<name>UI:ScheduledOutagesMenu</name>
-<label>UI:ScheduledOutagesMenu+</label>
-<hyperlink>./UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;search&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizChangeTicket WHERE outage = &apos;Yes&apos; AND ticket_status != &apos;Closed&apos;&lt;/itopblock&gt;
-&lt;p class=&quot;page-header&quot;&gt;&lt;itopstring&gt;UI:ScheduledOutagesMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizChangeTicket WHERE outage = &apos;Yes&apos; AND ticket_status != &apos;Closed&apos;&lt;/itopblock&gt;
-</template>
-<type>application</type>
-<rank>7</rank>
-<parent_id>3</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="39">
-<name>UI:ServersMenu</name>
-<label>UI:ServersMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;search&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizServer&lt;/itopblock&gt;
-&lt;p class=&quot;page-header&quot;&gt;&lt;itopstring&gt;UI:ServersMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizServer&lt;/itopblock&gt;
-</template>
-<type>application</type>
-<rank>999</rank>
-<parent_id>4</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="13">
-<name>UI:ServiceDeskMenu</name>
-<label>UI:ServiceDeskMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;h1&gt;&lt;itopstring&gt;UI:ServiceDeskMenu:Title&lt;/itopstring&gt;&lt;/h1&gt;
-&lt;table border=&quot;0&quot; padding=&quot;5&quot; width=&quot;100%&quot;&gt;
-&lt;tr&gt;
-&lt;td class=&quot;dashboard&quot;&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;open_flash_chart&quot; parameters=&quot;chart_type:pie;group_by:type;chart_title:UI-ServiceDeskMenu-CallsByType&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizServiceCall&lt;/itopblock&gt;
-&lt;/td&gt;
-&lt;td class=&quot;dashboard&quot;&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;open_flash_chart&quot; parameters=&quot;chart_type:bars;group_by:call_status;chart_title:UI-ServiceDeskMenu-CallsByStatus&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizServiceCall&lt;/itopblock&gt;
-&lt;/td&gt;
-&lt;/tr&gt;&lt;tr&gt;
-&lt;td class=&quot;dashboard&quot;&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;open_flash_chart&quot; parameters=&quot;chart_type:pie;group_by:severity;chart_title:UI-ServiceDeskMenu-CallsBySeverity&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizServiceCall&lt;/itopblock&gt;
-&lt;/td&gt;
-&lt;td class=&quot;dashboard&quot;&gt;
-&lt;h2&gt;&lt;itopstring&gt;UI-ServiceDeskMenu-CallsNotYetAssigned&lt;/itopstring&gt;&lt;/h2&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; parameters=&quot;dashboard:true&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizServiceCall WHERE call_status = &apos;New&apos;&lt;/itopblock&gt;
-&lt;/td&gt;
-&lt;/tr&gt;
-&lt;/table&gt;</template>
-<type>application</type>
-<rank>3</rank>
-<parent_id>0</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="14">
-<name>UI:ServiceManagementMenu</name>
-<label>UI:ServiceManagementMenu+</label>
-<hyperlink>./UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;h1&gt;&lt;itopstring&gt;UI:ServiceManagementMenu:Title&lt;/itopstring&gt;&lt;/h1&gt;
-&lt;table border=&quot;0&quot; padding=&quot;5&quot; width=&quot;100%&quot;&gt;
-&lt;tr&gt;
-&lt;td class=&quot;dashboard&quot;&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;open_flash_chart&quot; parameters=&quot;chart_type:bars;group_by:type;chart_title:UI-ServiceManagementMenu-ContractsBySrvLevel&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizContract&lt;/itopblock&gt;
-&lt;/td&gt;
-&lt;td class=&quot;dashboard&quot;&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;open_flash_chart&quot; parameters=&quot;chart_type:pie;group_by:status;chart_title:UI-ServiceManagementMenu-ContractsByStatus&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizContract&lt;/itopblock&gt;
-&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-&lt;td class=&quot;dashboard&quot;&gt;
-&lt;h2&gt;&lt;itopstring&gt;UI-ServiceManagementMenu-ContractsEndingIn30Days&lt;/itopstring&gt;&lt;/h2&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; parameters=&quot;dashboard:true&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizContract WHERE bizContract.end_prod = (TO_DAYS(NOW()) + TO_DAYS(30))&lt;/itopblock&gt;
-&lt;/td&gt;
-&lt;/tr&gt;
-&lt;/table&gt;</template>
-<type>application</type>
-<rank>8</rank>
-<parent_id>0</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="40">
-<name>UI:ServicesMenu</name>
-<label>UI:ServicesMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;search&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizService&lt;/itopblock&gt;
-&lt;p class=&quot;page-header&quot;&gt;&lt;itopstring&gt;UI:ServicesMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizService&lt;/itopblock&gt;
-</template>
-<type>application</type>
-<rank>1</rank>
-<parent_id>14</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="41">
-<name>UI:SubnetsMenu</name>
-<label>UI:SubnetsMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;search&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizSubnet&lt;/itopblock&gt;
-&lt;p class=&quot;page-header&quot;&gt;&lt;itopstring&gt;UI:SubnetsMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizSubnet&lt;/itopblock&gt;
-</template>
-<type>application</type>
-<rank>999</rank>
-<parent_id>4</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="42">
-<name>UI:TeamsMenu</name>
-<label>UI:TeamsMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;search&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizTeam&lt;/itopblock&gt;
-&lt;p class=&quot;page-header&quot;&gt;&lt;itopstring&gt;UI:TeamsMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizTeam&lt;/itopblock&gt;
-</template>
-<type>application</type>
-<rank>8</rank>
-<parent_id>6</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="44">
-<name>UI:UniversalSearchMenu</name>
-<label>UI:UniversalSearchMenu+</label>
-<hyperlink>UniversalSearch.php</hyperlink>
-<icon_path></icon_path>
-<template></template>
-<type>administrator</type>
-<rank>1600</rank>
-<parent_id>1</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="43">
-<name>UI:UserAccountsMenu</name>
-<label>UI:UserAccountsMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path>../images/std_view.gif</icon_path>
-<template>&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;search&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT URP_Users&lt;/itopblock&gt;
-&lt;p class=&quot;page-header&quot;&gt;&lt;itopstring&gt;UI:UserAccountsMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT URP_Users&lt;/itopblock&gt;
-</template>
-<type>administrator</type>
-<rank>10</rank>
-<parent_id>45</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="45">
-<name>UI:UserManagementMenu</name>
-<label>UI:UserManagementMenu+</label>
-<hyperlink>UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;p&gt;&lt;/p&gt;
-&lt;p&gt;&lt;/p&gt;
-&lt;p style=&quot;text-align:center; font-family:Georgia, &apos;Times New Roman&apos;, Times, serif; font-size:32px;&quot;&gt;User management&lt;/p&gt;
-&lt;p&gt;&lt;/p&gt;
-&lt;p style=&quot;text-align:center; font-family:Georgia, &apos;Times New Roman&apos;, Times, serif; font-size:14px;&quot;&gt;&lt;i&gt;User management by profiles&lt;/i&gt;&lt;/p&gt;
-</template>
-<type>administrator</type>
-<rank>1</rank>
-<parent_id>1</parent_id>
-<user_id>0</user_id>
-</menuNode>
-<menuNode alias="menuNode" id="46">
-<name>UI:WelcomeMenu</name>
-<label>UI:WelcomeMenu+</label>
-<hyperlink>./UI.php</hyperlink>
-<icon_path></icon_path>
-<template>&lt;div style=&quot;width:100%;background: url(../images/welcome.jpg) top left no-repeat;&quot;&gt;
-&lt;style&gt;
-.dashboard {
-vertical-align:top;
-width:50%;
-border:0px solid #000;
-background-color:#F9F9F1;
-padding:10px;
-text-align:left;
-font-size:10pt;
-}
-.dashboard2 {
-vertical-align:top;
-width:50%;
-border:0px solid #000;
--moz-border-radius:10px;
-padding:5px;
-text-align:left;
-}
-
-td.dashboard li {
-margin-top: 5px;
-display: list-item;
-}
-&lt;/style&gt;
-&lt;p&gt;&lt;/p&gt;
-&lt;p&gt;&lt;/p&gt;
-&lt;p style=&quot;text-align:left; font-size:32px;padding-left:400px;padding-top:40px;margin-bottom:30px;margin-top:0;color:#FFFFFF;&quot;&gt;&lt;itopstring&gt;UI:WelcomeMenu:Title&lt;/itopstring&gt;&lt;/p&gt;
-&lt;p&gt;&lt;/p&gt;
-&lt;table border=&quot;0&quot; style=&quot;padding:10px;border-spacing: 10px;&quot;&gt;
-&lt;tr&gt;
-&lt;td class=&quot;dashboard&quot;&gt;
-&lt;itopstring&gt;UI:WelcomeMenu:LeftBlock&lt;/itopstring&gt;
-&lt;/td&gt;
-&lt;td class=&quot;dashboard&quot;&gt;
-&lt;itopstring&gt;UI:WelcomeMenu:RightBlock&lt;/itopstring&gt;
-&lt;/td&gt;
-&lt;/tr&gt;
-&lt;tr&gt;
-&lt;td class=&quot;dashboard2&quot;&gt;
-&lt;p style=&quot;text-align:left; font-family:Verdana, Arial, sans-serif; font-size:16px;&quot;&gt;&lt;itopstring&gt;UI:WelcomeMenu:MyCalls&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizServiceCall AS i WHERE i.caller_id = :current_contact_id&lt;/itopblock&gt;
-&lt;/td&gt;
-&lt;td class=&quot;dashboard2&quot;&gt;
-&lt;p style=&quot;text-align:left; font-family:Verdana, Arial, sans-serif; font-size:16px;&quot;&gt;&lt;itopstring&gt;UI:WelcomeMenu:MyIncidents&lt;/itopstring&gt;&lt;/p&gt;
-&lt;itopblock BlockClass=&quot;DisplayBlock&quot; type=&quot;list&quot; asynchronous=&quot;false&quot; encoding=&quot;text/oql&quot;&gt;SELECT bizIncidentTicket AS i WHERE i.caller_id = :current_contact_id&lt;/itopblock&gt;
-&lt;/td&gt;
-
-&lt;/tr&gt;
-&lt;/table&gt;
-&lt;/div&gt;</template>
-<type>application</type>
-<rank>1</rank>
-<parent_id>0</parent_id>
-<user_id>0</user_id>
-</menuNode>
-</Set>