Ver código fonte

Revised the CSV import: fixed issues with the external keys, added hyperlinks to the found objects, obsoleted the word 'pkey', replaced by 'id'

git-svn-id: http://svn.code.sf.net/p/itop/code/trunk@154 a333f486-631f-4898-b8df-5754b55c2be0
romainq 15 anos atrás
pai
commit
a292aaef1d

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

@@ -74,12 +74,6 @@ abstract class cmdbAbstractObject extends CMDBObject
 		return "<a href=\"$sPage?operation=details&class=$sObjClass&id=$sObjKey&".$oAppContext->GetForLink()."\" title=\"$sHint\">$sLabel</a>";
 	}
 
-	public function GetHyperlink()
-	{
-		$aAvailableFields[MetaModel::GetNameAttributeCode(get_class($this))] = $this->GetName();
-		return $this->MakeHyperLink(get_class($this), $this->GetKey(), $aAvailableFields);
-	}
-
 	public function GetDisplayValue($sAttCode)
 	{
 		$sDisplayValue = "";

+ 73 - 30
core/bulkchange.class.inc.php

@@ -37,36 +37,55 @@ abstract class CellChangeSpec
 		$this->m_proposedValue = $proposedValue;
 	}
 
-	public function GetValue()
+	static protected function ValueAsHtml($value)
 	{
-		return $this->m_proposedValue; 
+		if (MetaModel::IsValidObject($value))
+		{
+			return $value->GetHyperLink();
+		}
+		else
+		{
+			return htmlentities($value);
+		}
+	}
+
+	public function GetValue($bHtml = false)
+	{
+		if ($bHtml)
+		{
+			return self::ValueAsHtml($this->m_proposedValue);
+		}
+		else
+		{
+			return $this->m_proposedValue;
+		}
 	}
 
-	abstract public function GetDescription();
+	abstract public function GetDescription($bHtml = false);
 }
 
 
 class CellChangeSpec_Void extends CellChangeSpec
 {
-	public function GetDescription()
+	public function GetDescription($bHtml = false)
 	{
-		return $this->GetValue();
+		return $this->GetValue($bHtml);
 	}
 }
 
 class CellChangeSpec_Unchanged extends CellChangeSpec
 {
-	public function GetDescription()
+	public function GetDescription($bHtml = false)
 	{
-		return $this->GetValue()." (unchanged)";
+		return $this->GetValue($bHtml)." (unchanged)";
 	}
 }
 
 class CellChangeSpec_Init extends CellChangeSpec
 {
-	public function GetDescription()
+	public function GetDescription($bHtml = false)
 	{
-		return $this->GetValue();
+		return $this->GetValue($bHtml);
 	}
 }
 
@@ -80,9 +99,9 @@ class CellChangeSpec_Modify extends CellChangeSpec
 		parent::__construct($proposedValue);
 	}
 
-	public function GetDescription()
+	public function GetDescription($bHtml = false)
 	{
-		return $this->GetValue()." (previous: ".$this->m_previousValue.")";
+		return $this->GetValue($bHtml)." (previous: ".self::ValueAsHtml($this->m_previousValue).")";
 	}
 }
 
@@ -96,13 +115,13 @@ class CellChangeSpec_Issue extends CellChangeSpec_Modify
 		parent::__construct($proposedValue, $previousValue);
 	}
 
-	public function GetDescription()
+	public function GetDescription($bHtml = false)
 	{
 		if (is_null($this->m_proposedValue))
 		{
 			return 'Could not be changed - reason: '.$this->m_sReason;
 		}
-		return 'Could not be changed to "'.$this->GetValue().'" - reason: '.$this->m_sReason.' (previous: '.$this->m_previousValue.')';
+		return 'Could not be changed to "'.$this->GetValue($bHtml).'" - reason: '.$this->m_sReason.' (previous: '.$this->m_previousValue.')';
 	}
 }
 
@@ -124,12 +143,12 @@ abstract class RowStatus
 	{
 	}
 
-	abstract public function GetDescription();
+	abstract public function GetDescription($bHtml = false);
 }
 
 class RowStatus_NoChange extends RowStatus
 {
-	public function GetDescription()
+	public function GetDescription($bHtml = false)
 	{
 		return "unchanged";
 	}
@@ -139,12 +158,13 @@ class RowStatus_NewObj extends RowStatus
 {
 	protected $m_iObjKey;
 
-	public function __construct($iObjKey = null)
+	public function __construct($sClass = '', $iObjKey = null)
 	{
 		$this->m_iObjKey = $iObjKey;
+		$this->m_sClass = $sClass;
 	}
 
-	public function GetDescription()
+	public function GetDescription($bHtml = false)
 	{
 		if (is_null($this->m_iObjKey))
 		{
@@ -152,7 +172,15 @@ class RowStatus_NewObj extends RowStatus
 		}
 		else
 		{
-			return 'Created ('.$this->m_iObjKey.')';
+			if (empty($this->m_sClass))
+			{
+				$oObj = MetaModel::GetObject($this->m_sClass, $this->m_iObjKey);
+				return 'Created '.$oObj->GetHyperLink();
+			}
+			else
+			{
+				return 'Created (id: '.$this->m_iObjKey.')';
+			}
 		}	
 	}
 }
@@ -166,7 +194,7 @@ class RowStatus_Modify extends RowStatus
 		$this->m_iChanged = $iChanged;
 	}
 
-	public function GetDescription()
+	public function GetDescription($bHtml = false)
 	{
 		return "update ".$this->m_iChanged." cols";
 	}
@@ -181,7 +209,7 @@ class RowStatus_Issue extends RowStatus
 		$this->m_sReason = $sReason;
 	}
 
-	public function GetDescription()
+	public function GetDescription($bHtml = false)
 	{
 		return 'Skipped - reason:'.$this->m_sReason;
 	}
@@ -217,6 +245,19 @@ class BulkChange
 		$this->m_aExtKeys = $aExtKeys;
 	}
 
+	static protected function MakeSpecObject($sClass, $iId)
+	{
+		$oObj = MetaModel::GetObject($sClass, $iId);
+		if (is_null($oObj))
+		{
+			return $iId;
+		}
+		else
+		{
+			return $oObj;
+		}
+	}
+
 	protected function PrepareObject(&$oTargetObj, $aRowData, &$aErrors)
 	{
 		$aResults = array();
@@ -250,23 +291,26 @@ class BulkChange
 				// Report it
 				if (array_key_exists($sAttCode, $oTargetObj->ListChanges()))
 				{
+
 					if ($oTargetObj->IsNew())
 					{
-						$aResults[$sAttCode]= new CellChangeSpec_Init($oForeignObj->GetKey(), $oTargetObj->Get($sAttCode), $oTargetObj->GetOriginal($sAttCode));
+						$aResults[$sAttCode]= new CellChangeSpec_Init($oForeignObj);
 					}
 					else
 					{
-						$aResults[$sAttCode]= new CellChangeSpec_Modify($oForeignObj->GetKey(), $oTargetObj->Get($sAttCode), $oTargetObj->GetOriginal($sAttCode));
+						$previousValue = self::MakeSpecObject($oExtKey->GetTargetClass(), $oTargetObj->GetOriginal($sAttCode));
+						$aResults[$sAttCode]= new CellChangeSpec_Modify($oForeignObj, $previousValue);
 					}
 				}
 				else
 				{
-					$aResults[$sAttCode]= new CellChangeSpec_Unchanged($oTargetObj->Get($sAttCode));
+					$aResults[$sAttCode]= new CellChangeSpec_Unchanged($oForeignObj);
 				}
 				break;
 			default:
 				$aErrors[$sAttCode] = "Found ".$oExtObjects->Count()." matches";
-				$aResults[$sAttCode]= new CellChangeSpec_Issue(null, $oTargetObj->Get($sAttCode), "Found ".$oExtObjects->Count()." matches");
+				$previousValue = self::MakeSpecObject($oExtKey->GetTargetClass(), $oTargetObj->Get($sAttCode));
+				$aResults[$sAttCode]= new CellChangeSpec_Issue(null, $previousValue, "Found ".$oExtObjects->Count()." matches");
 			}
 		}	
 	
@@ -291,18 +335,17 @@ class BulkChange
 		{
 			if (isset($aErrors[$sAttCode]))
 			{
-				$aResults["col$iCol"]= new CellChangeSpec_Issue($aRowData[$iCol], $oTargetObj->Get($sAttCode), $aErrors[$sAttCode]);
+				$aResults["col$iCol"]= new CellChangeSpec_Issue($oTargetObj->Get($sAttCode), $oTargetObj->GetOriginal($sAttCode), $aErrors[$sAttCode]);
 			}
 			elseif (array_key_exists($sAttCode, $aChangedFields))
 			{
-				$originalValue = $oTargetObj->GetOriginal($sAttCode);
 				if ($oTargetObj->IsNew())
 				{
-					$aResults["col$iCol"]= new CellChangeSpec_Init($aRowData[$iCol], $oTargetObj->Get($sAttCode), $originalValue);
+					$aResults["col$iCol"]= new CellChangeSpec_Init($oTargetObj->Get($sAttCode));
 				}
 				else
 				{
-					$aResults["col$iCol"]= new CellChangeSpec_Modify($aRowData[$iCol], $oTargetObj->Get($sAttCode), $originalValue);
+					$aResults["col$iCol"]= new CellChangeSpec_Modify($oTargetObj->Get($sAttCode), $oTargetObj->GetOriginal($sAttCode));
 				}
 			}
 			else
@@ -358,7 +401,7 @@ class BulkChange
 		if ($oChange)
 		{
 			$newID = $oTargetObj->DBInsertTrackedNoReload($oChange);
-			$aResult[$iRow]["__STATUS__"] = new RowStatus_NewObj($newID);
+			$aResult[$iRow]["__STATUS__"] = new RowStatus_NewObj($this->m_sClass, $newID);
 		}
 		else
 		{
@@ -424,7 +467,7 @@ class BulkChange
 			case 1:
 				$oTargetObj = $oReconciliationSet->Fetch();
 				$this->UpdateObject($aResult, $iRow, $oTargetObj, $aRowData, $oChange);
-				$aResult[$iRow]["__RECONCILIATION__"] = "Found a match ".$oTargetObj->GetKey();
+				$aResult[$iRow]["__RECONCILIATION__"] = "Found a match ".$oTargetObj->GetHyperLink();
 				// $aResult[$iRow]["__STATUS__"]=> set in UpdateObject
 				break;
 			default:

+ 24 - 5
core/cmdbobject.class.inc.php

@@ -154,7 +154,7 @@ abstract class CMDBObject extends DBObject
 		$oMyChangeOp->Set("objkey", $objkey);
 		$iId = $oMyChangeOp->DBInsertNoReload();
 	}
-	private function RecordAttChanges(CMDBChange $oChange, array $aValues)
+	private function RecordAttChanges(CMDBChange $oChange, array $aValues, array $aOrigValues)
 	{
 		// $aValues is an array of $sAttCode => $value
 		//
@@ -167,7 +167,15 @@ abstract class CMDBObject extends DBObject
 			$oMyChangeOp->Set("objclass", get_class($this));
 			$oMyChangeOp->Set("objkey", $this->GetKey());
 			$oMyChangeOp->Set("attcode", $sAttCode);
-			$oMyChangeOp->Set("oldvalue", $this->GetOriginal($sAttCode));
+			if (array_key_exists($sAttCode, $aOrigValues))
+			{
+				$sOriginalValue = $aOrigValues[$sAttCode];
+			}
+			else
+			{
+				$sOriginalValue = 'undefined';
+			}
+			$oMyChangeOp->Set("oldvalue", $sOriginalValue);
 			$oMyChangeOp->Set("newvalue", $value);
 			$iId = $oMyChangeOp->DBInsertNoReload();
 		}
@@ -262,9 +270,11 @@ abstract class CMDBObject extends DBObject
 			throw new CoreWarning("Attempting to update an unchanged object");
 			return;
 		}
-
+		
+		// Save the original values (will be reset to the new values when the object get written to the DB)
+		$aOriginalValues = $this->m_aOrigValues;
 		$ret = parent::DBUpdate();
-		$this->RecordAttChanges(self::$m_oCurrChange, $aChanges);
+		$this->RecordAttChanges(self::$m_oCurrChange, $aChanges, $aOriginalValues);
 		return $ret;
 	}
 
@@ -355,14 +365,23 @@ abstract class CMDBObject extends DBObject
 		$oObjSet = new CMDBObjectSet($oFilter);
 		$oObjSet->Load();
 
+		// Keep track of the previous values (will be overwritten when the objects are synchronized with the DB)
+		$aOriginalValues = array();
+		$oObjSet->Rewind();
+		while ($oItem = $oObjSet->Fetch())
+		{
+			$aOriginalValues[$oItem->GetKey()] = $oItem->m_aOrigValues;
+		}
+
 		// Update in one single efficient query
 		$ret = parent::BulkUpdate($oFilter, $aValues);
 
 		// Record... in many queries !!!
+		$oObjSet->Rewind();
 		while ($oItem = $oObjSet->Fetch())
 		{
 			$aChangedValues = $oItem->ListChangedValues($aValues);
-			$oItem->RecordAttChanges(self::$m_oCurrChange, $aChangedValues);
+			$oItem->RecordAttChanges(self::$m_oCurrChange, $aChangedValues, $aOriginalValues[$oItem->GetKey()]);
 		}
 		return $ret;
 	}

+ 22 - 10
core/dbobject.class.php

@@ -33,7 +33,7 @@ abstract class DBObject
 	private $m_bIsInDB = false; // true IIF the object is mapped to a DB record
 	private $m_iKey = null;
 	private $m_aCurrValues = array();
-	private $m_aOrigValues = array();
+	protected $m_aOrigValues = array();
 
 	private $m_bFullyLoaded = false; // Compound objects can be partially loaded
 	private $m_aLoadedAtt = array(); // Compound objects can be partially loaded, array of sAttCode
@@ -217,6 +217,12 @@ abstract class DBObject
 	
 	public function Set($sAttCode, $value)
 	{
+		if ($sAttCode == 'finalclass')
+		{
+			// Ignore it - this attribute is set upon object creation and that's it
+			//throw new CoreWarning('Attempting to set the value for the internal attribute \"finalclass\"', array('current value'=>$this->Get('finalclass'), 'new value'=>$value));
+			return;
+		}
 		if (!array_key_exists($sAttCode, MetaModel::ListAttributeDefs(get_class($this))))
 		{
 			throw new CoreException("Unknown attribute code '$sAttCode' for the class ".get_class($this));
@@ -348,15 +354,7 @@ abstract class DBObject
 			}
 
 			$sTargetClass = $oAtt->GetTargetClass(EXTKEY_ABSOLUTE);
-			$aMakeHLink = array(get_class($this), 'MakeHyperLink');
-			if (is_callable($aMakeHLink))
-			{
-				return call_user_func($aMakeHLink, $sTargetClass, $this->Get($sAttCode), $aAvailableFields);
-			}
-			else
-			{
-				return $this->Get($sAttCode);
-			}
+			return $this->MakeHyperLink($sTargetClass, $this->Get($sAttCode), $aAvailableFields);
 		}
 
 		// That's a standard attribute (might be an ext field or a direct field, etc.)
@@ -375,6 +373,20 @@ abstract class DBObject
 		return $oAtt->GetAsCSV($this->Get($sAttCode), $sSeparator, $sSepEscape);
 	}
 
+	protected static function MakeHyperLink($sObjClass, $sObjKey, $aAvailableFields)
+	{
+		if ($sObjKey == 0) return '<em>undefined</em>';
+
+		return MetaModel::GetName($sObjClass)."::$sObjKey";
+	}
+
+	public function GetHyperlink()
+	{
+		$aAvailableFields[MetaModel::GetNameAttributeCode(get_class($this))] = $this->GetName();
+		return $this->MakeHyperLink(get_class($this), $this->GetKey(), $aAvailableFields);
+	}
+
+
 	// could be in the metamodel ?
 	public static function IsValidPKey($value)
 	{

+ 6 - 0
core/metamodel.class.php

@@ -2636,6 +2636,12 @@ abstract class MetaModel
 		return self::GetObjectByRow($sClass, $aRow);
 	}
 
+	public static function GetHyperLink($sTargetClass, $sOldValue)
+	{
+		$oObj = self::GetObject($sTargetClass, $sOldValue);
+		return $oObj->GetHyperLink();
+	}
+
 	public static function NewObject($sClass)
 	{
 		self::_check_subclass($sClass);

+ 105 - 46
pages/csvimport.php

@@ -38,9 +38,17 @@ function GetExtKeyFieldCodes($sColDesc)
 function MakeExtFieldLabel($sClass, $sExtKeyAttCode, $sForeignAttCode)
 {
 	$oExtKeyAtt = MetaModel::GetAttributeDef($sClass, $sExtKeyAttCode);
-	$oForeignAtt = MetaModel::GetAttributeDef($oExtKeyAtt->GetTargetClass(), $sForeignAttCode);
+	if ($sForeignAttCode == 'id')
+	{
+		$sForeignAttLabel = 'id';
+	}
+	else
+	{
+		$oForeignAtt = MetaModel::GetAttributeDef($oExtKeyAtt->GetTargetClass(), $sForeignAttCode);
+		$sForeignAttLabel = $oForeignAtt->GetLabel();
+	}
 	
-	return $oExtKeyAtt->GetLabel().EXTKEY_LABELSEP.$oForeignAtt->GetLabel();
+	return $oExtKeyAtt->GetLabel().EXTKEY_LABELSEP.$sForeignAttLabel;
 }
 
 function MakeExtFieldSelectValue($sAttCode, $sExtAttCode)
@@ -67,27 +75,33 @@ function ShowTableForm($oPage, $oCSVParser, $sClass)
 	$aFields = array();
 	foreach($oCSVParser->ListFields() as $iFieldIndex=>$sFieldName)
 	{
-		$sSelField = "<select name=\"fmap[field$iFieldIndex]\">";
-		$sSelField .= "<option value=\"__none__\">None (ignore)</option>";
-		$sSELECTED = (strcasecmp($sFieldName, "pkey") == 0) ? " SELECTED" : "";
-		$sSelField .= "<option value=\"pkey\"$sSELECTED>Private Key</option>";
+		$aOptions = array();
+		$aOptions['id'] = array(
+			'LabelHtml' => "Private key",
+			'LabelRef' => "Private key",
+			'IsReconcKey' => false,
+			'Tip' => '',
+		);
+
 		$sFoundAttCode = ""; // quick and dirty way to remind if a match has been found and suggest a reconciliation key if possible
 		foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode=>$oAtt)
 		{
 			if ($oAtt->IsExternalField()) continue;
 
 			$bIsThatField = (strcasecmp($sFieldName, $oAtt->GetLabel()) == 0);
-			//$sIsReconcKey = (MetaModel::IsValidFilterCode($sClass, $sAttCode)) ? " [key]" : "";
-			$sIsReconcKey = MetaModel::IsReconcKey($sClass, $sAttCode) ? " [rk!]" : "";
 			$sFoundAttCode = (MetaModel::IsValidFilterCode($sClass, $sAttCode) && $bIsThatField) ? $sAttCode : $sFoundAttCode; 
-			$sSELECTED = $bIsThatField ? " SELECTED" : "";
 
 			if ($oAtt->IsExternalKey())
 			{
 				// An external key might be loaded by
 				// the pkey or a reconciliation key
 				//
-				$sSelField .= "<option value=\"$sAttCode\"$sSELECTED><em>".$oAtt->GetLabel()."</em> (pkey)$sIsReconcKey</option>";
+				$aOptions[MakeExtFieldSelectValue($sAttCode, 'id')] = array(
+					'LabelHtml' => "<em>".$oAtt->GetLabel()."</em> (id)",
+					'LabelRef' => $oAtt->GetLabel()." (id)",
+					'IsReconcKey' => MetaModel::IsReconcKey($sClass, $sAttCode),
+					'Tip' => '',
+				);
 
 				$sRemoteClass = $oAtt->GetTargetClass();
 				foreach(MetaModel::GetReconcKeys($sRemoteClass) as $sExtAttCode)
@@ -104,35 +118,79 @@ function ShowTableForm($oPage, $oCSVParser, $sClass)
 					{
 						if ($oExtFieldAtt->GetExtAttCode() == $sExtAttCode)
 						{
-							$sLabel2 = $oExtFieldAtt->GetLabel();
-
-							$bIsThatField = (strcasecmp($sFieldName, $sLabel2) == 0);
-							$sSELECTED = $bIsThatField ? " SELECTED" : "";
-							$sTITLE = " title=\"equivalent to '".htmlentities($sLabel1)."'\"";
-							$sSelField .= "<option value=\"$sValue\"$sTITLE $sSELECTED>".htmlentities($sLabel2)."</option>";
+							$aOptions[$sValue] = array(
+								'LabelHtml' => htmlentities($oExtFieldAtt->GetLabel()),
+								'LabelRef' => $oExtFieldAtt->GetLabel(),
+								'IsReconcKey' => false,
+								'Tip' => "equivalent to '".htmlentities($sLabel1)."'",
+							);
 							$bFoundTwin = true;
+							$sLabel2 = $oExtFieldAtt->GetLabel();
 							break;
 						}
 					}
 
-					$bIsThatField = (strcasecmp($sFieldName, $sLabel1) == 0);
-					$sSELECTED = $bIsThatField ? " SELECTED" : "";
-					$sTITLE = $bFoundTwin ? " title=\"equivalent to '".htmlentities($sLabel2)."'\"" : "";
-					$sSelField .= "<option value=\"$sValue\"$sTITLE $sSELECTED>".htmlentities($sLabel1)."</option>";
+					$aOptions[$sValue] = array(
+						'LabelHtml' => htmlentities($sLabel1),
+						'LabelRef' => $sLabel1,
+						'IsReconcKey' => false,
+						'Tip' => $bFoundTwin ? "equivalent to '".htmlentities($sLabel2)."'" : "",
+					);
 				}
 			}
 			else
 			{
-				$sSelField .= "<option value=\"$sAttCode\"$sSELECTED>".$oAtt->GetLabel()."$sIsReconcKey</option>";
+				$aOptions[$sAttCode] = array(
+					'LabelHtml' => htmlentities($oAtt->GetLabel()),
+					'LabelRef' => $oAtt->GetLabel(),
+					'IsReconcKey' => MetaModel::IsReconcKey($sClass, $sAttCode),
+					'Tip' => '',
+				);
+			}
+		}
+
+		// Find the best match
+		$iMin = strlen($sFieldName);
+		$sBestValue = null;
+		foreach ($aOptions as $sValue => $aData)
+		{
+			$iDist = levenshtein(strtolower($sFieldName), strtolower($aData['LabelRef']));
+			if (($iDist != -1) && ($iDist < $iMin))
+			{
+				$iMin = $iDist;
+				$sBestValue = $sValue;
+			}
+		}
+
+		$sSelField = "<select name=\"fmap[field$iFieldIndex]\">";
+		foreach ($aOptions as $sValue => $aData)
+		{
+			$sStyle = '';
+			$sComment = '';
+			$sSELECTED = '';
+			if ($sValue == $sBestValue)
+			{
+				$sSELECTED = ' SELECTED';
+				if ($iMin > 0)
+				{
+					$sStyle = " style=\"background-color: #ffdddd;\"";
+					$sComment = '- suggested';
+				}
 			}
+
+			$sIsRecondKey = $aData['IsReconcKey'] ? " [rk!]" : "";
+			$sSelField .= "<option value=\"$sValue\" title=\"".$aData['Tip']."\"$sStyle$sSELECTED>".$aData['LabelHtml']."$sComment$sIsRecondKey</option>\n";
 		}
 		$sSelField .= "</select>";
-		
-		$sCHECKED = ($sFieldName == "pkey" || MetaModel::IsReconcKey($sClass, $sFoundAttCode)) ? " CHECKED" : "";
-		$sSelField .= "&nbsp;<input type=\"checkbox\" name=\"iskey[field$iFieldIndex]\" value=\"yes\" $sCHECKED>";
+		$aFields["field$iFieldIndex"]["label"] = $sSelField; 
+
+		$sCHECKED = ($sFieldName == "id" || MetaModel::IsReconcKey($sClass, $sFoundAttCode)) ? " CHECKED" : "";
+		$aFields["field$iFieldIndex"]["label"] .= "<input type=\"checkbox\" name=\"iskey[field$iFieldIndex]\" value=\"yes\" $sCHECKED>";
 
-		$aFields["field$iFieldIndex"]["label"] = $sSelField;
-		$aFields["field$iFieldIndex"]["value"] = $aColToRow[$iFieldIndex];
+		if (array_key_exists($iFieldIndex, $aColToRow))
+		{
+			$aFields["field$iFieldIndex"]["value"] = $aColToRow[$iFieldIndex];
+		}
 	}
 	$oPage->details($aFields);
 }
@@ -151,7 +209,7 @@ function ProcessData($oPage, $sClass, $oCSVParser, $aFieldMap, $aIsReconcKey, CM
 	foreach($aFieldMap as $sFieldId=>$sColDesc)
 	{
 		$iFieldId = (int) substr($sFieldId, strlen("field"));
-		if ($sColDesc == "pkey")
+		if ($sColDesc == "id")
 		{
 			// Skip !
 			$iPKeyId = $iFieldId;
@@ -162,18 +220,19 @@ function ProcessData($oPage, $sClass, $oCSVParser, $aFieldMap, $aIsReconcKey, CM
 		}
 		elseif (IsExtKeyField($sColDesc))
 		{
+			// This field is value to search on, to find a value for an external key
 			list($sExtKeyAttCode, $sExtReconcKeyAttCode) = GetExtKeyFieldCodes($sColDesc);
 			$aExtKeys[$sExtKeyAttCode][$sExtReconcKeyAttCode] = $iFieldId;
 		}
 		elseif (array_key_exists($sFieldId, $aIsReconcKey))
 		{
+			// This value is a reconciliation key
 			$aReconcilKeys[$sColDesc] = $iFieldId;
 			$aAttList[$sColDesc] = $iFieldId; // A reconciliation key is also a field
 		}
 		else
 		{
 			// $sColDesc is an attribute code
-			//
 			$aAttList[$sColDesc] = $iFieldId;
 		}
 	}
@@ -182,10 +241,10 @@ function ProcessData($oPage, $sClass, $oCSVParser, $aFieldMap, $aIsReconcKey, CM
 	//
 	$aDisplayConfig = array();
 	$aDisplayConfig["__RECONCILIATION__"] = array("label"=>"Reconciliation", "description"=>"");
-	$aDisplayConfig["__STATUS__"] = array("label"=>"Status", "description"=>"");
+	$aDisplayConfig["__STATUS__"] = array("label"=>"Import status", "description"=>"");
 	if (isset($iPKeyId))
 	{
-		$aDisplayConfig["col$iPKeyId"] = array("label"=>"<strong>pkey</strong>", "description"=>"");
+		$aDisplayConfig["col$iPKeyId"] = array("label"=>"<strong>id</strong>", "description"=>"");
 	}
 	foreach($aReconcilKeys as $sAttCode => $iCol)
 	{
@@ -223,13 +282,12 @@ function ProcessData($oPage, $sClass, $oCSVParser, $aFieldMap, $aIsReconcKey, CM
 		$aExtKeys
 	);
 	$aRes = $oBulk->Process($oChange);
-
 	$aResultDisp = array(); // to be displayed
 	foreach($aRes as $iRow => $aRowData)
 	{
 		$aRowDisp = array();
 		$aRowDisp["__RECONCILIATION__"] = $aRowData["__RECONCILIATION__"];
-		$aRowDisp["__STATUS__"] = $aRowData["__STATUS__"]->GetDescription();
+		$aRowDisp["__STATUS__"] = $aRowData["__STATUS__"]->GetDescription(true);
 		foreach($aRowData as $sKey => $value)
 		{
 			if ($sKey == '__RECONCILIATION__') continue;
@@ -255,11 +313,11 @@ function ProcessData($oPage, $sClass, $oCSVParser, $aFieldMap, $aIsReconcKey, CM
 			}
 			if (empty($sClass))
 			{
-				$aRowDisp[$sKey] = $value->GetDescription();
+				$aRowDisp[$sKey] = $value->GetDescription(true);
 			}
 			else
 			{
-				$aRowDisp[$sKey] = "<div class=\"$sClass\">".$value->GetDescription()."</div>";
+				$aRowDisp[$sKey] = "<div class=\"$sClass\">".$value->GetDescription(true)."</div>";
 			}
 		}
 		$aResultDisp[$iRow] = $aRowDisp;
@@ -297,7 +355,7 @@ function Do_Welcome($oPage, $sClass)
 		$aList = MetaModel::GetZListItems($sClassName, 'details');
 		$aHeader = array();
 		// $aHeader[] = MetaModel::GetKeyLabel($sClassName);
-		$aHeader[] = 'pkey'; // Should be what's coded on the line above... but there is a bug
+		$aHeader[] = 'id'; // Should be what's coded on the line above... but there is a bug
 		foreach($aList as $sAttCode)
 		{
 			$aHeader[] = MetaModel::GetLabel($sClassName, $sAttCode);
@@ -347,12 +405,9 @@ function Do_Format($oPage, $sClass)
 	$iTarget = count($aData);
 	if ($iTarget == 0)
 	{
-	    $oPage->add("Empty data set...");
-	    $oPage->add("<form method=\"post\" action=\"\">");
-	    $oPage->add("<input type=\"hidden\" name=\"csvdata\" value=\"$sCSVData\">");
-	    $oPage->add("<input type=\"hidden\" name=\"fromwiztep\" value=\"$sWiztep\">");
-	    $oPage->add("<input type=\"submit\" name=\"todo\" value=\"Back\">");
-		$oPage->add("</form>");
+	   $oPage->p("Empty data set..., please provide some data!");
+		$oPage->add("<button onClick=\"window.history.back();\">Back</button>\n");
+		return;
 	}
 
 	// Guess the format :
@@ -405,9 +460,9 @@ function DoProcessOrVerify($oPage, $sClass, CMDBChange $oChange = null)
 			$sReconcKey = "";
 		}
 
-		if ($sColDesc == "pkey")
+		if ($sColDesc == "id")
 		{
-			$aDisplayConfig[$sFieldId] = array("label"=>"Private key $sReconcKey", "description"=>"blah pkey");
+			$aDisplayConfig[$sFieldId] = array("label"=>"Private key $sReconcKey", "description"=>"");
 		}
 		elseif ($sColDesc == "__none__")
 		{
@@ -455,12 +510,16 @@ function DoProcessOrVerify($oPage, $sClass, CMDBChange $oChange = null)
 		if (count($aMissingKeys) > 0)
 		{
 			$oPage->p("Warning: the objects could not be created, due to some missing mandatory external keys in the field list: ");
-			$oPage->p("<ul>");
+			$oPage->add("<ul>");
 			foreach($aMissingKeys as $sAttCode => $oAttDef)
 			{
-				$oPage->p("<li>".$oAttDef->GetLabel()."</li>");
+				$oPage->add("<li>".$oAttDef->GetLabel()."</li>");
 			}
-			$oPage->p("</ul>");
+			$oPage->add("</ul>");
+		}
+		else
+		{
+			$oPage->p("ok - required external keys (if any) have been found in the field list");
 		}
 
 		$oPage->p("<h2>Check...</h2>");