mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 07:24:13 +01:00
Integration of the new impact analysis into the tickets.
SVN:trunk[3578]
This commit is contained in:
@@ -218,7 +218,7 @@ EOF;
|
||||
},
|
||||
beforeLoad: function( event, ui ) {
|
||||
if ( ui.tab.data('loaded') && (ui.tab.attr('data-cache') == 'true')) {
|
||||
event.defaultPrevented = true;
|
||||
event.preventDefault();
|
||||
return;
|
||||
}
|
||||
ui.panel.html('<div><img src="../images/indicator.gif"></div>');
|
||||
@@ -867,26 +867,29 @@ EOF
|
||||
}
|
||||
else if ($this->GetOutputFormat() == 'pdf' && $this->IsOutputFormatAvailable('pdf') )
|
||||
{
|
||||
require_once(APPROOT.'lib/MPDF/mpdf.php');
|
||||
$oMPDF = new mPDF('c');
|
||||
$oMPDF->mirroMargins = false;
|
||||
if ($this->a_base['href'] != '')
|
||||
if (@is_readable(APPROOT.'lib/MPDF/mpdf.php'))
|
||||
{
|
||||
$oMPDF->setBasePath($this->a_base['href']); // Seems that the <BASE> tag is not recognized by mPDF...
|
||||
require_once(APPROOT.'lib/MPDF/mpdf.php');
|
||||
$oMPDF = new mPDF('c');
|
||||
$oMPDF->mirroMargins = false;
|
||||
if ($this->a_base['href'] != '')
|
||||
{
|
||||
$oMPDF->setBasePath($this->a_base['href']); // Seems that the <BASE> tag is not recognized by mPDF...
|
||||
}
|
||||
$oMPDF->showWatermarkText = true;
|
||||
if ($this->GetOutputOption('pdf', 'template_path'))
|
||||
{
|
||||
$oMPDF->setImportUse(); // Allow templates
|
||||
$oMPDF->SetDocTemplate ($this->GetOutputOption('pdf', 'template_path'), 1);
|
||||
}
|
||||
$oMPDF->WriteHTML($sHtml);
|
||||
$sOutputName = $this->s_title.'.pdf';
|
||||
if ($this->GetOutputOption('pdf', 'output_name'))
|
||||
{
|
||||
$sOutputName = $this->GetOutputOption('pdf', 'output_name');
|
||||
}
|
||||
$oMPDF->Output($sOutputName, 'I');
|
||||
}
|
||||
$oMPDF->showWatermarkText = true;
|
||||
if ($this->GetOutputOption('pdf', 'template_path'))
|
||||
{
|
||||
$oMPDF->setImportUse(); // Allow templates
|
||||
$oMPDF->SetDocTemplate ($this->GetOutputOption('pdf', 'template_path'), 1);
|
||||
}
|
||||
$oMPDF->WriteHTML($sHtml);
|
||||
$sOutputName = $this->s_title.'.pdf';
|
||||
if ($this->GetOutputOption('pdf', 'output_name'))
|
||||
{
|
||||
$sOutputName = $this->GetOutputOption('pdf', 'output_name');
|
||||
}
|
||||
$oMPDF->Output($sOutputName, 'I');
|
||||
}
|
||||
MetaModel::RecordQueryTrace();
|
||||
ExecutionKPI::ReportStats();
|
||||
|
||||
@@ -29,8 +29,8 @@ class iTopPDF extends TCPDF
|
||||
$aMargins = $this->getMargins();
|
||||
|
||||
// Display the title (centered)
|
||||
$this->SetY(0);
|
||||
$this->MultiCell($this->getPageWidth() - $aMargins['left'] - $aMargins['right'] - $iPageNumberWidth, 15, $this->sDocumentTitle, 0, 'C', false, 0 /* $ln */, '', '', true, 0, false, true, 15, 'M' /* $valign */);
|
||||
$this->SetXY($aMargins['left'] + $iPageNumberWidth, 0);
|
||||
$this->MultiCell($this->getPageWidth() - $aMargins['left'] - $aMargins['right'] - 2*$iPageNumberWidth, 15, $this->sDocumentTitle, 0, 'C', false, 0 /* $ln */, '', '', true, 0, false, true, 15, 'M' /* $valign */);
|
||||
$this->SetFont('dejavusans', '', 10);
|
||||
|
||||
// Display the page number (right aligned)
|
||||
|
||||
@@ -560,13 +560,17 @@ class DisplayableGroupNode extends DisplayableNode
|
||||
*/
|
||||
class DisplayableGraph extends SimpleGraph
|
||||
{
|
||||
protected $sDirection;
|
||||
protected $bDirectionDown;
|
||||
protected $aTempImages;
|
||||
protected $aSourceObjects;
|
||||
protected $aSinkObjects;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->aTempImages = array();
|
||||
$this->aSourceObjects = array();
|
||||
$this->aSinkObjects = array();
|
||||
}
|
||||
|
||||
public function GetTempImageName()
|
||||
@@ -594,6 +598,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
public static function FromRelationGraph(RelationGraph $oGraph, $iGroupingThreshold = 20, $bDirectionDown = true)
|
||||
{
|
||||
$oNewGraph = new DisplayableGraph();
|
||||
$oNewGraph->bDirectionDown = $bDirectionDown;
|
||||
|
||||
$oNodesIter = new RelationTypeIterator($oGraph, 'Node');
|
||||
foreach($oNodesIter as $oNode)
|
||||
@@ -603,16 +608,27 @@ class DisplayableGraph extends SimpleGraph
|
||||
case 'RelationObjectNode':
|
||||
$oNewNode = new DisplayableNode($oNewGraph, $oNode->GetId(), 0, 0);
|
||||
|
||||
$oObj = $oNode->GetProperty('object');
|
||||
$sClass = get_class($oObj);
|
||||
if ($oNode->GetProperty('source'))
|
||||
{
|
||||
if (!array_key_exists($sClass, $oNewGraph->aSourceObjects))
|
||||
{
|
||||
$oNewGraph->aSourceObjects[$sClass] = array();
|
||||
}
|
||||
$oNewGraph->aSourceObjects[$sClass][] = $oObj->GetKey();
|
||||
$oNewNode->SetProperty('source', true);
|
||||
}
|
||||
if ($oNode->GetProperty('sink'))
|
||||
{
|
||||
if (!array_key_exists($sClass, $oNewGraph->aSinkObjects))
|
||||
{
|
||||
$oNewGraph->aSinkObjects[$sClass] = array();
|
||||
}
|
||||
$oNewGraph->aSinkObjects[$sClass][] = $oObj->GetKey();
|
||||
$oNewNode->SetProperty('sink', true);
|
||||
}
|
||||
$oObj = $oNode->GetProperty('object');
|
||||
$oNewNode->SetProperty('class', get_class($oObj));
|
||||
$oNewNode->SetProperty('class', $sClass);
|
||||
$oNewNode->SetProperty('object', $oObj);
|
||||
$oNewNode->SetProperty('icon_url', $oObj->GetIcon(false));
|
||||
$oNewNode->SetProperty('label', $oObj->GetRawName());
|
||||
@@ -791,71 +807,6 @@ class DisplayableGraph extends SimpleGraph
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders as a suite of Javascript instructions to display the graph using the simple_graph widget
|
||||
* @param WebPage $oP
|
||||
* @param string $sId
|
||||
* @param string $sExportAsPdfURL
|
||||
* @param string $sExportAsDocumentURL
|
||||
* @param string $sDrillDownURL
|
||||
*/
|
||||
function RenderAsRaphael(WebPage $oP, $sId = null, $sExportAsPdfURL, $sExportAsDocumentURL, $sDrillDownURL)
|
||||
{
|
||||
if ($sId == null)
|
||||
{
|
||||
$sId = 'graph';
|
||||
}
|
||||
$oP->add('<div id="'.$sId.'" class="simple-graph"></div>');
|
||||
$aParams = array(
|
||||
'export_as_pdf' => array('url' => $sExportAsPdfURL, 'label' => Dict::S('UI:Relation:ExportAsPDF')),
|
||||
'export_as_document' => array('url' => $sExportAsDocumentURL, 'label' => Dict::S('UI:Relation:ExportAsDocument')),
|
||||
'drill_down' => array('url' => $sDrillDownURL, 'label' => Dict::S('UI:Relation:DrillDown')),
|
||||
'labels' => array(
|
||||
'export_pdf_title' => Dict::S('UI:Relation:PDFExportOptions'),
|
||||
'export' => Dict::S('UI:Relation:PDFExportOptions'),
|
||||
'cancel' => Dict::S('UI:Button:Cancel'),
|
||||
),
|
||||
'page_format' => array(
|
||||
'label' => Dict::S('UI:Relation:PDFExportPageFormat'),
|
||||
'values' => array(
|
||||
'A3' => Dict::S('UI:PageFormat_A3'),
|
||||
'A4' => Dict::S('UI:PageFormat_A4'),
|
||||
'Letter' => Dict::S('UI:PageFormat_Letter'),
|
||||
),
|
||||
),
|
||||
'page_orientation' => array(
|
||||
'label' => Dict::S('UI:Relation:PDFExportPageOrientation'),
|
||||
'values' => array(
|
||||
'P' => Dict::S('UI:PageOrientation_Portrait'),
|
||||
'L' => Dict::S('UI:PageOrientation_Landscape'),
|
||||
),
|
||||
),
|
||||
);
|
||||
$oP->add_ready_script("var oGraph = $('#$sId').simple_graph(".json_encode($aParams).");");
|
||||
|
||||
$oIterator = new RelationTypeIterator($this, 'Node');
|
||||
foreach($oIterator as $sId => $oNode)
|
||||
{
|
||||
$aNode = $oNode->GetForRaphael();
|
||||
$sJSNode = json_encode($aNode);
|
||||
$oP->add_ready_script("oGraph.simple_graph('add_node', $sJSNode);");
|
||||
}
|
||||
$oIterator = new RelationTypeIterator($this, 'Edge');
|
||||
foreach($oIterator as $sId => $oEdge)
|
||||
{
|
||||
$aEdge = array();
|
||||
$aEdge['id'] = $oEdge->GetId();
|
||||
$aEdge['source_node_id'] = $oEdge->GetSourceNode()->GetId();
|
||||
$aEdge['sink_node_id'] = $oEdge->GetSinkNode()->GetId();
|
||||
$fOpacity = ($oEdge->GetSinkNode()->GetProperty('is_reached') && $oEdge->GetSourceNode()->GetProperty('is_reached') ? 1 : 0.2);
|
||||
$aEdge['attr'] = array('opacity' => $fOpacity, 'stroke' => '#000');
|
||||
$sJSEdge = json_encode($aEdge);
|
||||
$oP->add_ready_script("oGraph.simple_graph('add_edge', $sJSEdge);");
|
||||
}
|
||||
|
||||
$oP->add_ready_script("oGraph.simple_graph('draw');");
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders as JSON string suitable for loading into the simple_graph widget
|
||||
@@ -964,13 +915,26 @@ class DisplayableGraph extends SimpleGraph
|
||||
$oPdf->SetAlpha(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders (in PDF) the key (legend) of the graphics vertically to the left of the specified zone (xmin,ymin, xmax,ymax). Returns the width used by the legend.
|
||||
* @param TCPDF $oPdf
|
||||
* @param string $sComments
|
||||
* @param float $xMin
|
||||
* @param float $yMin
|
||||
* @param float $xMax
|
||||
* @param float $yMax
|
||||
* @return number The width used by the legend
|
||||
*/
|
||||
protected function RenderKey(TCPDF $oPdf, $sComments, $xMin, $yMin, $xMax, $yMax)
|
||||
{
|
||||
$fFontSize = 7; // in mm
|
||||
$fIconSize = 6; // in mm
|
||||
$fPadding = 1; // in mm
|
||||
$oIterator = new RelationTypeIterator($this, 'Node');
|
||||
$fMaxWidth = max($oPdf->GetStringWidth(Dict::S('UI:Relation:Key')) - 6, $oPdf->GetStringWidth(Dict::S('UI:Relation:Comments')) - 6);
|
||||
$fMaxWidth = max($oPdf->GetStringWidth(Dict::S('UI:Relation:Key')) - $fIconSize, $oPdf->GetStringWidth(Dict::S('UI:Relation:Comments')) - $fIconSize);
|
||||
$aClasses = array();
|
||||
$aIcons = array();
|
||||
$oPdf->SetFont('dejavusans', '', 8, '', true);
|
||||
$oPdf->SetFont('dejavusans', '', $fFontSize, '', true);
|
||||
foreach($oIterator as $sId => $oNode)
|
||||
{
|
||||
if ($sClass = $oNode->GetProperty('class'))
|
||||
@@ -987,26 +951,169 @@ class DisplayableGraph extends SimpleGraph
|
||||
}
|
||||
}
|
||||
}
|
||||
$oPdf->SetXY($xMin + 1, $yMin +1);
|
||||
$yPos = $yMin + 1;
|
||||
$oPdf->SetXY($xMin + $fPadding, $yMin + $fPadding);
|
||||
$yPos = $yMin + $fPadding;
|
||||
$oPdf->SetFillColor(225, 225, 225);
|
||||
$oPdf->Cell(7 + $fMaxWidth, 7, Dict::S('UI:Relation:Key'), 0 /* border */, 1 /* ln */, 'C', true /* fill */);
|
||||
$yPos += 8;
|
||||
$oPdf->Cell($fIconSize + $fPadding + $fMaxWidth, $fIconSize + $fPadding, Dict::S('UI:Relation:Key'), 0 /* border */, 1 /* ln */, 'C', true /* fill */);
|
||||
$yPos += $fIconSize + 2*$fPadding;
|
||||
foreach($aClasses as $sClass => $sLabel)
|
||||
{
|
||||
$oPdf->SetX($xMin + 7);
|
||||
$oPdf->Cell(0, 8, $sLabel, 0 /* border */, 1 /* ln */);
|
||||
$oPdf->Image($aIcons[$sClass], $xMin+1, $yPos, 6, 6);
|
||||
$yPos += 8;
|
||||
$oPdf->SetX($xMin + $fIconSize + $fPadding);
|
||||
$oPdf->Cell(0, $fIconSize + 2*$fPadding, $sLabel, 0 /* border */, 1 /* ln */);
|
||||
$oPdf->Image($aIcons[$sClass], $xMin+1, $yPos, $fIconSize, $fIconSize);
|
||||
$yPos += $fIconSize + 2*$fPadding;
|
||||
}
|
||||
$oPdf->Rect($xMin, $yMin, $fMaxWidth+9, $yPos - $yMin, 'D');
|
||||
$oPdf->Rect($xMin, $yPos, $fMaxWidth+9, $yMax - $yPos, 'D');
|
||||
$oPdf->Rect($xMin, $yMin, $fMaxWidth + $fIconSize + 3*$fPadding, $yPos - $yMin, 'D');
|
||||
$oPdf->Rect($xMin, $yPos, $fMaxWidth + $fIconSize + 3*$fPadding, $yMax - $yPos, 'D');
|
||||
$yPos +=1;
|
||||
$oPdf->SetXY($xMin + 1, $yPos);
|
||||
$oPdf->Cell(7 + $fMaxWidth, 7, Dict::S('UI:Relation:Comments'), 0 /* border */, 1 /* ln */, 'C', true /* fill */);
|
||||
$yPos += 8;
|
||||
$oPdf->SetXY($xMin + $fPadding, $yPos);
|
||||
$oPdf->Cell($fIconSize + $fPadding + $fMaxWidth, $fIconSize + $fPadding, Dict::S('UI:Relation:Comments'), 0 /* border */, 1 /* ln */, 'C', true /* fill */);
|
||||
$yPos += $fIconSize + 2*$fPadding;
|
||||
$oPdf->SetX($xMin);
|
||||
$oPdf->writeHTMLCell(8 + $fMaxWidth, $yMax - $yPos, $xMin, $yPos, '<p>'.str_replace("\n", '<br/>', htmlentities($sComments, ENT_QUOTES, 'UTF-8')).'</p>', 0 /* border */, 1 /* ln */);
|
||||
return $fMaxWidth + 10;
|
||||
$oPdf->writeHTMLCell($fIconSize + 2*$fPadding + $fMaxWidth, $yMax - $yPos, $xMin, $yPos, '<p>'.str_replace("\n", '<br/>', htmlentities($sComments, ENT_QUOTES, 'UTF-8')).'</p>', 0 /* border */, 1 /* ln */);
|
||||
return $fMaxWidth + $fIconSize + 4*$fPadding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the graph inside the given page, with the "filter" drawer above it
|
||||
* @param WebPage $oP
|
||||
* @param hash $aResults
|
||||
* @param string $sRelation
|
||||
* @param ApplicationContext $oAppContext
|
||||
* @param array $aExcludedObjects
|
||||
*/
|
||||
function Display(WebPage $oP, $aResults, $sRelation, ApplicationContext $oAppContext, $aExcludedObjects)
|
||||
{
|
||||
$aExcludedByClass = array();
|
||||
foreach($aExcludedObjects as $oObj)
|
||||
{
|
||||
if (!array_key_exists(get_class($oObj), $aExcludedByClass))
|
||||
{
|
||||
$aExcludedByClass[get_class($oObj)] = array();
|
||||
}
|
||||
$aExcludedByClass[get_class($oObj)][] = $oObj->GetKey();
|
||||
}
|
||||
$oP->add("<div id=\"ds_flash\" class=\"SearchDrawer\" style=\"display:none;\">\n");
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$( "#tabbedContent_0" ).tabs({ heightStyle: "fill" });
|
||||
$("#dh_flash").click( function() {
|
||||
$("#ds_flash").slideToggle('normal', function() { $("#ds_flash").parent().resize(); } );
|
||||
$("#dh_flash").toggleClass('open');
|
||||
});
|
||||
$('#ReloadMovieBtn').button().button('disable');
|
||||
EOF
|
||||
);
|
||||
$aSortedElements = array();
|
||||
foreach($aResults as $sClassIdx => $aObjects)
|
||||
{
|
||||
foreach($aObjects as $oCurrObj)
|
||||
{
|
||||
$sSubClass = get_class($oCurrObj);
|
||||
$aSortedElements[$sSubClass] = MetaModel::GetName($sSubClass);
|
||||
}
|
||||
}
|
||||
|
||||
asort($aSortedElements);
|
||||
$idx = 0;
|
||||
foreach($aSortedElements as $sSubClass => $sClassName)
|
||||
{
|
||||
$oP->add("<span style=\"padding-right:2em; white-space:nowrap;\"><input type=\"checkbox\" id=\"exclude_$idx\" name=\"excluded[]\" value=\"$sSubClass\" checked onChange=\"$('#ReloadMovieBtn').button('enable')\"><label for=\"exclude_$idx\"> ".MetaModel::GetClassIcon($sSubClass)." $sClassName</label></span> ");
|
||||
$idx++;
|
||||
}
|
||||
$oP->add("<p style=\"text-align:right\"><button type=\"button\" id=\"ReloadMovieBtn\" onClick=\"DoReload()\">".Dict::S('UI:Button:Refresh')."</button></p>");
|
||||
$oP->add("</div>\n");
|
||||
$oP->add("<div class=\"HRDrawer\"></div>\n");
|
||||
$oP->add("<div id=\"dh_flash\" class=\"DrawerHandle\">".Dict::S('UI:ElementsDisplayed')."</div>\n");
|
||||
|
||||
$sDirection = utils::ReadParam('d', 'horizontal');
|
||||
$iGroupingThreshold = utils::ReadParam('g', 5);
|
||||
|
||||
$oP->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/fraphael.js');
|
||||
$oP->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/jquery.contextMenu.css');
|
||||
$oP->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.contextMenu.js');
|
||||
$oP->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/simple_graph.js');
|
||||
try
|
||||
{
|
||||
$this->InitFromGraphviz();
|
||||
$sExportAsPdfURL = '';
|
||||
if (extension_loaded('gd'))
|
||||
{
|
||||
$sExportAsPdfURL = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=relation_pdf&relation='.$sRelation.'&direction='.($this->bDirectionDown ? 'down' : 'up');
|
||||
}
|
||||
$oAppcontext = new ApplicationContext();
|
||||
$sContext = $oAppContext->GetForLink();
|
||||
$sDrillDownURL = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=details&class=%1$s&id=%2$s&'.$sContext;
|
||||
$sExportAsDocumentURL = '';
|
||||
$sLoadFromURL = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=relation_json&relation='.$sRelation.'&direction='.($this->bDirectionDown ? 'down' : 'up');
|
||||
|
||||
$sId = 'graph';
|
||||
$oP->add('<div id="'.$sId.'" class="simple-graph"></div>');
|
||||
$aParams = array(
|
||||
'source_url' => $sLoadFromURL,
|
||||
'sources' => ($this->bDirectionDown ? $this->aSourceObjects : $this->aSinkObjects),
|
||||
'excluded' => $aExcludedByClass,
|
||||
'grouping_threshold' => $iGroupingThreshold,
|
||||
'export_as_pdf' => array('url' => $sExportAsPdfURL, 'label' => Dict::S('UI:Relation:ExportAsPDF')),
|
||||
//'export_as_document' => array('url' => $sExportAsDocumentURL, 'label' => Dict::S('UI:Relation:ExportAsDocument')),
|
||||
'drill_down' => array('url' => $sDrillDownURL, 'label' => Dict::S('UI:Relation:DrillDown')),
|
||||
'labels' => array(
|
||||
'export_pdf_title' => Dict::S('UI:Relation:PDFExportOptions'),
|
||||
'export' => Dict::S('UI:Button:Export'),
|
||||
'cancel' => Dict::S('UI:Button:Cancel'),
|
||||
'title' => Dict::S('UI:RelationOption:Title'),
|
||||
'include_list' => Dict::S('UI:RelationOption:IncludeList'),
|
||||
'comments' => Dict::S('UI:RelationOption:Comments'),
|
||||
'grouping_threshold' => Dict::S('UI:RelationOption:GroupingThreshold'),
|
||||
'refresh' => Dict::S('UI:Button:Refresh'),
|
||||
),
|
||||
'page_format' => array(
|
||||
'label' => Dict::S('UI:Relation:PDFExportPageFormat'),
|
||||
'values' => array(
|
||||
'A3' => Dict::S('UI:PageFormat_A3'),
|
||||
'A4' => Dict::S('UI:PageFormat_A4'),
|
||||
'Letter' => Dict::S('UI:PageFormat_Letter'),
|
||||
),
|
||||
),
|
||||
'page_orientation' => array(
|
||||
'label' => Dict::S('UI:Relation:PDFExportPageOrientation'),
|
||||
'values' => array(
|
||||
'P' => Dict::S('UI:PageOrientation_Portrait'),
|
||||
'L' => Dict::S('UI:PageOrientation_Landscape'),
|
||||
),
|
||||
),
|
||||
);
|
||||
$oP->add_ready_script("$('#$sId').simple_graph(".json_encode($aParams).");");
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$oP->add('<div>'.$e->getMessage().'</div>');
|
||||
}
|
||||
$oP->add_script(
|
||||
<<<EOF
|
||||
|
||||
function DoReload()
|
||||
{
|
||||
$('#ReloadMovieBtn').button('disable');
|
||||
try
|
||||
{
|
||||
var aExcluded = [];
|
||||
$('input[name^=excluded]').each( function() {
|
||||
if (!$(this).prop('checked'))
|
||||
{
|
||||
aExcluded.push($(this).val());
|
||||
}
|
||||
} );
|
||||
$('#graph').simple_graph('option', {excluded_classes: aExcluded});
|
||||
$('#graph').simple_graph('reload');
|
||||
}
|
||||
catch(err)
|
||||
{
|
||||
alert(err);
|
||||
}
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1454,17 +1454,18 @@ abstract class MetaModel
|
||||
* @param array $asourceObjects The objects to start with
|
||||
* @param int $iMaxDepth
|
||||
* @param boolean $bEnableReduncancy
|
||||
* @param array $aUnreachable Array of objects to be considered as 'unreachable'
|
||||
*
|
||||
* @return RelationGraph The graph of all the related objects
|
||||
*/
|
||||
static public function GetRelatedObjectsDown($sRelCode, $aSourceObjects, $iMaxDepth = 99, $bEnableRedundancy = true)
|
||||
static public function GetRelatedObjectsDown($sRelCode, $aSourceObjects, $iMaxDepth = 99, $bEnableRedundancy = true, $aUnreachable = array())
|
||||
{
|
||||
$oGraph = new RelationGraph();
|
||||
foreach ($aSourceObjects as $oObject)
|
||||
{
|
||||
$oGraph->AddSourceObject($oObject);
|
||||
}
|
||||
$oGraph->ComputeRelatedObjectsDown($sRelCode, $iMaxDepth, $bEnableRedundancy);
|
||||
$oGraph->ComputeRelatedObjectsDown($sRelCode, $iMaxDepth, $bEnableRedundancy, $aUnreachable);
|
||||
return $oGraph;
|
||||
}
|
||||
|
||||
|
||||
@@ -75,11 +75,11 @@ class RelationObjectNode extends GraphNode
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively mark the objects nodes as reached, unless we get stopped by a redundancy node
|
||||
* Recursively mark the objects nodes as reached, unless we get stopped by a redundancy node or a 'not allowed' node
|
||||
*/
|
||||
public function ReachDown($sProperty, $value)
|
||||
{
|
||||
if (is_null($this->GetProperty($sProperty)))
|
||||
if (is_null($this->GetProperty($sProperty)) && ($this->GetProperty($sProperty.'_allowed') !== false))
|
||||
{
|
||||
$this->SetProperty($sProperty, $value);
|
||||
foreach ($this->GetOutgoingEdges() as $oOutgoingEdge)
|
||||
@@ -201,7 +201,7 @@ class RelationGraph extends SimpleGraph
|
||||
/**
|
||||
* Build the graph downstream, and mark the nodes that can be reached from the source node
|
||||
*/
|
||||
public function ComputeRelatedObjectsDown($sRelCode, $iMaxDepth, $bEnableRedundancy)
|
||||
public function ComputeRelatedObjectsDown($sRelCode, $iMaxDepth, $bEnableRedundancy, $aUnreachableObjects = array())
|
||||
{
|
||||
//echo "<h5>Sources only...</h5>\n".$this->DumpAsHtmlImage()."<br/>\n";
|
||||
// Build the graph out of the sources
|
||||
@@ -210,6 +210,21 @@ class RelationGraph extends SimpleGraph
|
||||
$this->AddRelatedObjects($sRelCode, true, $oSourceNode, $iMaxDepth, $bEnableRedundancy);
|
||||
//echo "<h5>After processing of {$oSourceNode->GetId()}</h5>\n".$this->DumpAsHtmlImage()."<br/>\n";
|
||||
}
|
||||
|
||||
// Mark the unreachable nodes
|
||||
foreach ($aUnreachableObjects as $oObj)
|
||||
{
|
||||
$sNodeId = RelationObjectNode::MakeId($oObj);
|
||||
$oNode = $this->GetNode($sNodeId);
|
||||
if($oNode)
|
||||
{
|
||||
$oNode->SetProperty('is_reached_allowed', false);
|
||||
}
|
||||
else
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
// Determine the reached nodes
|
||||
foreach ($this->aSourceNodes as $oSourceNode)
|
||||
{
|
||||
@@ -437,4 +452,28 @@ class RelationGraph extends SimpleGraph
|
||||
}
|
||||
return $oRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the objects referenced by the graph as a hash array: 'class' => array of objects
|
||||
* @return Ambigous <multitype:multitype: , unknown>
|
||||
*/
|
||||
public function GetObjectsByClass()
|
||||
{
|
||||
$aResults = array();
|
||||
$oIterator = new RelationTypeIterator($this, 'Node');
|
||||
foreach($oIterator as $oNode)
|
||||
{
|
||||
$oObj = $oNode->GetProperty('object'); // Some nodes (Redundancy Nodes and Group) do not contain an object
|
||||
if ($oObj)
|
||||
{
|
||||
$sObjClass = get_class($oObj);
|
||||
if (!array_key_exists($sObjClass, $aResults))
|
||||
{
|
||||
$aResults[$sObjClass] = array();
|
||||
}
|
||||
$aResults[$sObjClass][] = $oObj;
|
||||
}
|
||||
}
|
||||
return $aResults;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -932,47 +932,32 @@
|
||||
<static>false</static>
|
||||
<access>protected</access>
|
||||
<type>Overload-DBObject</type>
|
||||
<code><![CDATA[ protected function OnInsert()
|
||||
<code><![CDATA[
|
||||
protected function OnInsert()
|
||||
{
|
||||
$oToNotify = $this->Get('contacts_list');
|
||||
$oToImpact = $this->Get('functionalcis_list');
|
||||
|
||||
$oImpactedInfras = DBObjectSet::FromLinkSet($this, 'functionalcis_list', 'functionalci_id');
|
||||
|
||||
$aComputed = $oImpactedInfras->GetRelatedObjects('impacts', 10);
|
||||
|
||||
if (isset($aComputed['FunctionalCI']) && is_array($aComputed['FunctionalCI']))
|
||||
{
|
||||
foreach($aComputed['FunctionalCI'] as $iKey => $oObject)
|
||||
{
|
||||
$oNewLink = new lnkFunctionalCIToTicket();
|
||||
$oNewLink->Set('functionalci_id', $iKey);
|
||||
$oToImpact->AddObject($oNewLink);
|
||||
}
|
||||
}
|
||||
if (isset($aComputed['Contact']) && is_array($aComputed['Contact']))
|
||||
{
|
||||
foreach($aComputed['Contact'] as $iKey => $oObject)
|
||||
{
|
||||
$oNewLink = new lnkContactToTicket();
|
||||
$oNewLink->Set('contact_id', $iKey);
|
||||
$oNewLink->Set('role', 'contact automatically computed');
|
||||
$oToNotify->AddObject($oNewLink);
|
||||
}
|
||||
}
|
||||
|
||||
parent::OnInsert();
|
||||
$this->UpdateImpactedItems();
|
||||
$this->Set('creation_date', time());
|
||||
$this->Set('last_update', time());
|
||||
}]]></code>
|
||||
}]]>
|
||||
</code>
|
||||
</method>
|
||||
<method id="OnUpdate">
|
||||
<static>false</static>
|
||||
<access>protected</access>
|
||||
<type>Overload-DBObject</type>
|
||||
<code><![CDATA[ protected function OnUpdate()
|
||||
{
|
||||
$this->Set('last_update', time());
|
||||
}]]></code>
|
||||
<code><![CDATA[
|
||||
protected function OnUpdate()
|
||||
{
|
||||
parent::OnUpdate();
|
||||
$aChanges = $this->ListChanges();
|
||||
if (array_key_exists('functionalcis_list', $aChanges))
|
||||
{
|
||||
$this->UpdateImpactedItems();
|
||||
}
|
||||
$this->Set('last_update', time());
|
||||
}]]>
|
||||
</code>
|
||||
</method>
|
||||
</methods>
|
||||
<presentation>
|
||||
|
||||
@@ -498,35 +498,11 @@
|
||||
<static>false</static>
|
||||
<access>protected</access>
|
||||
<type>Overload-DBObject</type>
|
||||
<code><![CDATA[ protected function OnInsert()
|
||||
<code><![CDATA[
|
||||
protected function OnInsert()
|
||||
{
|
||||
$oToNotify = $this->Get('contacts_list');
|
||||
$oToImpact = $this->Get('functionalcis_list');
|
||||
|
||||
$oImpactedInfras = DBObjectSet::FromLinkSet($this, 'functionalcis_list', 'functionalci_id');
|
||||
|
||||
$aComputed = $oImpactedInfras->GetRelatedObjects('impacts', 10);
|
||||
|
||||
if (isset($aComputed['FunctionalCI']) && is_array($aComputed['FunctionalCI']))
|
||||
{
|
||||
foreach($aComputed['FunctionalCI'] as $iKey => $oObject)
|
||||
{
|
||||
$oNewLink = new lnkFunctionalCIToTicket();
|
||||
$oNewLink->Set('functionalci_id', $iKey);
|
||||
$oToImpact->AddObject($oNewLink);
|
||||
}
|
||||
}
|
||||
if (isset($aComputed['Contact']) && is_array($aComputed['Contact']))
|
||||
{
|
||||
foreach($aComputed['Contact'] as $iKey => $oObject)
|
||||
{
|
||||
$oNewLink = new lnkContactToTicket();
|
||||
$oNewLink->Set('contact_id', $iKey);
|
||||
$oNewLink->Set('role', 'contact automatically computed');
|
||||
$oToNotify->AddObject($oNewLink);
|
||||
}
|
||||
}
|
||||
|
||||
parent::OnInsert();
|
||||
$this->UpdateImpactedItems();
|
||||
$this->Set('creation_date', time());
|
||||
$this->Set('last_update', time());
|
||||
}]]></code>
|
||||
@@ -535,8 +511,15 @@
|
||||
<static>false</static>
|
||||
<access>protected</access>
|
||||
<type>Overload-DBObject</type>
|
||||
<code><![CDATA[ protected function OnUpdate()
|
||||
<code><![CDATA[
|
||||
protected function OnUpdate()
|
||||
{
|
||||
parent::OnUpdate();
|
||||
$aChanges = $this->ListChanges();
|
||||
if (array_key_exists('functionalcis_list', $aChanges))
|
||||
{
|
||||
$this->UpdateImpactedItems();
|
||||
}
|
||||
$this->Set('last_update', time());
|
||||
}]]></code>
|
||||
</method>
|
||||
|
||||
@@ -1361,61 +1361,21 @@
|
||||
<static>false</static>
|
||||
<access>public</access>
|
||||
<type>LifecycleAction</type>
|
||||
<code><![CDATA[ public function ComputeImpactedItems()
|
||||
<code><![CDATA[
|
||||
public function ComputeImpactedItems()
|
||||
{
|
||||
$oToNotify = $this->Get('contacts_list');
|
||||
$oToImpact = $this->Get('functionalcis_list');
|
||||
|
||||
$oImpactedInfras = DBObjectSet::FromLinkSet($this, 'functionalcis_list', 'functionalci_id');
|
||||
|
||||
$oGraph = $oImpactedInfras->GetRelatedObjectsDown('impacts',10, true /* bEnableRedundancy */);
|
||||
$oIterator = new RelationTypeIterator($oGraph, 'Node');
|
||||
foreach($oIterator as $oNode)
|
||||
{
|
||||
if($oNode instanceof RelationObjectNode)
|
||||
{
|
||||
if ($oNode->GetProperty('is_reached') && (!$oNode->GetProperty('source')))
|
||||
{
|
||||
$oObj = $oNode->GetProperty('object');
|
||||
$sRootClass = MetaModel::GetRootClass(get_class($oObj));
|
||||
if (!array_key_exists($sRootClass, $aComputed))
|
||||
{
|
||||
$aComputed[$sRootClass] = array();
|
||||
}
|
||||
$aComputed[$sRootClass][$oObj->GetKey()] = $oObj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($aComputed['FunctionalCI']) && is_array($aComputed['FunctionalCI']))
|
||||
{
|
||||
foreach($aComputed['FunctionalCI'] as $iKey => $oObject)
|
||||
{
|
||||
$oNewLink = new lnkFunctionalCIToTicket();
|
||||
$oNewLink->Set('functionalci_id', $iKey);
|
||||
$oNewLink->Set('impact', 'potentially impacted (automatically computed)');
|
||||
$oToImpact->AddObject($oNewLink);
|
||||
}
|
||||
}
|
||||
if (isset($aComputed['Contact']) && is_array($aComputed['Contact']))
|
||||
{
|
||||
foreach($aComputed['Contact'] as $iKey => $oObject)
|
||||
{
|
||||
$oNewLink = new lnkContactToTicket();
|
||||
$oNewLink->Set('contact_id', $iKey);
|
||||
$oNewLink->Set('role', 'contact automatically computed');
|
||||
$oToNotify->AddObject($oNewLink);
|
||||
}
|
||||
}
|
||||
parent::OnInsert();
|
||||
// This method is kept for backward compatibility
|
||||
// in case a delta redefines it, but you may call
|
||||
// UpdateImpactedItems directly
|
||||
$this->UpdateImpactedItems();
|
||||
}]]></code>
|
||||
</method>
|
||||
<method id="OnInsert">
|
||||
<static>false</static>
|
||||
<access>protected</access>
|
||||
<type>Overload-DBObject</type>
|
||||
<code><![CDATA[ protected function OnInsert()
|
||||
|
||||
<code><![CDATA[
|
||||
protected function OnInsert()
|
||||
{
|
||||
$this->ComputeImpactedItems();
|
||||
$this->Set('last_update', time());
|
||||
@@ -1426,8 +1386,15 @@
|
||||
<static>false</static>
|
||||
<access>protected</access>
|
||||
<type>Overload-DBObject</type>
|
||||
<code><![CDATA[ protected function OnUpdate()
|
||||
<code><![CDATA[
|
||||
protected function OnUpdate()
|
||||
{
|
||||
parent::OnUpdate();
|
||||
$aChanges = $this->ListChanges();
|
||||
if (array_key_exists('functionalcis_list', $aChanges))
|
||||
{
|
||||
$this->UpdateImpactedItems();
|
||||
}
|
||||
$this->Set('last_update', time());
|
||||
$this->UpdateChildRequestLog();
|
||||
}]]></code>
|
||||
|
||||
@@ -1363,62 +1363,23 @@
|
||||
<static>false</static>
|
||||
<access>public</access>
|
||||
<type>LifecycleAction</type>
|
||||
<code><![CDATA[ public function ComputeImpactedItems()
|
||||
<code><![CDATA[
|
||||
public function ComputeImpactedItems()
|
||||
{
|
||||
$oToNotify = $this->Get('contacts_list');
|
||||
$oToImpact = $this->Get('functionalcis_list');
|
||||
|
||||
$oImpactedInfras = DBObjectSet::FromLinkSet($this, 'functionalcis_list', 'functionalci_id');
|
||||
|
||||
$oGraph = $oImpactedInfras->GetRelatedObjectsDown('impacts',10, true /* bEnableRedundancy */);
|
||||
$oIterator = new RelationTypeIterator($oGraph, 'Node');
|
||||
foreach($oIterator as $oNode)
|
||||
{
|
||||
if($oNode instanceof RelationObjectNode)
|
||||
{
|
||||
if ($oNode->GetProperty('is_reached') && (!$oNode->GetProperty('source')))
|
||||
{
|
||||
$oObj = $oNode->GetProperty('object');
|
||||
$sRootClass = MetaModel::GetRootClass(get_class($oObj));
|
||||
if (!array_key_exists($sRootClass, $aComputed))
|
||||
{
|
||||
$aComputed[$sRootClass] = array();
|
||||
}
|
||||
$aComputed[$sRootClass][$oObj->GetKey()] = $oObj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($aComputed['FunctionalCI']) && is_array($aComputed['FunctionalCI']))
|
||||
{
|
||||
foreach($aComputed['FunctionalCI'] as $iKey => $oObject)
|
||||
{
|
||||
$oNewLink = new lnkFunctionalCIToTicket();
|
||||
$oNewLink->Set('functionalci_id', $iKey);
|
||||
$oNewLink->Set('impact', 'potentially impacted (automatically computed)');
|
||||
$oToImpact->AddObject($oNewLink);
|
||||
}
|
||||
}
|
||||
if (isset($aComputed['Contact']) && is_array($aComputed['Contact']))
|
||||
{
|
||||
foreach($aComputed['Contact'] as $iKey => $oObject)
|
||||
{
|
||||
$oNewLink = new lnkContactToTicket();
|
||||
$oNewLink->Set('contact_id', $iKey);
|
||||
$oNewLink->Set('role', 'contact automatically computed');
|
||||
$oToNotify->AddObject($oNewLink);
|
||||
}
|
||||
}
|
||||
parent::OnInsert();
|
||||
// This method is kept for backward compatibility
|
||||
// in case a delta redefines it, but you may call
|
||||
// UpdateImpactedItems directly
|
||||
$this->UpdateImpactedItems();
|
||||
}]]></code>
|
||||
</method>
|
||||
<method id="OnInsert">
|
||||
<static>false</static>
|
||||
<access>protected</access>
|
||||
<type>Overload-DBObject</type>
|
||||
<code><![CDATA[ protected function OnInsert()
|
||||
|
||||
<code><![CDATA[
|
||||
protected function OnInsert()
|
||||
{
|
||||
parent::OnInsert();
|
||||
$this->ComputeImpactedItems();
|
||||
$this->Set('last_update', time());
|
||||
$this->Set('start_date', time());
|
||||
@@ -1428,8 +1389,15 @@
|
||||
<static>false</static>
|
||||
<access>protected</access>
|
||||
<type>Overload-DBObject</type>
|
||||
<code><![CDATA[ protected function OnUpdate()
|
||||
<code><![CDATA[
|
||||
protected function OnUpdate()
|
||||
{
|
||||
parent::OnUpdate();
|
||||
$aChanges = $this->ListChanges();
|
||||
if (array_key_exists('functionalcis_list', $aChanges))
|
||||
{
|
||||
$this->UpdateImpactedItems();
|
||||
}
|
||||
$this->Set('last_update', time());
|
||||
$this->UpdateChildRequestLog();
|
||||
}]]></code>
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
<classes>
|
||||
<class id="Ticket" _delta="define">
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
<php_parent><name>_Ticket</name></php_parent>
|
||||
<properties>
|
||||
<comment><![CDATA[/**
|
||||
* Persistent classes for a CMDB
|
||||
@@ -366,6 +367,17 @@
|
||||
<default_value/>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
</field>
|
||||
<field id="role_code" xsi:type="AttributeEnum">
|
||||
<values>
|
||||
<value id="manual">manual</value>
|
||||
<value id="computed">computed</value>
|
||||
<value id="do_not_notify">do_not_notify</value>
|
||||
</values>
|
||||
<sql>impact_code</sql>
|
||||
<default_value>manual</default_value>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<display_style>list</display_style>
|
||||
</field>
|
||||
</fields>
|
||||
<methods/>
|
||||
<presentation>
|
||||
@@ -377,7 +389,7 @@
|
||||
<item id="contact_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
<item id="role">
|
||||
<item id="role_code">
|
||||
<rank>30</rank>
|
||||
</item>
|
||||
</items>
|
||||
@@ -390,7 +402,7 @@
|
||||
<item id="contact_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
<item id="role">
|
||||
<item id="role_code">
|
||||
<rank>30</rank>
|
||||
</item>
|
||||
</items>
|
||||
@@ -403,7 +415,7 @@
|
||||
<item id="contact_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
<item id="role">
|
||||
<item id="role_code">
|
||||
<rank>30</rank>
|
||||
</item>
|
||||
</items>
|
||||
@@ -465,6 +477,17 @@
|
||||
<default_value/>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
</field>
|
||||
<field id="impact_code" xsi:type="AttributeEnum">
|
||||
<values>
|
||||
<value id="manual">manual</value>
|
||||
<value id="computed">computed</value>
|
||||
<value id="not_impacted">not_impacted</value>
|
||||
</values>
|
||||
<sql>impact_code</sql>
|
||||
<default_value>manual</default_value>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<display_style>list</display_style>
|
||||
</field>
|
||||
</fields>
|
||||
<methods/>
|
||||
<presentation>
|
||||
@@ -476,7 +499,7 @@
|
||||
<item id="functionalci_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
<item id="impact">
|
||||
<item id="impact_code">
|
||||
<rank>30</rank>
|
||||
</item>
|
||||
</items>
|
||||
@@ -489,7 +512,7 @@
|
||||
<item id="functionalci_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
<item id="impact">
|
||||
<item id="impact_code">
|
||||
<rank>30</rank>
|
||||
</item>
|
||||
</items>
|
||||
@@ -502,7 +525,7 @@
|
||||
<item id="functionalci_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
<item id="impact">
|
||||
<item id="impact_code">
|
||||
<rank>30</rank>
|
||||
</item>
|
||||
</items>
|
||||
|
||||
@@ -58,22 +58,31 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Class:Ticket/Attribute:workorders_list+' => '',
|
||||
'Class:Ticket/Attribute:finalclass' => 'Typ',
|
||||
'Class:Ticket/Attribute:finalclass+' => '',
|
||||
'Ticket:ImpactAnalysis' => 'Impact Analysis~~',
|
||||
'Class:lnkContactToTicket' => 'Verknüpfung Kontakt/Ticket',
|
||||
'Class:lnkContactToTicket+' => '',
|
||||
'Class:lnkContactToTicket/Attribute:ticket_id' => 'Ticket',
|
||||
'Class:lnkContactToTicket/Attribute:ticket_id+' => '',
|
||||
'Class:lnkContactToTicket/Attribute:contact_id' => 'Kontakt',
|
||||
'Class:lnkContactToTicket/Attribute:contact_id+' => '',
|
||||
'Class:lnkContactToTicket/Attribute:role' => 'Rolle',
|
||||
'Class:lnkContactToTicket/Attribute:role' => 'Rolle (Text)',
|
||||
'Class:lnkContactToTicket/Attribute:role+' => '',
|
||||
'Class:lnkContactToTicket/Attribute:role_code' => 'Rolle',
|
||||
'Class:lnkContactToTicket/Attribute:role_code/Value:manual' => 'Added manually~~',
|
||||
'Class:lnkContactToTicket/Attribute:role_code/Value:computed' => 'Computed~~',
|
||||
'Class:lnkContactToTicket/Attribute:role_code/Value:do_not_notify' => 'Do not notify~~',
|
||||
'Class:lnkFunctionalCIToTicket' => 'Verknüpfung FunctionalCI/Ticket',
|
||||
'Class:lnkFunctionalCIToTicket+' => '',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:ticket_id' => 'Ticket',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:ticket_id+' => '',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:functionalci_id' => 'CI',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:functionalci_id+' => '',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:impact' => 'Auswirkung',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:impact' => 'Auswirkung (Text)',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:impact+' => '',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:impact_code' => 'Auswirkung',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:impact_code/Value:manual' => 'Added manually~~',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:impact_code/Value:computed' => 'Computed~~',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:impact_code/Value:not_impacted' => 'Not impacted~~',
|
||||
'Class:WorkOrder' => 'Arbeitsauftrag',
|
||||
'Class:WorkOrder+' => '',
|
||||
'Class:WorkOrder/Attribute:name' => 'Name',
|
||||
|
||||
@@ -82,6 +82,7 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:Ticket/Attribute:workorders_list+' => 'All the work orders for this ticket',
|
||||
'Class:Ticket/Attribute:finalclass' => 'Type',
|
||||
'Class:Ticket/Attribute:finalclass+' => '',
|
||||
'Ticket:ImpactAnalysis' => 'Impact Analysis',
|
||||
));
|
||||
|
||||
|
||||
@@ -100,8 +101,12 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:lnkContactToTicket/Attribute:contact_id+' => '',
|
||||
'Class:lnkContactToTicket/Attribute:contact_email' => 'Contact Email',
|
||||
'Class:lnkContactToTicket/Attribute:contact_email+' => '',
|
||||
'Class:lnkContactToTicket/Attribute:role' => 'Role',
|
||||
'Class:lnkContactToTicket/Attribute:role' => 'Role (text)',
|
||||
'Class:lnkContactToTicket/Attribute:role+' => '',
|
||||
'Class:lnkContactToTicket/Attribute:role_code' => 'Role',
|
||||
'Class:lnkContactToTicket/Attribute:role_code/Value:manual' => 'Added manually',
|
||||
'Class:lnkContactToTicket/Attribute:role_code/Value:computed' => 'Computed',
|
||||
'Class:lnkContactToTicket/Attribute:role_code/Value:do_not_notify' => 'Do not notify',
|
||||
));
|
||||
|
||||
//
|
||||
@@ -119,8 +124,12 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:functionalci_id+' => '',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:functionalci_name' => 'CI Name',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:functionalci_name+' => '',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:impact' => 'Impact',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:impact' => 'Impact (text)',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:impact+' => '',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:impact_code' => 'Impact',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:impact_code/Value:manual' => 'Added manually',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:impact_code/Value:computed' => 'Computed',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:impact_code/Value:not_impacted' => 'Not impacted',
|
||||
));
|
||||
|
||||
|
||||
|
||||
@@ -69,6 +69,7 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Class:Ticket/Attribute:workorders_list+' => '',
|
||||
'Class:Ticket/Attribute:finalclass' => 'Type',
|
||||
'Class:Ticket/Attribute:finalclass+' => '',
|
||||
'Ticket:ImpactAnalysis' => 'Analyse d\'Impact',
|
||||
));
|
||||
|
||||
|
||||
@@ -87,8 +88,12 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Class:lnkContactToTicket/Attribute:contact_id+' => '',
|
||||
'Class:lnkContactToTicket/Attribute:contact_email' => 'Email Contact',
|
||||
'Class:lnkContactToTicket/Attribute:contact_email+' => '',
|
||||
'Class:lnkContactToTicket/Attribute:role' => 'Rôle',
|
||||
'Class:lnkContactToTicket/Attribute:role' => 'Rôle (texte)',
|
||||
'Class:lnkContactToTicket/Attribute:role+' => '',
|
||||
'Class:lnkContactToTicket/Attribute:role_code' => 'Rôle',
|
||||
'Class:lnkContactToTicket/Attribute:role_code/Value:manual' => 'Ajouté manuellement',
|
||||
'Class:lnkContactToTicket/Attribute:role_code/Value:computed' => 'Calculé',
|
||||
'Class:lnkContactToTicket/Attribute:role_code/Value:do_not_notify' => 'Ne pas notifier',
|
||||
));
|
||||
|
||||
//
|
||||
@@ -106,8 +111,12 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:functionalci_id+' => '',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:functionalci_name' => 'Nom CI',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:functionalci_name+' => '',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:impact' => 'Impact',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:impact' => 'Impact (texte)',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:impact+' => '',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:impact_code' => 'Impact',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:impact_code/Value:manual' => 'Ajouté manuellement',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:impact_code/Value:computed' => 'Calculé',
|
||||
'Class:lnkFunctionalCIToTicket/Attribute:impact_code/Value:not_impacted' => 'Non impacté',
|
||||
));
|
||||
|
||||
|
||||
|
||||
@@ -127,4 +127,124 @@ class ResponseTicketTTR extends ResponseTicketSLT implements iMetricComputer
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class _Ticket extends cmdbAbstractObject
|
||||
{
|
||||
|
||||
public function UpdateImpactedItems()
|
||||
{
|
||||
$oContactsSet = $this->Get('contacts_list');
|
||||
$oCIsSet = $this->Get('functionalcis_list');
|
||||
|
||||
$aCIsToImpactCode = array();
|
||||
$aSources = array();
|
||||
$aExcluded = array();
|
||||
|
||||
$oCIsSet->Rewind();
|
||||
while ($oLink = $oCIsSet->Fetch())
|
||||
{
|
||||
$iKey = $oLink->Get('functionalci_id');
|
||||
$aCIsToImpactCode[$iKey] = $oLink->Get('impact_code');
|
||||
if ($oLink->Get('impact_code') == 'manual')
|
||||
{
|
||||
$oObj = MetaModel::GetObject('FunctionalCI', $iKey);
|
||||
$aSources[$iKey] = $oObj;
|
||||
}
|
||||
else if ($oLink->Get('impact_code') == 'not_impacted')
|
||||
{
|
||||
$oObj = MetaModel::GetObject('FunctionalCI', $iKey);
|
||||
$aExcluded[$iKey] = $oObj;
|
||||
}
|
||||
}
|
||||
|
||||
$aContactsToRoleCode = array();
|
||||
$oContactsSet->Rewind();
|
||||
while ($oLink = $oContactsSet->Fetch())
|
||||
{
|
||||
$iKey = $oLink->Get('contact_id');
|
||||
$aContactsToRoleCode[$iKey] = $oLink->Get('role_code');
|
||||
if ($oLink->Get('role_code') == 'do_not_notify')
|
||||
{
|
||||
$oObj = MetaModel::GetObject('Contact', $iKey);
|
||||
$aExcluded[$iKey] = $oObj;
|
||||
}
|
||||
}
|
||||
|
||||
$oNewCIsSet = DBObjectSet::FromScratch('lnkFunctionalCIToTicket');
|
||||
foreach($aCIsToImpactCode as $iKey => $sImpactCode)
|
||||
{
|
||||
if ($sImpactCode != 'computed')
|
||||
{
|
||||
$oNewLink = new lnkFunctionalCIToTicket();
|
||||
$oNewLink->Set('functionalci_id', $iKey);
|
||||
$oNewLink->Set('impact_code', $sImpactCode);
|
||||
$oNewCIsSet->AddObject($oNewLink);
|
||||
}
|
||||
}
|
||||
|
||||
$oNewContactsSet = DBObjectSet::FromScratch('lnkContactToTicket');
|
||||
foreach($aContactsToRoleCode as $iKey => $sImpactCode)
|
||||
{
|
||||
if ($sImpactCode != 'computed')
|
||||
{
|
||||
$oNewLink = new lnkContactToTicket();
|
||||
$oNewLink->Set('contact_id', $iKey);
|
||||
$oNewLink->Set('role_code', $sImpactCode);
|
||||
$oNewContactsSet->AddObject($oNewLink);
|
||||
}
|
||||
}
|
||||
|
||||
$oContactsSet = DBObjectSet::FromScratch('lnkContactToTicket');
|
||||
$oGraph = MetaModel::GetRelatedObjectsDown('impacts', $aSources, 10, true /* bEnableRedundancy */, $aExcluded);
|
||||
$oIterator = new RelationTypeIterator($oGraph, 'Node');
|
||||
foreach ($oIterator as $oNode)
|
||||
{
|
||||
if ( ($oNode instanceof RelationObjectNode) && ($oNode->GetProperty('is_reached')) && (!$oNode->GetProperty('source')))
|
||||
{
|
||||
$oObj = $oNode->GetProperty('object');
|
||||
$iKey = $oObj->GetKey();
|
||||
$sRootClass = MetaModel::GetRootClass(get_class($oObj));
|
||||
switch ($sRootClass)
|
||||
{
|
||||
case 'FunctionalCI':
|
||||
// Only link FunctionalCIs which are not already linked to the ticket
|
||||
if (!array_key_exists($iKey, $aCIsToImpactCode) || ($aCIsToImpactCode[$iKey] != 'not_impacted'))
|
||||
{
|
||||
$oNewLink = new lnkFunctionalCIToTicket();
|
||||
$oNewLink->Set('functionalci_id', $iKey);
|
||||
$oNewLink->Set('impact_code', 'computed');
|
||||
$oNewCIsSet->AddObject($oNewLink);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'Contact':
|
||||
// Only link Contacts which are not already linked to the ticket
|
||||
if (!array_key_exists($iKey, $aContactsToRoleCode) || ($aCIsToImpactCode[$iKey] != 'do_not_notify'))
|
||||
{
|
||||
$oNewLink = new lnkContactToTicket();
|
||||
$oNewLink->Set('contact_id', $iKey);
|
||||
$oNewLink->Set('role_code', 'computed');
|
||||
$oNewContactsSet->AddObject($oNewLink);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->Set('functionalcis_list', $oNewCIsSet);
|
||||
$this->Set('contacts_list', $oNewContactsSet);
|
||||
}
|
||||
|
||||
public function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
|
||||
{
|
||||
parent::DisplayBareRelations($oPage, $bEditMode);
|
||||
if (!$bEditMode)
|
||||
{
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/fraphael.js');
|
||||
$oPage->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/jquery.contextMenu.css');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.contextMenu.js');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/simple_graph.js');
|
||||
$oPage->AddAjaxTab(Dict::S('Ticket:ImpactAnalysis'), utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=ticket_impact&class='.get_class($this).'&id='.$this->GetKey(), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__,
|
||||
'itop-tickets/2.1.0',
|
||||
'itop-tickets/2.2.0',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
@@ -22,8 +22,8 @@ SetupWebPage::AddModule(
|
||||
// Components
|
||||
//
|
||||
'datamodel' => array(
|
||||
'model.itop-tickets.php',
|
||||
'main.itop-tickets.php',
|
||||
'model.itop-tickets.php',
|
||||
),
|
||||
'data.struct' => array(
|
||||
// 'data.struct.ta-actions.xml',
|
||||
|
||||
@@ -777,6 +777,7 @@ Wenn Aktionen mit Trigger verknüpft sind, bekommt jede Aktion eine Auftragsnumm
|
||||
'UI:RelationGroups' => 'Gruppen',
|
||||
'UI:RelationGroupNumber_N' => 'Gruppe #%1$d~~',
|
||||
'UI:Relation:ExportAsPDF' => 'Export as PDF...~~',
|
||||
'UI:RelationOption:GroupingThreshold' => 'Grouping threshold~~',
|
||||
'UI:Relation:ExportAsDocument' => 'Export as Document...~~',
|
||||
'UI:Relation:DrillDown' => 'Details...~~',
|
||||
'UI:Relation:PDFExportOptions' => 'PDF Export Options~~',
|
||||
|
||||
@@ -970,6 +970,7 @@ When associated with a trigger, each action is given an "order" number, specifyi
|
||||
'UI:ElementsDisplayed' => 'Filtering',
|
||||
'UI:RelationGroupNumber_N' => 'Group #%1$d',
|
||||
'UI:Relation:ExportAsPDF' => 'Export as PDF...',
|
||||
'UI:RelationOption:GroupingThreshold' => 'Grouping threshold',
|
||||
'UI:Relation:ExportAsDocument' => 'Export as Document...',
|
||||
'UI:Relation:DrillDown' => 'Details...',
|
||||
'UI:Relation:PDFExportOptions' => 'PDF Export Options',
|
||||
|
||||
@@ -812,10 +812,11 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé
|
||||
'UI:RelationGroups' => 'Groupes',
|
||||
'UI:ElementsDisplayed' => 'Filtrage',
|
||||
'UI:RelationGroupNumber_N' => 'Groupe n°%1$d',
|
||||
'UI:Relation:ExportAsPDF' => 'Exportation en PDF...',
|
||||
'UI:Relation:ExportAsDocument' => 'Exportation comme Document...',
|
||||
'UI:Relation:ExportAsPDF' => 'Exporter en PDF...',
|
||||
'UI:RelationOption:GroupingThreshold' => 'Seuil de groupage',
|
||||
'UI:Relation:ExportAsDocument' => 'Exporter comme Document...',
|
||||
'UI:Relation:DrillDown' => 'Détails...',
|
||||
'UI:Relation:PDFExportOptions' => 'Options de l\'Exportation PDF',
|
||||
'UI:Relation:PDFExportOptions' => 'Options de l\'export en PDF',
|
||||
'UI:Relation:Key' => 'Légende',
|
||||
'UI:Relation:Comments' => 'Commentaires',
|
||||
'UI:RelationOption:Title' => 'Titre',
|
||||
|
||||
@@ -16,13 +16,24 @@ $(function()
|
||||
align: 'center',
|
||||
'vertical-align': 'middle',
|
||||
source_url: null,
|
||||
sources: {},
|
||||
excluded: {},
|
||||
export_as_pdf: null,
|
||||
page_format: { label: 'Page Format:', values: { A3: 'A3', A4: 'A4', Letter: 'Letter' }, 'default': 'A4'},
|
||||
page_orientation: { label: 'Page Orientation:', values: { P: 'Portait', L: 'Landscape' }, 'default': 'L' },
|
||||
labels: { export_pdf_title: 'PDF Export Options', cancel: 'Cancel', 'export': 'Export', title: 'Document Title', include_list: 'Include the list of objects', comments: 'Comments' },
|
||||
labels: {
|
||||
export_pdf_title: 'PDF Export Options',
|
||||
cancel: 'Cancel', 'export': 'Export',
|
||||
title: 'Document Title',
|
||||
include_list: 'Include the list of objects',
|
||||
comments: 'Comments',
|
||||
grouping_threshold: 'Grouping Threshold',
|
||||
refresh: 'Refresh'
|
||||
},
|
||||
export_as_document: null,
|
||||
drill_down: null,
|
||||
excluded: []
|
||||
grouping_threshold: 10,
|
||||
excluded_classes: []
|
||||
},
|
||||
|
||||
// the constructor
|
||||
@@ -352,7 +363,10 @@ $(function()
|
||||
_create_toolkit_menu: function()
|
||||
{
|
||||
var sPopupMenuId = 'tk_graph'+this.element.attr('id');
|
||||
var sHtml = '<div class="itop_popup toolkit_menu graph" style="font-size: 12px;" id="'+sPopupMenuId+'"><ul><li><img src="../images/toolkit_menu.png"><ul>';
|
||||
var sHtml = '<div class="graph_config">';
|
||||
var sId = this.element.attr('id');
|
||||
sHtml += this.options.labels.grouping_threshold+' <input type="text" name="g" value="'+this.options.grouping_threshold+'" id="'+sId+'_grouping_threshold" size="2"> <button type="button" id="'+sId+'_refresh_btn">'+this.options.labels.refresh+'</button>';
|
||||
sHtml += '<div class="itop_popup toolkit_menu graph" style="font-size: 12px;" id="'+sPopupMenuId+'"><ul><li><img src="../images/toolkit_menu.png"><ul>';
|
||||
if (this.options.export_as_pdf != null)
|
||||
{
|
||||
sHtml += '<li><a href="#" id="'+sPopupMenuId+'_pdf">'+this.options.export_as_pdf.label+'</a></li>';
|
||||
@@ -363,16 +377,17 @@ $(function()
|
||||
}
|
||||
//sHtml += '<li><a href="#" id="'+sPopupMenuId+'_reload">Refresh</a></li>';
|
||||
sHtml += '</ul></li></ul></div>';
|
||||
sHtml += '</div>';
|
||||
|
||||
this.element.before(sHtml);
|
||||
$('#'+sPopupMenuId).popupmenu();
|
||||
$('#'+sPopupMenuId+'>ul').popupmenu();
|
||||
|
||||
|
||||
var me = this;
|
||||
$('#'+sPopupMenuId+'_pdf').click(function() { me.export_as_pdf(); });
|
||||
$('#'+sPopupMenuId+'_document').click(function() { me.export_as_document(); });
|
||||
$('#'+sPopupMenuId+'_reload').click(function() { me.reload(); });
|
||||
|
||||
$('#'+sId+'_grouping_threshold').spinner({ min: 2});
|
||||
$('#'+sId+'_refresh_btn').button().click(function() { me.reload(); });
|
||||
},
|
||||
_build_context_menus: function()
|
||||
{
|
||||
@@ -400,13 +415,16 @@ $(function()
|
||||
{
|
||||
case 'group':
|
||||
var sGroupIndex = oNode.group_index;
|
||||
oResult = {
|
||||
callback: function(key, options) {
|
||||
var me = $('.itop-simple-graph').data('itopSimple_graph'); // need a live value
|
||||
me.show_group('relation_group_'+sGroupIndex);
|
||||
},
|
||||
items: { 'show': {name: me.options.drill_down.label } }
|
||||
};
|
||||
if( $('#relation_group_'+sGroupIndex).length > 0)
|
||||
{
|
||||
oResult = {
|
||||
callback: function(key, options) {
|
||||
var me = $('.itop-simple-graph').data('itopSimple_graph'); // need a live value
|
||||
me.show_group('relation_group_'+sGroupIndex);
|
||||
},
|
||||
items: { 'show': {name: me.options.drill_down.label } }
|
||||
};
|
||||
}
|
||||
break;
|
||||
|
||||
case 'icon':
|
||||
@@ -438,10 +456,25 @@ $(function()
|
||||
oPositions[this.aNodes[k].id] = {x: this.aNodes[k].x, y: this.aNodes[k].y };
|
||||
}
|
||||
var sHtmlForm = '<div id="PDFExportDlg'+this.element.attr('id')+'"><form id="graph_'+this.element.attr('id')+'_export_as_pdf" target="_blank" action="'+this.options.export_as_pdf.url+'" method="post">';
|
||||
sHtmlForm += '<input type="hidden" name="g" value="'+this.options.grouping_threshold+'">';
|
||||
sHtmlForm += '<input type="hidden" name="positions" value="">';
|
||||
for(k in this.options.excluded)
|
||||
for(k in this.options.excluded_classes)
|
||||
{
|
||||
sHtmlForm += '<input type="hidden" name="excluded[]" value="'+this.options.excluded[k]+'">';
|
||||
sHtmlForm += '<input type="hidden" name="excluded_classes[]" value="'+this.options.excluded_classes[k]+'">';
|
||||
}
|
||||
for(var k1 in this.options.sources)
|
||||
{
|
||||
for(var k2 in this.options.sources[k1])
|
||||
{
|
||||
sHtmlForm += '<input type="hidden" name="sources['+k1+'][]" value="'+this.options.sources[k1][k2]+'">';
|
||||
}
|
||||
}
|
||||
for(var k1 in this.options.excluded)
|
||||
{
|
||||
for(var k2 in this.options.excluded[k1])
|
||||
{
|
||||
sHtmlForm += '<input type="hidden" name="excluded['+k1+'][]" value="'+this.options.excluded[k1][k2]+'">';
|
||||
}
|
||||
}
|
||||
sHtmlForm += '<table>';
|
||||
sHtmlForm += '<tr><td>'+this.options.page_format.label+'</td><td><select name="p">';
|
||||
@@ -507,9 +540,16 @@ $(function()
|
||||
{
|
||||
this.options.load_from_url = sUrl;
|
||||
var me = this;
|
||||
var sId = this.element.attr('id');
|
||||
this.options.grouping_threshold = $('#'+sId+'_grouping_threshold').val();
|
||||
if (this.options.grouping_threshold < 2)
|
||||
{
|
||||
this.options.grouping_threshold = 2;
|
||||
$('#'+sId+'_grouping_threshold').val(this.options.grouping_threshold);
|
||||
}
|
||||
this.element.closest('.ui-tabs').tabs({ heightStyle: "fill" });
|
||||
this.oPaper.rect(0, 0, this.element.width(), this.element.height()).attr({fill: '#000', opacity: 0.4, 'stroke-width': 0});
|
||||
$.post(sUrl, {excluded: this.options.excluded }, function(data) {
|
||||
$.post(sUrl, {excluded_classes: this.options.excluded_classes, g: this.options.grouping_threshold, sources: this.options.sources, excluded: this.options.excluded }, function(data) {
|
||||
me.load(data);
|
||||
}, 'json');
|
||||
},
|
||||
|
||||
185
pages/UI.php
185
pages/UI.php
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
// Copyright (C) 2010-2015 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -262,163 +262,11 @@ function DisplayNavigatorGroupTab($oP, $aGroups, $sRelation, $oObj)
|
||||
}
|
||||
}
|
||||
|
||||
function DisplayNavigatorGraphicsTab($oP, $aResults, $oDisplayGraph, $sClass, $id, $sRelation, $oAppContext, $bDirectionDown)
|
||||
{
|
||||
$oP->SetCurrentTab(Dict::S('UI:RelationshipGraph'));
|
||||
|
||||
$oP->add("<div id=\"ds_flash\" class=\"SearchDrawer\" style=\"display:none;\">\n");
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$( "#tabbedContent_0" ).tabs({ heightStyle: "fill" });
|
||||
$("#dh_flash").click( function() {
|
||||
$("#ds_flash").slideToggle('normal', function() { $("#ds_flash").parent().resize(); } );
|
||||
$("#dh_flash").toggleClass('open');
|
||||
});
|
||||
EOF
|
||||
);
|
||||
$aSortedElements = array();
|
||||
foreach($aResults as $sClassIdx => $aObjects)
|
||||
{
|
||||
foreach($aObjects as $oCurrObj)
|
||||
{
|
||||
$sSubClass = get_class($oCurrObj);
|
||||
$aSortedElements[$sSubClass] = MetaModel::GetName($sSubClass);
|
||||
}
|
||||
}
|
||||
|
||||
asort($aSortedElements);
|
||||
$idx = 0;
|
||||
foreach($aSortedElements as $sSubClass => $sClassName)
|
||||
{
|
||||
$oP->add("<span style=\"padding-right:2em; white-space:nowrap;\"><input type=\"checkbox\" id=\"exclude_$idx\" name=\"excluded[]\" value=\"$sSubClass\" checked onChange=\"$('#ReloadMovieBtn').button('enable')\"><label for=\"exclude_$idx\"> ".MetaModel::GetClassIcon($sSubClass)." $sClassName</label></span> ");
|
||||
$idx++;
|
||||
}
|
||||
$oP->add("<p style=\"text-align:right\"><button type=\"button\" id=\"ReloadMovieBtn\" onClick=\"DoReload()\">".Dict::S('UI:Button:Refresh')."</button></p>");
|
||||
$oP->add("</div>\n");
|
||||
$oP->add("<div class=\"HRDrawer\"></div>\n");
|
||||
$oP->add("<div id=\"dh_flash\" class=\"DrawerHandle\">".Dict::S('UI:ElementsDisplayed')."</div>\n");
|
||||
|
||||
$sDirection = utils::ReadParam('d', 'horizontal');
|
||||
$iGroupingThreshold = utils::ReadParam('g', 5);
|
||||
|
||||
$oP->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/fraphael.js');
|
||||
$oP->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/jquery.contextMenu.css');
|
||||
$oP->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.contextMenu.js');
|
||||
$oP->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/simple_graph.js');
|
||||
try
|
||||
{
|
||||
$oDisplayGraph->InitFromGraphviz();
|
||||
$sExportAsPdfURL = '';
|
||||
if (extension_loaded('gd'))
|
||||
{
|
||||
$sExportAsPdfURL = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=relation_pdf&relation='.$sRelation.'&direction='.($bDirectionDown ? 'down' : 'up').'&class='.$sClass.'&id='.$id.'&g='.$iGroupingThreshold;
|
||||
}
|
||||
$oAppcontext = new ApplicationContext();
|
||||
$sContext = $oAppContext->GetForLink();
|
||||
$sDrillDownURL = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=details&class=%1$s&id=%2$s&'.$sContext;
|
||||
$sExportAsDocumentURL = '';
|
||||
$sLoadFromURL = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=relation_json&relation='.$sRelation.'&direction='.($bDirectionDown ? 'down' : 'up').'&class='.$sClass.'&id='.$id.'&g='.$iGroupingThreshold;
|
||||
|
||||
$sId = 'graph';
|
||||
$oP->add('<div id="'.$sId.'" class="simple-graph"></div>');
|
||||
$aParams = array(
|
||||
'source_url' => $sLoadFromURL,
|
||||
'export_as_pdf' => array('url' => $sExportAsPdfURL, 'label' => Dict::S('UI:Relation:ExportAsPDF')),
|
||||
//'export_as_document' => array('url' => $sExportAsDocumentURL, 'label' => Dict::S('UI:Relation:ExportAsDocument')),
|
||||
'drill_down' => array('url' => $sDrillDownURL, 'label' => Dict::S('UI:Relation:DrillDown')),
|
||||
'labels' => array(
|
||||
'export_pdf_title' => Dict::S('UI:Relation:PDFExportOptions'),
|
||||
'export' => Dict::S('UI:Button:Export'),
|
||||
'cancel' => Dict::S('UI:Button:Cancel'),
|
||||
'title' => Dict::S('UI:RelationOption:Title'),
|
||||
'include_list' => Dict::S('UI:RelationOption:IncludeList'),
|
||||
'comments' => Dict::S('UI:RelationOption:Comments'),
|
||||
),
|
||||
'page_format' => array(
|
||||
'label' => Dict::S('UI:Relation:PDFExportPageFormat'),
|
||||
'values' => array(
|
||||
'A3' => Dict::S('UI:PageFormat_A3'),
|
||||
'A4' => Dict::S('UI:PageFormat_A4'),
|
||||
'Letter' => Dict::S('UI:PageFormat_Letter'),
|
||||
),
|
||||
),
|
||||
'page_orientation' => array(
|
||||
'label' => Dict::S('UI:Relation:PDFExportPageOrientation'),
|
||||
'values' => array(
|
||||
'P' => Dict::S('UI:PageOrientation_Portrait'),
|
||||
'L' => Dict::S('UI:PageOrientation_Landscape'),
|
||||
),
|
||||
),
|
||||
);
|
||||
$oP->add_ready_script("$('#$sId').simple_graph(".json_encode($aParams).");");
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$oP->add('<div>'.$e->getMessage().'</div>');
|
||||
}
|
||||
$oP->add_script(
|
||||
<<<EOF
|
||||
|
||||
function DoReload()
|
||||
{
|
||||
$('#ReloadMovieBtn').button('disable');
|
||||
try
|
||||
{
|
||||
var aExcluded = [];
|
||||
$('input[name^=excluded]').each( function() {
|
||||
if (!$(this).prop('checked'))
|
||||
{
|
||||
aExcluded.push($(this).val());
|
||||
}
|
||||
} );
|
||||
$('#graph').simple_graph('option', {excluded: aExcluded});
|
||||
$('#graph').simple_graph('reload');
|
||||
}
|
||||
catch(err)
|
||||
{
|
||||
alert(err);
|
||||
}
|
||||
}
|
||||
EOF
|
||||
);
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
var ajax_request = null;
|
||||
|
||||
$('#ReloadMovieBtn').button().button('disable');
|
||||
|
||||
function UpdateImpactedObjects(sClass, iId, sRelation)
|
||||
{
|
||||
var class_name = sClass; //$('select[name=class_name]').val();
|
||||
if (class_name != '')
|
||||
{
|
||||
$('#impacted_objects').block();
|
||||
|
||||
// Make sure that we cancel any pending request before issuing another
|
||||
// since responses may arrive in arbitrary order
|
||||
if (ajax_request != null)
|
||||
{
|
||||
ajax_request.abort();
|
||||
ajax_request = null;
|
||||
}
|
||||
|
||||
ajax_request = $.get(GetAbsoluteUrlAppRoot()+'pages/xml.navigator.php', { 'class': sClass, id: iId, relation: sRelation, format: 'html' },
|
||||
function(data)
|
||||
{
|
||||
alert('Not yet implemented');
|
||||
$('#impacted_objects').unblock();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
/***********************************************************************************
|
||||
*
|
||||
* Main user interface page, starts here
|
||||
* Main user interface page starts here
|
||||
*
|
||||
* ***********************************************************************************/
|
||||
***********************************************************************************/
|
||||
try
|
||||
{
|
||||
require_once('../approot.inc.php');
|
||||
@@ -1608,26 +1456,11 @@ EOF
|
||||
}
|
||||
|
||||
|
||||
$aResults = array();
|
||||
$aGroups = array();
|
||||
$iGroupIdx = 0;
|
||||
$oIterator = new RelationTypeIterator($oRelGraph, 'Node');
|
||||
foreach($oIterator as $oNode)
|
||||
{
|
||||
$oObj = $oNode->GetProperty('object'); // Some nodes (Redundancy Nodes and Group) do not contain an object
|
||||
if ($oObj)
|
||||
{
|
||||
$sObjClass = get_class($oObj);
|
||||
if (!array_key_exists($sObjClass, $aResults))
|
||||
{
|
||||
$aResults[$sObjClass] = array();
|
||||
}
|
||||
$aResults[$sObjClass][] = $oObj;
|
||||
}
|
||||
}
|
||||
|
||||
$aResults = $oRelGraph->GetObjectsByClass();
|
||||
$oDisplayGraph = DisplayableGraph::FromRelationGraph($oRelGraph, $iGroupingThreshold, ($sDirection == 'down'));
|
||||
|
||||
$aGroups = array();
|
||||
$iGroupIdx = 0;
|
||||
$oIterator = new RelationTypeIterator($oDisplayGraph, 'Node');
|
||||
foreach($oIterator as $oNode)
|
||||
{
|
||||
@@ -1646,12 +1479,14 @@ EOF
|
||||
if ($sFirstTab == 'list')
|
||||
{
|
||||
DisplayNavigatorListTab($oP, $aResults, $sRelation, $oObj);
|
||||
DisplayNavigatorGraphicsTab($oP, $aResults, $oDisplayGraph, $sClass, $id, $sRelation, $oAppContext, ($sDirection == 'down'));
|
||||
$oP->SetCurrentTab(Dict::S('UI:RelationshipGraph'));
|
||||
$oDisplayGraph->Display($oP, $aResults, $sRelation, $oAppContext, ($sDirection == 'down'));
|
||||
DisplayNavigatorGroupTab($oP, $aGroups, $sRelation, $oObj);
|
||||
}
|
||||
else
|
||||
{
|
||||
DisplayNavigatorGraphicsTab($oP, $aResults, $oDisplayGraph, $sClass, $id, $sRelation, $oAppContext, ($sDirection == 'down'));
|
||||
$oP->SetCurrentTab(Dict::S('UI:RelationshipGraph'));
|
||||
$oDisplayGraph->Display($oP, $aResults, $sRelation, $oAppContext, ($sDirection == 'down'));
|
||||
DisplayNavigatorListTab($oP, $aResults, $sRelation, $oObj);
|
||||
DisplayNavigatorGroupTab($oP, $aGroups, $sRelation, $oObj);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2014 Combodo SARL
|
||||
// Copyright (C) 2010-2015 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -1731,9 +1731,7 @@ EOF
|
||||
require_once(APPROOT.'core/simplegraph.class.inc.php');
|
||||
require_once(APPROOT.'core/relationgraph.class.inc.php');
|
||||
require_once(APPROOT.'core/displayablegraph.class.inc.php');
|
||||
$sClass = utils::ReadParam('class', '', false, 'class');
|
||||
$id = (int)utils::ReadParam('id', 0);
|
||||
$sRelation = utils::ReadParam('relation', 'impact');
|
||||
$sRelation = utils::ReadParam('relation', 'impacts');
|
||||
$sDirection = utils::ReadParam('direction', 'down');
|
||||
|
||||
$iGroupingThreshold = utils::ReadParam('g', 5);
|
||||
@@ -1741,7 +1739,7 @@ EOF
|
||||
$sPageOrientation = utils::ReadParam('o', 'L');
|
||||
$sTitle = utils::ReadParam('title', '', false, 'raw_data');
|
||||
$sPositions = utils::ReadParam('positions', null, false, 'raw_data');
|
||||
$aExcluded = utils::ReadParam('excluded', array(), false, 'raw_data');
|
||||
$aExcludedClasses = utils::ReadParam('excluded_classes', array(), false, 'raw_data');
|
||||
$bIncludeList = (bool)utils::ReadParam('include_list', false);
|
||||
$sComments = utils::ReadParam('comments', '', false, 'raw_data');
|
||||
$aPositions = null;
|
||||
@@ -1750,26 +1748,52 @@ EOF
|
||||
$aPositions = json_decode($sPositions, true);
|
||||
}
|
||||
|
||||
$oObj = MetaModel::GetObject($sClass, $id);
|
||||
// Get the list of source objects
|
||||
$aSources = utils::ReadParam('sources', array(), false, 'raw_data');
|
||||
$aSourceObjects = array();
|
||||
foreach($aSources as $sClass => $aIDs)
|
||||
{
|
||||
$oSearch = new DBObjectSearch($sClass);
|
||||
$oSearch->AddCondition('id', $aIDs, 'IN');
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
while($oObj = $oSet->Fetch())
|
||||
{
|
||||
$aSourceObjects[] = $oObj;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the list of excluded objects
|
||||
$aExcluded = utils::ReadParam('excluded', array(), false, 'raw_data');
|
||||
$aExcludedObjects = array();
|
||||
foreach($aExcluded as $sClass => $aIDs)
|
||||
{
|
||||
$oSearch = new DBObjectSearch($sClass);
|
||||
$oSearch->AddCondition('id', $aIDs, 'IN');
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
while($oObj = $oSet->Fetch())
|
||||
{
|
||||
$aExcludedObjects[] = $oObj;
|
||||
}
|
||||
}
|
||||
|
||||
$iMaxRecursionDepth = MetaModel::GetConfig()->Get('relations_max_depth', 20);
|
||||
$aSourceObjects = array($oObj);
|
||||
if ($sDirection == 'up')
|
||||
{
|
||||
$oRelGraph = MetaModel::GetRelatedObjectsUp($sRelation, $aSourceObjects, $iMaxRecursionDepth);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oRelGraph = MetaModel::GetRelatedObjectsDown($sRelation, $aSourceObjects, $iMaxRecursionDepth);
|
||||
$oRelGraph = MetaModel::GetRelatedObjectsDown($sRelation, $aSourceObjects, $iMaxRecursionDepth, true, $aExcludedObjects);
|
||||
}
|
||||
|
||||
// Remove excluded classes from the graph
|
||||
if (count($aExcluded) > 0)
|
||||
if (count($aExcludedClasses) > 0)
|
||||
{
|
||||
$oIterator = new RelationTypeIterator($oRelGraph, 'Node');
|
||||
foreach($oIterator as $oNode)
|
||||
{
|
||||
$oObj = $oNode->GetProperty('object');
|
||||
if ($oObj && in_array(get_class($oObj), $aExcluded))
|
||||
if ($oObj && in_array(get_class($oObj), $aExcludedClasses))
|
||||
{
|
||||
$oRelGraph->FilterNode($oNode);
|
||||
}
|
||||
@@ -1798,13 +1822,7 @@ EOF
|
||||
}
|
||||
// First page is the graph
|
||||
$oGraph->RenderAsPDF($oPage, $sComments);
|
||||
/*
|
||||
// Experimental QR code at the bottom left of the page...
|
||||
$sUrl = "r=$sRelation&d=$sDirection&c=$sClass&id=$id";
|
||||
$oPdf = $oPage->get_tcpdf();
|
||||
$aMargins = $oPdf->getMargins();
|
||||
$oPdf->write2DBarcode($sUrl, 'QRCODE,H', $aMargins['left'], $oPdf->getPageHeight() - $aMargins['bottom'] - 35, 25, 25, array(), 'N');
|
||||
*/
|
||||
|
||||
if ($bIncludeList)
|
||||
{
|
||||
// Then the lists of objects (one table per finalclass)
|
||||
@@ -1864,39 +1882,64 @@ EOF
|
||||
require_once(APPROOT.'core/simplegraph.class.inc.php');
|
||||
require_once(APPROOT.'core/relationgraph.class.inc.php');
|
||||
require_once(APPROOT.'core/displayablegraph.class.inc.php');
|
||||
$sClass = utils::ReadParam('class', '', false, 'class');
|
||||
$id = utils::ReadParam('id', 0);
|
||||
$sRelation = utils::ReadParam('relation', 'impact');
|
||||
$sRelation = utils::ReadParam('relation', 'impacts');
|
||||
$sDirection = utils::ReadParam('direction', 'down');
|
||||
$iGroupingThreshold = utils::ReadParam('g', 5);
|
||||
$sPositions = utils::ReadParam('positions', null, false, 'raw_data');
|
||||
$aExcluded = utils::ReadParam('excluded', array(), false, 'raw_data');
|
||||
$aExcludedClasses = utils::ReadParam('excluded_classes', array(), false, 'raw_data');
|
||||
$aPositions = null;
|
||||
if ($sPositions != null)
|
||||
{
|
||||
$aPositions = json_decode($sPositions, true);
|
||||
}
|
||||
|
||||
$oObj = MetaModel::GetObject($sClass, $id);
|
||||
// Get the list of source objects
|
||||
$aSources = utils::ReadParam('sources', array(), false, 'raw_data');
|
||||
$aSourceObjects = array();
|
||||
foreach($aSources as $sClass => $aIDs)
|
||||
{
|
||||
$oSearch = new DBObjectSearch($sClass);
|
||||
$oSearch->AddCondition('id', $aIDs, 'IN');
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
while($oObj = $oSet->Fetch())
|
||||
{
|
||||
$aSourceObjects[] = $oObj;
|
||||
}
|
||||
}
|
||||
|
||||
// Get the list of excluded objects
|
||||
$aExcluded = utils::ReadParam('excluded', array(), false, 'raw_data');
|
||||
$aExcludedObjects = array();
|
||||
foreach($aExcluded as $sClass => $aIDs)
|
||||
{
|
||||
$oSearch = new DBObjectSearch($sClass);
|
||||
$oSearch->AddCondition('id', $aIDs, 'IN');
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
while($oObj = $oSet->Fetch())
|
||||
{
|
||||
$aExcludedObjects[] = $oObj;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the graph
|
||||
$iMaxRecursionDepth = MetaModel::GetConfig()->Get('relations_max_depth', 20);
|
||||
$aSourceObjects = array($oObj);
|
||||
if ($sDirection == 'up')
|
||||
{
|
||||
$oRelGraph = MetaModel::GetRelatedObjectsUp($sRelation, $aSourceObjects, $iMaxRecursionDepth);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oRelGraph = MetaModel::GetRelatedObjectsDown($sRelation, $aSourceObjects, $iMaxRecursionDepth);
|
||||
$oRelGraph = MetaModel::GetRelatedObjectsDown($sRelation, $aSourceObjects, $iMaxRecursionDepth, true, $aExcludedObjects);
|
||||
}
|
||||
|
||||
// Remove excluded classes from the graph
|
||||
if (count($aExcluded) > 0)
|
||||
if (count($aExcludedClasses) > 0)
|
||||
{
|
||||
$oIterator = new RelationTypeIterator($oRelGraph, 'Node');
|
||||
foreach($oIterator as $oNode)
|
||||
{
|
||||
$oObj = $oNode->GetProperty('object');
|
||||
if ($oObj && in_array(get_class($oObj), $aExcluded))
|
||||
if ($oObj && in_array(get_class($oObj), $aExcludedClasses))
|
||||
{
|
||||
$oRelGraph->FilterNode($oNode);
|
||||
}
|
||||
@@ -1913,6 +1956,57 @@ EOF
|
||||
$oPage->SetContentType('application/json');
|
||||
break;
|
||||
|
||||
case 'ticket_impact':
|
||||
require_once(APPROOT.'core/simplegraph.class.inc.php');
|
||||
require_once(APPROOT.'core/relationgraph.class.inc.php');
|
||||
require_once(APPROOT.'core/displayablegraph.class.inc.php');
|
||||
$sRelation = utils::ReadParam('relation', 'impacts');
|
||||
$sDirection = utils::ReadParam('direction', 'down');
|
||||
$iGroupingThreshold = utils::ReadParam('g', 5);
|
||||
$sClass = utils::ReadParam('class', '', false, 'class');
|
||||
$sAttCode = utils::ReadParam('attcode', 'functionalcis_list');
|
||||
$sImpactAttCode = utils::ReadParam('impact_attcode', 'impact_code');
|
||||
$sImpactAttCodeValue = utils::ReadParam('impact_attcode_value', 'manual');
|
||||
$iId = (int)utils::ReadParam('id', 0, false, 'integer');
|
||||
|
||||
// Get the list of source objects
|
||||
$oTicket = MetaModel::GetObject($sClass, $iId);
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
$sExtKeyToRemote = $oAttDef->GetExtKeyToRemote();
|
||||
$oExtKeyToRemote = MetaModel::GetAttributeDef($oAttDef->GetLinkedClass(), $sExtKeyToRemote);
|
||||
$sRemoteClass = $oExtKeyToRemote->GetTargetClass();
|
||||
$oSet = $oTicket->Get($sAttCode);
|
||||
$aSourceObjects = array();
|
||||
$aExcludedObjects = array();
|
||||
while($oLnk = $oSet->Fetch())
|
||||
{
|
||||
if ($oLnk->Get($sImpactAttCode) == 'manual')
|
||||
{
|
||||
$aSourceObjects[] = MetaModel::GetObject($sRemoteClass, $oLnk->Get($sExtKeyToRemote));
|
||||
}
|
||||
if ($oLnk->Get($sImpactAttCode) == 'not_impacted')
|
||||
{
|
||||
$aExcludedObjects[] = MetaModel::GetObject($sRemoteClass, $oLnk->Get($sExtKeyToRemote));
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the graph
|
||||
$iMaxRecursionDepth = MetaModel::GetConfig()->Get('relations_max_depth', 20);
|
||||
if ($sDirection == 'up')
|
||||
{
|
||||
$oRelGraph = MetaModel::GetRelatedObjectsUp($sRelation, $aSourceObjects, $iMaxRecursionDepth);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oRelGraph = MetaModel::GetRelatedObjectsDown($sRelation, $aSourceObjects, $iMaxRecursionDepth, $aExcludedObjects);
|
||||
}
|
||||
|
||||
$aResults = $oRelGraph->GetObjectsByClass();
|
||||
$oGraph = DisplayableGraph::FromRelationGraph($oRelGraph, $iGroupingThreshold, ($sDirection == 'down'));
|
||||
$oAppContext = new ApplicationContext();
|
||||
$oGraph->Display($oPage, $aResults, $sRelation, $oAppContext, $aExcludedObjects);
|
||||
break;
|
||||
|
||||
default:
|
||||
$oPage->p("Invalid query.");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user