Browse Source

- completed the fix of the user object history (Trac #48)
- completed the implementation of truncated lists (Trac #61)
- Fixed the handling of the search form in the details page (Trac #29)

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@214 a333f486-631f-4898-b8df-5754b55c2be0

dflaven 15 years ago
parent
commit
6dd80c8409

+ 35 - 6
application/cmdbabstract.class.inc.php

@@ -131,7 +131,7 @@ abstract class cmdbAbstractObject extends CMDBObject
 		$oPage->add("<h1>".MetaModel::GetName(get_class($this)).": <span class=\"hilite\">".$this->GetDisplayName()."</span></h1>\n");
 
 		// history block (with toggle)
-		$oHistoryFilter = new DBObjectSearch('CMDBChangeOpSetAttribute');
+		$oHistoryFilter = new DBObjectSearch('CMDBChangeOp');
 		$oHistoryFilter->AddCondition('objkey', $this->GetKey());
 		$oHistoryFilter->AddCondition('objclass', get_class($this));
 		$oBlock = new HistoryBlock($oHistoryFilter, 'toggle', false);
@@ -269,6 +269,8 @@ abstract class cmdbAbstractObject extends CMDBObject
 	//public static function GetDisplaySet(web_page $oPage, CMDBObjectSet $oSet, $sLinkageAttribute = '', $bDisplayMenu = true, $bSelectMode = false)
 	public static function GetDisplaySet(web_page $oPage, CMDBObjectSet $oSet, $aExtraParams = array())
 	{
+		global $g_oConfig;
+
 		static $iListId = 0;
 		$iListId++;
 		
@@ -341,7 +343,16 @@ abstract class cmdbAbstractObject extends CMDBObject
 		}
 		$aValues = array();
 		$oSet->Seek(0);
-		while ($oObj = $oSet->Fetch())
+		$bDisplayLimit = isset($aExtraParams['display_limit']) ? $aExtraParams['display_limit'] : true;
+		$iMaxObjects = -1;
+		if ($bDisplayLimit)
+		{
+			if ($oSet->Count() > $g_oConfig->GetMaxDisplayLimit())
+			{
+				$iMaxObjects = $g_oConfig->GetMinDisplayLimit();
+			}
+		}
+		while (($oObj = $oSet->Fetch()) && ($iMaxObjects != 0))
 		{
 			$aRow['key'] = $oObj->GetKey();
 			if ($bSelectMode)
@@ -354,6 +365,7 @@ abstract class cmdbAbstractObject extends CMDBObject
 				$aRow[$sAttCode] = $oObj->GetAsHTML($sAttCode);
 			}
 			$aValues[] = $aRow;
+			$iMaxObjects--;
 		}
 		$oMenuBlock = new MenuBlock($oSet->GetFilter());
 		$sHtml .= '<table class="listContainer">';
@@ -367,7 +379,22 @@ abstract class cmdbAbstractObject extends CMDBObject
 				//$aMenuExtraParams['linkage'] = $sLinkageAttribute;
 				$aMenuExtraParams = $aExtraParams;
 			}
-			$sHtml .= '<tr class="containerHeader"><td>&nbsp;'.$oSet->Count().' object(s)</td><td>';
+			if ($bDisplayLimit && ($oSet->Count() > $g_oConfig->GetMaxDisplayLimit()))
+			{
+				// list truncated
+				$divId = $aExtraParams['block_id'];
+				$sFilter = $oSet->GetFilter()->serialize();
+				$aExtraParams['display_limit'] = false; // To expand the full list
+				$sExtraParams = addslashes(str_replace('"', "'", json_encode($aExtraParams))); // JSON encode, change the style of the quotes and escape them
+				$sHtml .= '<tr class="containerHeader"><td>'.$g_oConfig->GetMinDisplayLimit().' object(s) displayed out of '.$oSet->Count().'&nbsp;&nbsp;<a href="Javascript:ReloadTruncatedList(\''.$divId.'\', \''.$sFilter.'\', \''.$sExtraParams.'\');">Display All</a></td><td>';
+				$oPage->add_ready_script("$('#{$divId} table.listResults').addClass('truncated');");
+				$oPage->add_ready_script("$('#{$divId} table.listResults tr:last td').addClass('truncated');");
+			}
+			else
+			{
+				// Full list
+				$sHtml .= '<tr class="containerHeader"><td>&nbsp;'.$oSet->Count().' object(s)</td><td>';
+			}
 			$sHtml .= $oMenuBlock->GetRenderContent($oPage, $aMenuExtraParams);
 			$sHtml .= '</td></tr>';
 		}
@@ -570,9 +597,11 @@ abstract class cmdbAbstractObject extends CMDBObject
 		$sHtml .= "</table>\n";
 		foreach($aExtraParams as $sName => $sValue)
 		{
-			$sHtml .= "<input type=\"hidden\" name=\"$sName\" value=\"$sValue\">\n";
+			$sHtml .= "<input type=\"hidden\" name=\"$sName\" value=\"$sValue\" />\n";
 		}
-		$sHtml .= "<input type=\"hidden\" name=\"dosearch\" value=\"1\">\n";
+		$sHtml .= "<input type=\"hidden\" name=\"class\" value=\"$sClassName\" />\n";
+		$sHtml .= "<input type=\"hidden\" name=\"dosearch\" value=\"1\" />\n";
+		$sHtml .= "<input type=\"hidden\" name=\"operation\" value=\"search_form\" />\n";
 		$sHtml .= "</form>\n";		
 		$sHtml .= "</div><!-- Simple search form -->\n";
 
@@ -598,7 +627,7 @@ abstract class cmdbAbstractObject extends CMDBObject
 		{
 			$sHtml .= "<input type=\"hidden\" name=\"$sName\" value=\"$sValue\" />\n";
 		}
-		$sHtml .= "<input type=\"hidden\" name=\"operation\" value=\"search_form\" />\n";
+		$sHtml .= "<input type=\"hidden\" name=\"operation\" value=\"search_oql\" />\n";
 		$sHtml .= "</table></form>\n";
 		$sHtml .= "</div><!-- OQL query form -->\n";
 		return $sHtml;

+ 8 - 1
application/displayblock.class.inc.php

@@ -144,7 +144,10 @@ class DisplayBlock
 	
 	public function Display(web_page $oPage, $sId, $aExtraParams = array())
 	{
+		$oPage->add($this->GetDisplay($oPage, $sId, $aExtraParams));
+		/*
 		$aExtraParams = array_merge($aExtraParams, $this->m_aParams);
+		$aExtraParams['block_id'] = $sId;
 		if (!$this->m_bAsynchronous)
 		{
 			// render now
@@ -171,12 +174,14 @@ class DisplayBlock
 			 );
 			 </script>'); // TO DO: add support for $aExtraParams in asynchronous/Ajax mode
 		}
+		*/
 	}
 	
 	public function GetDisplay(web_page $oPage, $sId, $aExtraParams = array())
 	{
 		$sHtml = '';
 		$aExtraParams = array_merge($aExtraParams, $this->m_aParams);
+		$aExtraParams['block_id'] = $sId;
 		if (!$this->m_bAsynchronous)
 		{
 			// render now
@@ -188,17 +193,19 @@ class DisplayBlock
 		{
 			// render it as an Ajax (asynchronous) call
 			$sFilter = $this->m_oFilter->serialize();
+			$sExtraParams = addslashes(str_replace('"', "'", json_encode($aExtraParams))); // JSON encode, change the style of the quotes and escape them
 			$sHtml .= "<div id=\"$sId\" class=\"display_block loading\">\n";
 			$sHtml .= $oPage->GetP("<img src=\"../images/indicator_arrows.gif\"> Loading...");
 			$sHtml .= "</div>\n";
 			$sHtml .= '
 			<script language="javascript">
 			$.get("ajax.render.php?filter='.$sFilter.'&style='.$this->m_sStyle.'",
-			   { operation: "ajax" },
+			   { operation: "ajax", extra_params: "'.$sExtraParams.'" },
 			   function(data){
 				 $("#'.$sId.'").empty();
 				 $("#'.$sId.'").append(data);
 				 $("#'.$sId.'").removeClass("loading");
+				 $("#'.$sId.' .listResults").tablesorter( { headers: { 0:{sorter: false }}, widgets: [\'zebra\']} ); // sortable and zebra tables
 				}
 			 );
 			 </script>'; // TO DO: add support for $aExtraParams in asynchronous/Ajax mode

+ 1 - 0
application/itopwebpage.class.inc.php

@@ -35,6 +35,7 @@ class iTopWebPage extends nice_web_page
 		$this->add_linked_script("../js/date.js");
 		$this->add_linked_script("../js/jquery.date.picker.js");
 		$this->add_linked_script("../js/jquery.tablesorter.min.js");
+		$this->add_linked_script("../js/utils.js");
 		//$this->add_linked_script("../js/jquery-ui-personalized-1.5.3.js");
 		$this->add_linked_script("../js/swfobject.js");
 		$this->add_linked_stylesheet("../css/jquery.treeview.css");

+ 2 - 0
application/startup.inc.php

@@ -2,6 +2,8 @@
 
 require_once('../application/utils.inc.php');
 
+$g_oConfig = new Config('../config-itop.php');
+
 MetaModel::Startup('../config-itop.php');
 
 ?>

+ 4 - 3
application/uilinkswizard.class.inc.php

@@ -159,6 +159,7 @@ class UILinksWizard
 						{
 							$('#SearchResultsToAdd table.listResults tbody').attr('height', tbodyHeight);
 							$('#SearchResultsToAdd .listResults tbody').css('overflow', 'auto');
+							$('#SearchResultsToAdd .listResults').tablesorter( { headers: { 0:{sorter: false }}, widgets: ['zebra']} ); // sortable and zebra tables
 						}
 					}
 					
@@ -214,7 +215,7 @@ class UILinksWizard
 					}
 					$('.listResults tbody').append(data);
 					$('.listResults').trigger('update');
-					$('.listResults').tablesorter( { headers: { 0:{sorter: false }}, widgets: ['zebra']} ); // sortable and zebra tables 
+					$('.listResults').tablesorter( { headers: { 0:{sorter: false }}, widgets: ['zebra']} ); // sortable and zebra tables
 				},
 				'html'
 			);
@@ -362,12 +363,12 @@ class UILinksWizard
 
 	public function SearchObjectsToAdd(web_page $oP, UserContext $oContext)
 	{
-		$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $this->m_sLinkageAttr);
+		//$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $this->m_sLinkageAttr);
 
 		$oFilter = $oContext->NewFilter($this->m_sLinkedClass);
 		$oSet = new CMDBObjectSet($oFilter);
 		$oBlock = new DisplayBlock($oFilter, 'list', false);
-		$oBlock->Display($oP, 'ResultsToAdd', array('menu' => false, 'selection_mode' => true)); // Don't display the 'Actions' menu on the results
+		$oBlock->Display($oP, 'ResultsToAdd', array('menu' => false, 'selection_mode' => true, 'display_limit' => false)); // Don't display the 'Actions' menu on the results
 	}
 	
 	public function DoAddObjects(web_page $oP, UserContext $oContext, $aLinkedObjectIds = array())

+ 21 - 0
css/light-grey.css

@@ -663,3 +663,24 @@ div.HRDrawer {
 .mandatory {
 	border: 1px solid #f00;
 }
+table.listResults tr td.truncated {
+	background: transparent;
+}
+
+table.listResults tr td.truncated {
+	background: url(../images/truncated.png) bottom  repeat-x;
+	margin-bottom: -3px;
+}
+
+table.listResults tr.even td.truncated {
+	background: #f9f9f1 url(../images/truncated.png) bottom  repeat-x;
+}
+
+table.listResults tr.even td.truncated.hover {
+	background: #E8FFD3 url(../images/truncated.png) bottom  repeat-x;
+}
+
+table.listResults.truncated {
+	border-bottom: 0;
+	padding-bottom: 0;
+}

+ 19 - 0
js/utils.js

@@ -0,0 +1,19 @@
+// Some general purpose JS functions for the iTop application
+/**
+ * Reload a truncated list
+ */ 
+function ReloadTruncatedList(divId, sSerializedFilter, sExtraParams)
+{
+	$('#'+divId).addClass('loading');
+	//$('#'+divId).blockUI();
+	$.get('ajax.render.php?filter='+sSerializedFilter+'&style=list',
+	   { operation: 'ajax', extra_params: sExtraParams },
+	   function(data){
+		 $('#'+divId).empty();
+		 $('#'+divId).append(data);
+		 $('#'+divId).removeClass('loading');
+		 $('#'+divId+' .listResults').tablesorter( { headers: { 0:{sorter: false }}, widgets: ['zebra']} ); // sortable and zebra tables
+		 //$('#'+divId).unblockUI();
+		}
+	 );
+}

+ 37 - 4
pages/UI.php

@@ -74,7 +74,7 @@ switch($operation)
 		}
 	break;
 	
-	case 'search_form':
+	case 'search_oql':
 		$sOQLClass = utils::ReadParam('oql_class', '');
 		$sOQLClause = utils::ReadParam('oql_clause', '');
 		$sFormat = utils::ReadParam('format', '');
@@ -128,7 +128,39 @@ switch($operation)
 			}
 		}
 	break;
-	
+	case 'search_form':
+		$sClass = utils::ReadParam('class', '');
+		$sFormat = utils::ReadParam('format', 'html');
+		$bSearchForm = utils::ReadParam('search_form', true);
+		if (empty($sClass))
+		{
+			$oP->set_title("iTop - Error");
+			$oP->add("<p>'class' must be specifed for this operation.</p>\n");
+		}
+		else
+		{
+			$oP->set_title("iTop - Search results");
+			$oFilter =  $oContext->NewFilter($sClass);
+			$oSet = new DBObjectSet($oFilter);
+			if ($bSearchForm)
+			{
+				$oBlock = new DisplayBlock($oFilter, 'search', false /* Asynchronous */, array('open' => true));
+				$oBlock->Display($oP, 0);
+			}
+			if (strtolower($sFormat) == 'csv')
+			{
+				$oBlock = new DisplayBlock($oFilter, 'csv', false);
+				$oBlock->Display($oP, 1);
+				$oP->add_ready_script(" $('#csv').css('height', '95%');"); // adjust the size of the block
+			}
+			else
+			{
+				$oBlock = new DisplayBlock($oFilter, 'list', false);
+				$oBlock->Display($oP, 1);
+			}
+		}
+	break;
+		
 	case 'search':
 		$sFilter = utils::ReadParam('filter', '');
 		$sFormat = utils::ReadParam('format', '');
@@ -158,7 +190,7 @@ switch($operation)
 			else
 			{
 				$oBlock = new DisplayBlock($oFilter, 'list', false);
-				$oBlock->Display($oP, 0);
+				$oBlock->Display($oP, 1);
 			}
 		}
 	break;
@@ -173,6 +205,7 @@ switch($operation)
 		{
 			$oP->p("<h2>Results for '$sFullText':</h2>\n");
 			$iCount = 0;
+			$iBlock = 0;
 			// Search in full text mode in all the classes
 			foreach(MetaModel::GetClasses('bizmodel') as $sClassName)
 			{
@@ -198,7 +231,7 @@ switch($operation)
 						$oP->add("</div>\n");
 						$oLeafsFilter->AddCondition('pkey', $aLeafs, 'IN');
 						$oBlock = new DisplayBlock($oLeafsFilter, 'list', false);
-						$oBlock->Display($oP, 0);
+						$oBlock->Display($oP, $iBlock++);
 					}
 				}
 			}

+ 2 - 2
pages/UniversalSearch.php

@@ -73,11 +73,11 @@ if ($oFilter != null)
 {
 	$oSet = new CMDBObjectSet($oFilter);
 	$oBlock = new DisplayBlock($oFilter, 'search', false);
-	$oBlock->Display($oP, 0);
+	$oBlock->Display($oP, 0, array('open' => true));
 
 	// Search results	
 	$oResultBlock = new DisplayBlock($oFilter, 'list', false);
-	$oResultBlock->RenderContent($oP);
+	$oResultBlock->Display($oP, 1);
 	
 	// Menu node
 	$sFilter = $oFilter->ToOQL();

+ 7 - 1
pages/ajax.render.php

@@ -100,6 +100,12 @@ switch($operation)
 	case 'ajax':
 	if ($sFilter != "")
 	{
+		$sExtraParams = stripslashes(utils::ReadParam('extra_params', ''));
+		$aExtraParams = array();
+		if (!empty($sExtraParams))
+		{
+			$aExtraParams = json_decode(str_replace("'", '"', $sExtraParams), true /* associative array */);
+		}
 		if ($sEncoding == 'sibusql')
 		{
 			$oFilter = CMDBSearchFilter::FromSibusQL($sFilter);
@@ -109,7 +115,7 @@ switch($operation)
 			$oFilter = CMDBSearchFilter::unserialize($sFilter);
 		}
 		$oDisplayBlock = new DisplayBlock($oFilter, $sStyle, false);
-		$oDisplayBlock->RenderContent($oPage);
+		$oDisplayBlock->RenderContent($oPage, $aExtraParams);
 	}
 	else
 	{

+ 2 - 2
pages/run_query.php

@@ -109,8 +109,8 @@ try
 		{
 			$oP->add("<h3>Query results</h3>\n");
 			
-			$oSet = new CMDBObjectSet($oFilter);
-			cmdbAbstractObject::DisplaySet($oP, $oSet);
+			$oResultBlock = new DisplayBlock($oFilter, 'list', false);
+			$oResultBlock->Display($oP, 1);
 
 			$oP->p('');
 			$oP->StartCollapsibleSection('More info on the query', false);

+ 1 - 1
webservices/export.php

@@ -47,7 +47,7 @@ if (!empty($sExpression))
 				}
 				$sUrl = "$sProtocol://{$sServerName}{$sPort}/pages/";
 				$oP->set_base($sUrl);
-				cmdbAbstractObject::DisplaySet($oP, $oSet, array('menu' => false));
+				cmdbAbstractObject::DisplaySet($oP, $oSet, array('menu' => false, 'display_limit' => false)); // no menu, no truncated list
 				break;
 				
 				case 'csv':