mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-12 23:14:18 +01:00
Refresh of the "Groups" tab in the impact analysis display, when the whole graph is refreshed.
SVN:trunk[3711]
This commit is contained in:
@@ -1001,14 +1001,27 @@ class DisplayableGraph extends SimpleGraph
|
||||
{
|
||||
$aContextDefs = $this->GetContextDefinitions($sContextKey, false);
|
||||
|
||||
$aData = array('nodes' => array(), 'edges' => array());
|
||||
$aData = array('nodes' => array(), 'edges' => array(), 'groups' => array());
|
||||
$iGroupIdx = 0;
|
||||
$oIterator = new RelationTypeIterator($this, 'Node');
|
||||
foreach($oIterator as $sId => $oNode)
|
||||
{
|
||||
if ($oNode instanceof DisplayableGroupNode)
|
||||
{
|
||||
$aGroups[] = $oNode->GetObjects();
|
||||
// The contents of the "Groups" tab will be rendered
|
||||
// using a separate ajax call, since the content of
|
||||
// the page is made of a mix of HTML / CSS / JS which
|
||||
// cannot be conveyed easily in the JSON structure
|
||||
// So we just pass a list of groups, each being defined by a class and a list of keys
|
||||
// in order to avoid redoing the impact computation which is expensive
|
||||
$aObjects = $oNode->GetObjects();
|
||||
$aKeys = array();
|
||||
foreach($aObjects as $oObj)
|
||||
{
|
||||
$sClass = get_class($oObj);
|
||||
$aKeys[] = $oObj->GetKey();
|
||||
}
|
||||
$aData['groups'][$iGroupIdx] = array('class' => $sClass, 'keys' => $aKeys);
|
||||
$oNode->SetProperty('group_index', $iGroupIdx);
|
||||
$iGroupIdx++;
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ $(function()
|
||||
this.iTextHeight = 12;
|
||||
this.fSliderZoom = 1.0;
|
||||
this.bInUpdateSliderZoom = false;
|
||||
this.bRedrawNeeded = false;
|
||||
|
||||
this.oPaper = Raphael(this.element.get(0), 16*this.element.width(), 16*this.element.height());
|
||||
|
||||
@@ -71,6 +72,17 @@ $(function()
|
||||
|
||||
this._create_toolkit_menu();
|
||||
this._build_context_menus();
|
||||
this.sTabId = null;
|
||||
var jTabPanel = this.element.closest('.ui-tabs-panel');
|
||||
if (jTabPanel.length > 0)
|
||||
{
|
||||
// We are inside a tab, find out which one and hook its activation
|
||||
this.sTabId = jTabPanel.attr('id');
|
||||
var jTabs = this.element.closest('.ui-tabs');
|
||||
jTabs.on( "tabsactivate", function( event, ui ) {
|
||||
me._on_tabs_activate(ui);
|
||||
});
|
||||
}
|
||||
$(window).bind('resized', function() { var that = me; window.setTimeout(function() { that._on_resize(); }, 50); } );
|
||||
this.element.bind('mousewheel', function(event, delta, deltaX, deltaY) {
|
||||
return me._on_mousewheel(event, delta, deltaX, deltaY);
|
||||
@@ -341,9 +353,8 @@ $(function()
|
||||
}
|
||||
return null;
|
||||
},
|
||||
auto_scale: function()
|
||||
adjust_height: function()
|
||||
{
|
||||
var fMaxZoom = 1.5;
|
||||
var maxHeight = this.element.parent().height();
|
||||
// Compute the available height
|
||||
var element = this.element;
|
||||
@@ -355,6 +366,12 @@ $(function()
|
||||
});
|
||||
|
||||
this.element.height(maxHeight - 20);
|
||||
this.oPaper.setSize(this.element.width(), this.element.height());
|
||||
},
|
||||
auto_scale: function()
|
||||
{
|
||||
var fMaxZoom = 1.5;
|
||||
this.adjust_height();
|
||||
|
||||
iMargin = 10;
|
||||
xmin = this.options.xmin - iMargin;
|
||||
@@ -639,10 +656,24 @@ $(function()
|
||||
{
|
||||
this.element.closest('.ui-tabs').tabs({ heightStyle: "fill" });
|
||||
this.auto_scale();
|
||||
this.oPaper.setSize(this.element.width(), this.element.height());
|
||||
this._close_all_tooltips();
|
||||
this.draw();
|
||||
},
|
||||
_on_tabs_activate: function(ui)
|
||||
{
|
||||
if (ui.newPanel.selector == ('#'+this.sTabId))
|
||||
{
|
||||
if (this.bRedrawNeeded)
|
||||
{
|
||||
this._updateBBox();
|
||||
this.auto_scale();
|
||||
this.oPaper.setSize(this.element.width(), this.element.height());
|
||||
this._reset_pan_and_zoom();
|
||||
this.draw();
|
||||
bRedrawNeeded = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
load: function(oData)
|
||||
{
|
||||
var me = this;
|
||||
@@ -657,11 +688,43 @@ $(function()
|
||||
{
|
||||
this.add_edge(oData.edges[k]);
|
||||
}
|
||||
this._updateBBox();
|
||||
this.auto_scale();
|
||||
this.oPaper.setSize(this.element.width(), this.element.height());
|
||||
this._reset_pan_and_zoom();
|
||||
this.draw();
|
||||
if (oData.groups)
|
||||
{
|
||||
this.refresh_groups(oData.groups);
|
||||
}
|
||||
if (this.element.is(':visible'))
|
||||
{
|
||||
this._updateBBox();
|
||||
this.auto_scale();
|
||||
this._reset_pan_and_zoom();
|
||||
this.draw();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.bRedrawNeeded = true;
|
||||
}
|
||||
},
|
||||
refresh_groups: function(aGroups)
|
||||
{
|
||||
if ($('#impacted_groups').length > 0)
|
||||
{
|
||||
|
||||
// The "Groups" tab is present, refresh it
|
||||
if (aGroups.length == 0)
|
||||
{
|
||||
this.element.closest('.ui-tabs').tabs("disable", 2);
|
||||
$('#impacted_groups').html('');
|
||||
}
|
||||
else
|
||||
{
|
||||
this.element.closest('.ui-tabs').tabs("enable", 2);
|
||||
$('#impacted_groups').html('<img src="../images/indicator.gif">');
|
||||
var sUrl = GetAbsoluteUrlAppRoot()+'pages/ajax.render.php';
|
||||
$.post(sUrl, { operation: 'relation_groups', groups: aGroups }, function(data) {
|
||||
$('#impacted_groups').html(data);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
_reset_pan_and_zoom: function()
|
||||
{
|
||||
@@ -688,11 +751,12 @@ $(function()
|
||||
var aContexts = [];
|
||||
$('#'+sId+'_contexts').multiselect('getChecked').each(function() { aContexts[$(this).val()] = me.options.additional_contexts[$(this).val()].oql; });
|
||||
this.element.closest('.ui-tabs').tabs({ heightStyle: "fill" });
|
||||
this.adjust_height();
|
||||
this._close_all_tooltips();
|
||||
this.oPaper.rect(this.xPan, this.yPan, this.element.width(), this.element.height()).attr({fill: '#000', opacity: 0.4, 'stroke-width': 0});
|
||||
this.oPaper.rect(this.xPan + this.element.width()/2 - 100, this.yPan + this.element.height()/2 - 10, 200, 20)
|
||||
.attr({fill: 'url(../setup/orange-progress.gif)', stroke: '#000', 'stroke-width': 1});
|
||||
this.oPaper.text(this.xPan + this.element.width()/2, this.yPan + this.element.height()/2 - 20, this.options.labels.loading);
|
||||
this.oPaper.text(this.xPan + this.element.width()/2, this.yPan + this.element.height()/2 - 20, this.options.labels.loading);
|
||||
|
||||
$('#'+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) {
|
||||
|
||||
51
pages/UI.php
51
pages/UI.php
@@ -244,27 +244,14 @@ function DisplayNavigatorListTab($oP, $aResults, $sRelation, $sDirection, $oObj)
|
||||
$oP->add("</div>");
|
||||
}
|
||||
|
||||
function DisplayNavigatorGroupTab($oP, $aGroups, $sRelation, $oObj)
|
||||
function DisplayNavigatorGroupTab($oP)
|
||||
{
|
||||
if (count($aGroups) > 0)
|
||||
{
|
||||
$oP->SetCurrentTab(Dict::S('UI:RelationGroups'));
|
||||
$oP->add("<div id=\"impacted_groups\" style=\"width:100%;background-color:#fff;padding:10px;\">");
|
||||
$iBlock = 1; // Zero is not a valid blockid
|
||||
foreach($aGroups as $idx => $aObjects)
|
||||
{
|
||||
$sListClass = get_class(current($aObjects));
|
||||
$oSet = CMDBObjectSet::FromArray($sListClass, $aObjects);
|
||||
$oP->add("<h1>".Dict::Format('UI:RelationGroupNumber_N', (1+$idx))."</h1>\n");
|
||||
$oP->add("<div id=\"relation_group_$idx\" class=\"page_header\">\n");
|
||||
$oP->add("<h2>".MetaModel::GetClassIcon($sListClass)." <span class=\"hilite\">".Dict::Format('UI:Search:Count_ObjectsOf_Class_Found', count($aObjects), Metamodel::GetName($sListClass))."</h2>\n");
|
||||
$oP->add("</div>\n");
|
||||
$oBlock = DisplayBlock::FromObjectSet($oSet, 'list');
|
||||
$oBlock->Display($oP, 'group_'.$iBlock++);
|
||||
$oP->p(' '); // Some space ?
|
||||
}
|
||||
$oP->add("</div>");
|
||||
}
|
||||
$oP->SetCurrentTab(Dict::S('UI:RelationGroups'));
|
||||
$oP->add("<div id=\"impacted_groups\" style=\"width:100%;background-color:#fff;padding:10px;\">");
|
||||
/*
|
||||
* Content is rendered asynchronously via pages/ajax.render.php?operation=relation_groups
|
||||
*/
|
||||
$oP->add("</div>");
|
||||
}
|
||||
|
||||
/***********************************************************************************
|
||||
@@ -1468,6 +1455,9 @@ EOF
|
||||
$oObj = MetaModel::GetObject($sClass, $id);
|
||||
$iMaxRecursionDepth = MetaModel::GetConfig()->Get('relations_max_depth', 20);
|
||||
$aSourceObjects = array($oObj);
|
||||
|
||||
$oP->set_title(MetaModel::GetRelationDescription($sRelation).' '.$oObj->GetName());
|
||||
|
||||
if ($sRelation == 'depends on')
|
||||
{
|
||||
$sRelation = 'impacts';
|
||||
@@ -1484,20 +1474,7 @@ EOF
|
||||
|
||||
|
||||
$aResults = $oRelGraph->GetObjectsByClass();
|
||||
$oDisplayGraph = DisplayableGraph::FromRelationGraph($oRelGraph, $iGroupingThreshold, ($sDirection == 'down'));
|
||||
|
||||
$aGroups = array();
|
||||
$iGroupIdx = 0;
|
||||
$oIterator = new RelationTypeIterator($oDisplayGraph, 'Node');
|
||||
foreach($oIterator as $oNode)
|
||||
{
|
||||
if ($oNode instanceof DisplayableGroupNode)
|
||||
{
|
||||
$aGroups[] = $oNode->GetObjects();
|
||||
$oNode->SetProperty('group_index', $iGroupIdx);
|
||||
$iGroupIdx++;
|
||||
}
|
||||
}
|
||||
$oDisplayGraph = DisplayableGraph::FromRelationGraph($oRelGraph, $iGroupingThreshold, ($sDirection == 'down'));
|
||||
|
||||
$oP->AddTabContainer('Navigator');
|
||||
$oP->SetCurrentTabContainer('Navigator');
|
||||
@@ -1526,14 +1503,14 @@ EOF
|
||||
DisplayNavigatorListTab($oP, $aResults, $sRelation, $sDirection, $oObj);
|
||||
$oP->SetCurrentTab(Dict::S('UI:RelationshipGraph'));
|
||||
$oDisplayGraph->Display($oP, $aResults, $sRelation, $oAppContext, array(), $sClassForAttachment, $iIdForAttachment, $sContextKey, array('this' => $oObj));
|
||||
DisplayNavigatorGroupTab($oP, $aGroups, $sRelation, $oObj);
|
||||
DisplayNavigatorGroupTab($oP);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oP->SetCurrentTab(Dict::S('UI:RelationshipGraph'));
|
||||
$oDisplayGraph->Display($oP, $aResults, $sRelation, $oAppContext, array(), $sClassForAttachment, $iIdForAttachment, $sContextKey, array('this' => $oObj));
|
||||
DisplayNavigatorListTab($oP, $aResults, $sRelation, $sDirection, $oObj);
|
||||
DisplayNavigatorGroupTab($oP, $aGroups, $sRelation, $oObj);
|
||||
DisplayNavigatorGroupTab($oP);
|
||||
}
|
||||
|
||||
$oP->SetCurrentTab('');
|
||||
@@ -1622,7 +1599,7 @@ catch(Exception $e)
|
||||
require_once(APPROOT.'/setup/setuppage.class.inc.php');
|
||||
$oP = new SetupPage(Dict::S('UI:PageTitle:FatalError'));
|
||||
$oP->add("<h1>".Dict::S('UI:FatalErrorMessage')."</h1>\n");
|
||||
$oP->error(Dict::Format('UI:Error_Details', $e->getMessage()));
|
||||
$oP->error(Dict::Format('UI:Error_Details', $e->getMessage()));
|
||||
$oP->output();
|
||||
|
||||
if (MetaModel::IsLogEnabledIssue())
|
||||
|
||||
@@ -1992,6 +1992,24 @@ EOF
|
||||
$oPage->SetContentType('application/json');
|
||||
break;
|
||||
|
||||
case 'relation_groups':
|
||||
$aGroups = utils::ReadParam('groups');
|
||||
$iBlock = 1; // Zero is not a valid blockid
|
||||
foreach($aGroups as $idx => $aDefinition)
|
||||
{
|
||||
$sListClass = $aDefinition['class'];
|
||||
$oSearch = new DBObjectSearch($sListClass);
|
||||
$oSearch->AddCondition('id', $aDefinition['keys'], 'IN');
|
||||
$oPage->add("<h1>".Dict::Format('UI:RelationGroupNumber_N', (1+$idx))."</h1>\n");
|
||||
$oPage->add("<div id=\"relation_group_$idx\" class=\"page_header\">\n");
|
||||
$oPage->add("<h2>".MetaModel::GetClassIcon($sListClass)." <span class=\"hilite\">".Dict::Format('UI:Search:Count_ObjectsOf_Class_Found', count($aDefinition['keys']), Metamodel::GetName($sListClass))."</h2>\n");
|
||||
$oPage->add("</div>\n");
|
||||
$oBlock = new DisplayBlock($oSearch, 'list');
|
||||
$oBlock->Display($oPage, 'group_'.$iBlock++);
|
||||
$oPage->p(' '); // Some space ?
|
||||
}
|
||||
break;
|
||||
|
||||
case 'ticket_impact':
|
||||
require_once(APPROOT.'core/simplegraph.class.inc.php');
|
||||
require_once(APPROOT.'core/relationgraph.class.inc.php');
|
||||
|
||||
Reference in New Issue
Block a user