A little bit of polishing on the impact analysis feature...

SVN:trunk[3630]
This commit is contained in:
Denis Flaven
2015-07-08 15:56:34 +00:00
parent 77388bed29
commit 20e4dbfc1d
9 changed files with 92 additions and 42 deletions

View File

@@ -282,22 +282,45 @@ class DisplayableNode extends GraphNode
{
if (count($aGroupProps['nodes']) >= $iThresholdCount)
{
$oNewNode = new DisplayableGroupNode($oGraph, $this->GetId().'::'.(($sStatus == 'reached') ? '_reached': ''));
$oNewNode->SetProperty('label', 'x'.$aGroupProps['count']);
$oNewNode->SetProperty('icon_url', $aGroupProps['icon_url']);
$oNewNode->SetProperty('class', $sClass);
$oNewNode->SetProperty('is_reached', ($sStatus == 'reached'));
$oNewNode->SetProperty('count', $aGroupProps['count']);
$sNewId = $this->GetId().'::'.(($sStatus == 'reached') ? '_reached': '');
$oNewNode = $oGraph->GetNode($sNewId);
if ($oNewNode == null)
{
$oNewNode = new DisplayableGroupNode($oGraph, $sNewId);
$oNewNode->SetProperty('label', 'x'.$aGroupProps['count']);
$oNewNode->SetProperty('icon_url', $aGroupProps['icon_url']);
$oNewNode->SetProperty('class', $sClass);
$oNewNode->SetProperty('is_reached', ($sStatus == 'reached'));
$oNewNode->SetProperty('count', $aGroupProps['count']);
}
else
{
$oNewNode->SetProperty('count', $oNewNode->GetProperty('count')+$aGroupProps['count']);
}
try
{
$oIncomingEdge = new DisplayableEdge($oGraph, $this->GetId().'-'.$oNewNode->GetId(), $this, $oNewNode);
}
catch(Exception $e)
{
// Ignore this redundant egde
}
$oIncomingEdge = new DisplayableEdge($oGraph, $this->GetId().'-'.$oNewNode->GetId(), $this, $oNewNode);
foreach($aGroupProps['nodes'] as $oNode)
{
foreach($oNode->GetIncomingEdges() as $oEdge)
{
if ($oEdge->GetSourceNode()->GetId() !== $this->GetId())
{
$oNewEdge = new DisplayableEdge($oGraph, $oEdge->GetId().'::'.$sClass, $oEdge->GetSourceNode(), $oNewNode);
try
{
$oNewEdge = new DisplayableEdge($oGraph, $oEdge->GetId().'::'.$sClass, $oEdge->GetSourceNode(), $oNewNode);
}
catch(Exception $e)
{
// ignore this edge
}
}
}
foreach($oNode->GetOutgoingEdges() as $oEdge)
@@ -825,7 +848,6 @@ class DisplayableGraph extends SimpleGraph
{
throw new Exception($sDot);
}
$sDot = preg_replace('/.*label=.*,/', '', $sDot); // Get rid of label lines since they may contain weird characters than can break the split and pattern matching below
$aChunks = explode(";", $sDot);
foreach($aChunks as $sChunk)
@@ -975,7 +997,7 @@ class DisplayableGraph extends SimpleGraph
$yMin = $aRemainingArea['ymin'];
$yMax = $aRemainingArea['ymax'];
//$oPdf->Rect($xMin, $yMin, $xMax - $xMin, $yMax - $yMin, 'D', array(), array(225, 225, 225));
//$oPdf->Rect($xMin, $yMin, $xMax - $xMin, $yMax - $yMin, 'D', array(), array(225, 50, 50));
$fPageW = $xMax - $xMin;
$fPageH = $yMax - $yMin;
@@ -1093,7 +1115,7 @@ class DisplayableGraph extends SimpleGraph
$yMax = $yPos - $fPadding;
}
return array('xmin' => $fMaxWidth + $fIconSize + 4*$fPadding, 'xmax' => $xMax, 'ymin' => $yMin, 'ymax' => $yMax);
return array('xmin' => $xMin + $fMaxWidth + $fIconSize + 4*$fPadding, 'xmax' => $xMax, 'ymin' => $yMin, 'ymax' => $yMax);
}
/**

View File

@@ -1403,10 +1403,11 @@ abstract class MetaModel
$aQueries[$sRemoteClass]['down'][$sLocalClass]['sQueryUp'] = $aNeighbourData['sQueryUp'];
$aQueries[$sRemoteClass]['down'][$sLocalClass]['sDirection'] = 'both';
}
else
{
throw new Exception("Legacy definition of the relation '$sRelCode/$sRevertCode', defined on $sLocalClass (relation: $sRevertCode, inherited to $sClass), missing the counterpart query on class $sRemoteClass ($sRelCode)");
}
// Be silent in order to transparently support legacy data models where the counterpart query does not always exist
//else
//{
// throw new Exception("Legacy definition of the relation '$sRelCode/$sRevertCode', defined on $sLocalClass (relation: $sRevertCode, inherited to $sClass), missing the counterpart query on class $sRemoteClass ($sRelCode)");
//}
}
}
}

View File

@@ -48,7 +48,7 @@ class RelationObjectNode extends GraphNode
/**
* Formatting for GraphViz
*/
public function GetDotAttributes()
public function GetDotAttributes($bNoLabel = false)
{
$sDot = parent::GetDotAttributes();
if ($this->GetProperty('developped', false))
@@ -114,7 +114,7 @@ class RelationRedundancyNode extends GraphNode
/**
* Formatting for GraphViz
*/
public function GetDotAttributes()
public function GetDotAttributes($bNoLabel = false)
{
$sDisplayThreshold = sprintf('%.1f', $this->GetProperty('threshold'));
$sDot = 'shape=doublecircle,fillcolor=indianred,fontcolor=papayawhip,label="'.$sDisplayThreshold.'"';

View File

@@ -128,10 +128,14 @@ class GraphNode extends GraphElement
$oGraph->_AddNode($this);
}
public function GetDotAttributes()
public function GetDotAttributes($bNoLabel = false)
{
$sLabel = addslashes($this->GetProperty('label', $this->GetId()));
$sDot = 'label="'.$sLabel.'"';
$sDot = '';
if (!$bNoLabel)
{
$sLabel = addslashes($this->GetProperty('label', $this->GetId()));
$sDot = 'label="'.$sLabel.'"';
}
return $sDot;
}
@@ -264,10 +268,14 @@ class GraphEdge extends GraphElement
return $this->oSinkNode;
}
public function GetDotAttributes()
public function GetDotAttributes($bNoLabel = false)
{
$sLabel = addslashes($this->GetProperty('label', ''));
$sDot = 'label="'.$sLabel.'"';
$sDot = '';
if (!$bNoLabel)
{
$sLabel = addslashes($this->GetProperty('label', ''));
$sDot = 'label="'.$sLabel.'"';
}
return $sDot;
}
}
@@ -443,9 +451,10 @@ class SimpleGraph
/**
* Get the description of the graph as a text string in the graphviz 'dot' language
* @param $bNoLabel bool Whether or not to include the labels in the dot file
* @return string
*/
public function GetDotDescription()
public function GetDotDescription($bNoLabel = false)
{
$sDot =
<<<EOF
@@ -464,12 +473,12 @@ EOF
foreach($oIterator as $key => $oNode)
{
$sDot .= "\t\"".$oNode->GetId()."\" [ ".$oNode->GetDotAttributes()." ];\n";
$sDot .= "\t\"".$oNode->GetId()."\" [ ".$oNode->GetDotAttributes($bNoLabel)." ];\n";
if (count($oNode->GetOutgoingEdges()) > 0)
{
foreach($oNode->GetOutgoingEdges() as $oEdge)
{
$sDot .= "\t\"".$oNode->GetId()."\" -> \"".$oEdge->GetSinkNode()->GetId()."\" [ ".$oEdge->GetDotAttributes()." ];\n";
$sDot .= "\t\"".$oNode->GetId()."\" -> \"".$oEdge->GetSinkNode()->GetId()."\" [ ".$oEdge->GetDotAttributes($bNoLabel)." ];\n";
}
}
}
@@ -556,7 +565,7 @@ EOF
@mkdir(APPROOT."data/tmp");
}
$sXdotFilePath = tempnam(APPROOT."data/tmp", 'xdot-');
$sDotDescription = $this->GetDotDescription();
$sDotDescription = $this->GetDotDescription(true); // true => don't put (localized) labels in the file, since it makes it harder to parse
$sDotFilePath = tempnam(APPROOT."data/tmp", 'dot-');
$rFile = @fopen($sDotFilePath, "w");
@@ -572,13 +581,14 @@ EOF
$sHtml .= "<p><b>Error:</b></p>";
$sHtml .= "<p>The command: <pre>$CommandLine</pre> returned $iRetCode</p>";
$sHtml .= "<p>The output of the command is:<pre>\n".implode("\n", $aOutput)."</pre></p>";
IssueLog::Error($sHtml);
}
else
{
$sHtml = '<pre>'.file_get_contents($sXdotFilePath).'</pre>';
@unlink($sImageFilePath);
@unlink($sXdotFilePath);
}
@unlink($sXdotFilePath);
@unlink($sDotFilePath);
}
else
{

View File

@@ -103,7 +103,7 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
'UI-ChangeManagementOverview-ChangeByDomain-last-7-days' => 'Changes der letzten sieben Tage nach Typ',
'UI-ChangeManagementOverview-ChangeByStatus-last-7-days' => 'Changes der letzten sieben Tage nach Status',
'Tickets:Related:OpenChanges' => 'Open changes~~',
'Tickets:Related:RecentChanges' => 'Recent changes~~',
'Tickets:Related:RecentChanges' => 'Recent changes (72h)~~',
'Class:Change/Attribute:changemanager_email' => 'Change Manager Email',
'Class:Change/Attribute:changemanager_email+' => '',
'Class:Change/Attribute:parent_name' => 'Parent Change ref',

View File

@@ -47,7 +47,7 @@ Dict::Add('EN US', 'English', 'English', array(
'UI-ChangeManagementOverview-ChangeByDomain-last-7-days' => 'Changes by domain for the last 7 days',
'UI-ChangeManagementOverview-ChangeByStatus-last-7-days' => 'Changes by status for the last 7 days',
'Tickets:Related:OpenChanges' => 'Open changes',
'Tickets:Related:RecentChanges' => 'Recent changes',
'Tickets:Related:RecentChanges' => 'Recent changes (72h)',
));
// Dictionnay conventions

View File

@@ -126,6 +126,6 @@ Dict::Add('FR FR', 'French', 'Français', array(
'UI-ChangeManagementOverview-ChangeByStatus-last-7-days' => 'Changements par statut',
'UI:ChangeMgmtMenuOverview:Title' => 'Tableau de bord des changements pour les 7 derniers jours',
'Tickets:Related:OpenChanges' => 'Changements en cours',
'Tickets:Related:RecentChanges' => 'Changements récents',
'Tickets:Related:RecentChanges' => 'Changements récents (72h)',
));
?>

View File

@@ -269,10 +269,10 @@ $(function()
this.options.ymax = -9999;
for(var k in this.aNodes)
{
this.options.xmin = Math.min(this.aNodes[k].x + this.aNodes[k].tx, this.options.xmin);
this.options.xmax = Math.max(this.aNodes[k].x + this.aNodes[k].tx, this.options.xmax);
this.options.ymin = Math.min(this.aNodes[k].y + this.aNodes[k].ty, this.options.ymin);
this.options.ymax = Math.max(this.aNodes[k].y + this.aNodes[k].ty, this.options.ymax);
this.options.xmin = Math.min(this.aNodes[k].x + this.aNodes[k].tx - this.aNodes[k].width/2, this.options.xmin);
this.options.xmax = Math.max(this.aNodes[k].x + this.aNodes[k].tx + this.aNodes[k].width/2, this.options.xmax);
this.options.ymin = Math.min(this.aNodes[k].y + this.aNodes[k].ty - this.aNodes[k].width/2, this.options.ymin);
this.options.ymax = Math.max(this.aNodes[k].y + this.aNodes[k].ty + this.aNodes[k].width/2, this.options.ymax);
}
},
_get_edge_path: function(oEdge)
@@ -617,8 +617,10 @@ $(function()
this.element.closest('.ui-tabs').tabs({ heightStyle: "fill" });
this._close_all_tooltips();
this.oPaper.rect(0, 0, this.element.width(), this.element.height()).attr({fill: '#000', opacity: 0.4, 'stroke-width': 0});
$('#'+sId+'_refresh_btn').button('disable');
$.post(sUrl, {excluded_classes: this.options.excluded_classes, g: this.options.grouping_threshold, sources: this.options.sources, excluded: this.options.excluded, contexts: aContexts, context_key: this.options.context_key }, function(data) {
me.load(data);
$('#'+sId+'_refresh_btn').button('enable');
}, 'json');
},
export_as_attachment: function()
@@ -665,13 +667,22 @@ $(function()
$.post(sUrl, oParams, function(data) {
var sDownloadLink = GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?operation=download_document&class=Attachment&id='+data.att_id+'&field=contents';
var sIcon = GetAbsoluteUrlModulesRoot()+'itop-attachments/icons/pdf.png';
$('#attachments').append('<div class="attachment" id="display_attachment_'+data.att_id+'"><a data-preview="false" href="'+sDownloadLink+'"><img src="'+sIcon+'"><br/>'+sTitle+'.pdf<input id="attachment_'+data.att_id+'" type="hidden" name="attachments[]" value="'+data.att_id+'"/></a><br/><input type="button" class="btn_hidden" value="{$sDeleteBtn}" onClick="RemoveAttachment('+data.att_id+');"/></div>');
if (jTab != null)
{
var re = /^([^(]+)\(([0-9]+)\)(.*)$/;
var aParts = re.exec(sTabText);
var iPrevCount = parseInt(aParts[2], 10);
jTab.find('span').html(aParts[1]+'('+(1 + iPrevCount)+')'+aParts[3]);
if (aParts == null)
{
// First attachment
$('#attachments').html('<div class="attachment" id="display_attachment_'+data.att_id+'"><a data-preview="false" href="'+sDownloadLink+'"><img src="'+sIcon+'"><br/>'+sTitle+'.pdf<input id="attachment_'+data.att_id+'" type="hidden" name="attachments[]" value="'+data.att_id+'"/></a><br/><input type="button" class="btn_hidden" value="{$sDeleteBtn}" onClick="RemoveAttachment('+data.att_id+');"/></div>');
jTab.find('span').html(sTabText +' (1)');
}
else
{
$('#attachments').append('<div class="attachment" id="display_attachment_'+data.att_id+'"><a data-preview="false" href="'+sDownloadLink+'"><img src="'+sIcon+'"><br/>'+sTitle+'.pdf<input id="attachment_'+data.att_id+'" type="hidden" name="attachments[]" value="'+data.att_id+'"/></a><br/><input type="button" class="btn_hidden" value="{$sDeleteBtn}" onClick="RemoveAttachment('+data.att_id+');"/></div>');
var iPrevCount = parseInt(aParts[2], 10);
jTab.find('span').html(aParts[1]+'('+(1 + iPrevCount)+')'+aParts[3]);
}
}
}, 'json');
return false;
@@ -691,15 +702,15 @@ $(function()
return sTooltipContent;
},
items: '.popupMenuTarget',
tooltipClass: 'tooltip-simple-graph',
position: {
my: "center bottom-10",
at: "center top",
at: "center top",
using: function( position, feedback ) {
$(this).css( position );
$( "<div>" )
.addClass( "arrow" )
.addClass( feedback.vertical )
.addClass( feedback.horizontal )
.appendTo( this );
}
}
@@ -739,6 +750,11 @@ $(function()
var sDataId = $(this).attr('data-id');
$('.popupMenuTarget[data-id="'+sDataId+'"]').tooltip('close');
});
this.element.on("click", ":not(.tooltip-simple-graph *,.tooltip-simple-graph)", function(){
$('.popupMenuTarget').each(function (i) {
$(this).tooltip("close");
});
});
},
_get_tooltip_content: function(sNodeId)
{

View File

@@ -1851,6 +1851,7 @@ EOF
}
$oPage->get_tcpdf()->AddPage();
$oPage->get_tcpdf()->SetFont('dejavusans', '', 10, '', true); // Reset the font size to its default
$oPage->add('<div class="page_header"><h1>'.Dict::S('UI:RelationshipList').'</h1></div>');
$iLoopTimeLimit = MetaModel::GetConfig()->Get('max_execution_time_per_loop');
foreach($aResults as $sListClass => $aObjects)