mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-13 07:24:13 +01:00
N°1370 portal : add charts capacity to the ManageBrick (restore 2018-04-10 revisions : r5646)
SVN:trunk[5635]
This commit is contained in:
@@ -103,6 +103,17 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'Brick:Portal:Manage:Name' => 'Manage items',
|
||||
'Brick:Portal:Manage:Table:NoData' => 'No item.',
|
||||
'Brick:Portal:Manage:Table:ItemActions' => 'Actions',
|
||||
'Brick:Portal:Manage:DisplayType:pie-chart' => 'Pie Chart',
|
||||
'Brick:Portal:Manage:DisplayType:bar-chart' => 'Bar Chart',
|
||||
'Brick:Portal:Manage:DisplayType:default' => 'List',
|
||||
'Brick:Portal:Manage:Others' => 'Others',
|
||||
'Brick:Portal:Manage:All' => 'All',
|
||||
'Brick:Portal:Manage:Group' => 'Group',
|
||||
'Brick:Portal:Manage:fct:count' => 'Total',
|
||||
'Brick:Portal:Manage:fct:sum' => 'Sum',
|
||||
'Brick:Portal:Manage:fct:avg' => 'Average',
|
||||
'Brick:Portal:Manage:fct:min' => 'Min',
|
||||
'Brick:Portal:Manage:fct:max' => 'Max',
|
||||
));
|
||||
|
||||
// ObjectBrick brick
|
||||
|
||||
@@ -103,6 +103,17 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'Brick:Portal:Manage:Name' => 'Gestion d\'éléments',
|
||||
'Brick:Portal:Manage:Table:NoData' => 'Aucun élément',
|
||||
'Brick:Portal:Manage:Table:ItemActions' => 'Actions',
|
||||
'Brick:Portal:Manage:DisplayType:pie-chart' => 'Secteur',
|
||||
'Brick:Portal:Manage:DisplayType:bar-chart' => 'Histogramme',
|
||||
'Brick:Portal:Manage:DisplayType:default' => 'Liste',
|
||||
'Brick:Portal:Manage:Others' => 'Autres',
|
||||
'Brick:Portal:Manage:All' => 'Total',
|
||||
'Brick:Portal:Manage:Group' => 'Groupe',
|
||||
'Brick:Portal:Manage:fct:count' => 'Total',
|
||||
'Brick:Portal:Manage:fct:sum' => 'Somme',
|
||||
'Brick:Portal:Manage:fct:avg' => 'Moyenne',
|
||||
'Brick:Portal:Manage:fct:min' => 'Min',
|
||||
'Brick:Portal:Manage:fct:max' => 'Max',
|
||||
));
|
||||
|
||||
// ObjectBrick brick
|
||||
|
||||
@@ -13,11 +13,12 @@ SetupWebPage::AddModule(
|
||||
'visible' => true,
|
||||
// Components
|
||||
'datamodel' => array(
|
||||
'portal/src/entities/abstractbrick.class.inc.php',
|
||||
'portal/src/entities/portalbrick.class.inc.php',
|
||||
'portal/src/apis/extensions/d3portaluiextension.class.inc.php',
|
||||
'portal/src/controllers/abstractcontroller.class.inc.php',
|
||||
'portal/src/controllers/brickcontroller.class.inc.php',
|
||||
'portal/src/routers/abstractrouter.class.inc.php',
|
||||
'portal/src/entities/abstractbrick.class.inc.php',
|
||||
'portal/src/entities/portalbrick.class.inc.php',
|
||||
'portal/src/routers/abstractrouter.class.inc.php',
|
||||
),
|
||||
'webservice' => array(
|
||||
//'webservices.itop-portal-base.php',
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
// Copyright (c) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
//
|
||||
namespace Combodo\iTop\Portal\API\Extension;
|
||||
|
||||
use AbstractPortalUIExtension;
|
||||
use Silex\Application;
|
||||
use utils;
|
||||
|
||||
class D3PortalUIExtension extends AbstractPortalUIExtension
|
||||
{
|
||||
public function GetCSSFiles(Application $oApp)
|
||||
{
|
||||
$aCSSFiles = array(
|
||||
utils::GetAbsoluteUrlAppRoot().'css/c3.min.css?v='.ITOP_VERSION,
|
||||
);
|
||||
return $aCSSFiles;
|
||||
}
|
||||
|
||||
public function GetJSFiles(Application $oApp)
|
||||
{
|
||||
$aJSFiles = array(
|
||||
utils::GetAbsoluteUrlAppRoot().'js/d3.min.js?v='.ITOP_VERSION,
|
||||
utils::GetAbsoluteUrlAppRoot().'js/c3.min.js?v='.ITOP_VERSION,
|
||||
utils::GetCurrentModuleUrl().'/portal/web/js/export.js?v='.ITOP_VERSION,
|
||||
);
|
||||
return $aJSFiles;
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,7 +4,7 @@
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
@@ -16,53 +16,97 @@
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
//
|
||||
|
||||
namespace Combodo\iTop\Portal\Brick;
|
||||
|
||||
use DOMFormatException;
|
||||
use DBSearch;
|
||||
use MetaModel;
|
||||
use Combodo\iTop\DesignElement;
|
||||
use Combodo\iTop\Portal\Brick\PortalBrick;
|
||||
use DBSearch;
|
||||
use DOMFormatException;
|
||||
use MetaModel;
|
||||
|
||||
define('MANAGE_BRICK_LAYOUT_PATH', 'itop-portal-base/portal/src/views/bricks/manage/');
|
||||
|
||||
/**
|
||||
* Description of ManageBrick
|
||||
*
|
||||
* @author Guillaume Lajarige
|
||||
*/
|
||||
class ManageBrick extends PortalBrick
|
||||
{
|
||||
const ENUM_ACTION_VIEW = 'view';
|
||||
const ENUM_ACTION_EDIT = 'edit';
|
||||
const ENUM_ACTION_VIEW = 'view';
|
||||
const ENUM_ACTION_EDIT = 'edit';
|
||||
|
||||
const DEFAULT_DECORATION_CLASS_HOME = 'fa fa-pencil-square';
|
||||
const DEFAULT_DECORATION_CLASS_NAVIGATION_MENU = 'fa fa-pencil-square fa-2x';
|
||||
const DEFAULT_PAGE_TEMPLATE_PATH = 'itop-portal-base/portal/src/views/bricks/manage/layout.html.twig';
|
||||
const DEFAULT_PAGE_TEMPLATE_PATH = 'itop-portal-base/portal/src/views/bricks/manage/layout-table.html.twig';
|
||||
const CHART_PAGE_TEMPLATE_PATH = 'itop-portal-base/portal/src/views/bricks/manage/layout-chart.html.twig';
|
||||
const DEFAULT_OQL = '';
|
||||
const DEFAULT_OPENING_MODE = self::ENUM_ACTION_EDIT;
|
||||
const DEFAULT_DATA_LOADING = self::ENUM_DATA_LOADING_LAZY;
|
||||
const DEFAULT_LIST_LENGTH = 20;
|
||||
const DEFAULT_ZLIST_FIELDS = 'list';
|
||||
const DEFAULT_SHOW_TAB_COUNTS = false;
|
||||
const DEFAULT_SHOW_TAB_COUNTS = false;
|
||||
|
||||
const DEFAULT_TILE_TEMPLATE_PATH = 'itop-portal-base/portal/src/views/bricks/manage/tile-default.html.twig';
|
||||
const DEFAULT_TILE_CONTROLLER_ACTION = 'Combodo\\iTop\\Portal\\Controller\\ManageBrickController::TileAction';
|
||||
|
||||
static $sRouteName = 'p_manage_brick';
|
||||
protected $sOql;
|
||||
protected $sOpeningMode;
|
||||
protected $aGrouping;
|
||||
protected $aFields;
|
||||
protected $aExportFields;
|
||||
protected $bShowTabCounts;
|
||||
protected $sDisplayType;
|
||||
protected $iGroupLimit;
|
||||
protected $bGroupShowOthers;
|
||||
|
||||
protected $aPresentationData = array(
|
||||
'badge' => array(
|
||||
'decorationCssClass' => 'fa fa-id-card-o fa-2x',
|
||||
'tileTemplate' => 'itop-portal-base/portal/src/views/bricks/manage/tile-badge.html.twig',
|
||||
'layoutTemplate' => 'itop-portal-base/portal/src/views/bricks/manage/layout-table.html.twig',
|
||||
'layoutDisplayType' => 'default',
|
||||
'need_details' => true,
|
||||
),
|
||||
'top-list' => array(
|
||||
'decorationCssClass' => 'fa fa-signal fa-rotate-270 fa-2x',
|
||||
'tileTemplate' => 'itop-portal-base/portal/src/views/bricks/manage/tile-top-list.html.twig',
|
||||
'layoutTemplate' => 'itop-portal-base/portal/src/views/bricks/manage/layout-table.html.twig',
|
||||
'layoutDisplayType' => 'default',
|
||||
'need_details' => true,
|
||||
),
|
||||
'pie-chart' => array(
|
||||
'decorationCssClass' => 'fa fa-pie-chart fa-2x',
|
||||
'tileTemplate' => 'itop-portal-base/portal/src/views/bricks/manage/tile-chart.html.twig',
|
||||
'layoutTemplate' => 'itop-portal-base/portal/src/views/bricks/manage/layout-chart.html.twig',
|
||||
'layoutDisplayType' => 'pie-chart',
|
||||
'need_details' => false,
|
||||
),
|
||||
'bar-chart' => array(
|
||||
'decorationCssClass' => 'fa fa-bar-chart fa-2x',
|
||||
'tileTemplate' => 'itop-portal-base/portal/src/views/bricks/manage/tile-chart.html.twig',
|
||||
'layoutTemplate' => 'itop-portal-base/portal/src/views/bricks/manage/layout-chart.html.twig',
|
||||
'layoutDisplayType' => 'bar-chart',
|
||||
'need_details' => false,
|
||||
),
|
||||
'default' => array(
|
||||
'decorationCssClass' => 'fa fa-pencil-square fa-2x',
|
||||
'tileTemplate' => self::DEFAULT_TILE_TEMPLATE_PATH,
|
||||
'layoutTemplate' => 'itop-portal-base/portal/src/views/bricks/manage/layout-table.html.twig',
|
||||
'layoutDisplayType' => 'default',
|
||||
'need_details' => true,
|
||||
),
|
||||
);
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->sOql = static::DEFAULT_OQL;
|
||||
$this->sOpeningMode = static::DEFAULT_OPENING_MODE;
|
||||
$this->sOpeningMode = static::DEFAULT_OPENING_MODE;
|
||||
$this->aGrouping = array();
|
||||
$this->aFields = array();
|
||||
$this->aExportFields = array();
|
||||
$this->bShowTabCounts = static::DEFAULT_SHOW_TAB_COUNTS;
|
||||
|
||||
// This is hardcoded for now, we might allow area grouping on another attribute in the futur
|
||||
// This is hardcoded for now, we might allow area grouping on another attribute in the future
|
||||
$this->AddGrouping('areas', array('attribute' => 'finalclass'));
|
||||
}
|
||||
|
||||
@@ -76,15 +120,15 @@ class ManageBrick extends PortalBrick
|
||||
return $this->sOql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the brick's objects opening mode (edit or view)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function GetOpeningMode()
|
||||
{
|
||||
return $this->sOpeningMode;
|
||||
}
|
||||
/**
|
||||
* Returns the brick's objects opening mode (edit or view)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function GetOpeningMode()
|
||||
{
|
||||
return $this->sOpeningMode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the brick grouping
|
||||
@@ -106,39 +150,114 @@ class ManageBrick extends PortalBrick
|
||||
return $this->aFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the brick should display objects count on tabs
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
/**
|
||||
* Returns the brick fields to export
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function GetExportFields()
|
||||
{
|
||||
return $this->aExportFields;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the brick should display objects count on tabs
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function GetShowTabCounts()
|
||||
{
|
||||
return $this->bShowTabCounts;
|
||||
}
|
||||
{
|
||||
return $this->bShowTabCounts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function GetDisplayType()
|
||||
{
|
||||
return $this->sDisplayType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sDisplayType
|
||||
*/
|
||||
public function SetDisplayType($sDisplayType)
|
||||
{
|
||||
$this->sDisplayType = $sDisplayType;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sDisplayType
|
||||
*
|
||||
* @return string[] parameters for specified type, default parameters if type is invalid
|
||||
*/
|
||||
public function GetPresentationDataForDisplayType($sDisplayType)
|
||||
{
|
||||
if (isset($this->aPresentationData[$sDisplayType]))
|
||||
{
|
||||
return $this->aPresentationData[$sDisplayType];
|
||||
}
|
||||
|
||||
return $this->aPresentationData['default'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function GetGroupLimit()
|
||||
{
|
||||
return $this->iGroupLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function ShowGroupOthers()
|
||||
{
|
||||
return $this->bGroupShowOthers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function ListLayoutDisplayTypes()
|
||||
{
|
||||
$aLayoutDisplayTypes = array();
|
||||
foreach ($this->aPresentationData as $aPresentationDatum)
|
||||
{
|
||||
$aLayoutDisplayTypes[$aPresentationDatum['layoutDisplayType']] = true;
|
||||
}
|
||||
|
||||
return array_keys($aLayoutDisplayTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the oql of the brick
|
||||
*
|
||||
* @param string $sOql
|
||||
* @return \Combodo\iTop\Portal\Brick\ManageBrick
|
||||
*
|
||||
* @return ManageBrick
|
||||
*/
|
||||
public function SetOql($sOql)
|
||||
{
|
||||
$this->sOql = $sOql;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the brick's objects opening mode
|
||||
*
|
||||
* @param string $sOpeningMode
|
||||
* @return \Combodo\iTop\Portal\Brick\ManageBrick
|
||||
*/
|
||||
public function SetOpeningMode($sOpeningMode)
|
||||
{
|
||||
$this->sOpeningMode = $sOpeningMode;
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* Sets the brick's objects opening mode
|
||||
*
|
||||
* @param string $sOpeningMode
|
||||
*
|
||||
* @return ManageBrick
|
||||
*/
|
||||
public function SetOpeningMode($sOpeningMode)
|
||||
{
|
||||
$this->sOpeningMode = $sOpeningMode;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the grouping of the brick
|
||||
@@ -148,6 +267,7 @@ class ManageBrick extends PortalBrick
|
||||
public function SetGrouping($aGrouping)
|
||||
{
|
||||
$this->aGrouping = $aGrouping;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -159,20 +279,23 @@ class ManageBrick extends PortalBrick
|
||||
public function SetFields($aFields)
|
||||
{
|
||||
$this->aFields = $aFields;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets if the brick should display objects count on tab
|
||||
*
|
||||
* @param bool $bShowTabCounts
|
||||
* @return \Combodo\iTop\Portal\Brick\ManageBrick
|
||||
*/
|
||||
public function SetShowTabCounts($bShowTabCounts)
|
||||
{
|
||||
$this->bShowTabCounts = $bShowTabCounts;
|
||||
return $this;
|
||||
}
|
||||
/**
|
||||
* Sets if the brick should display objects count on tab
|
||||
*
|
||||
* @param bool $bShowTabCounts
|
||||
*
|
||||
* @return ManageBrick
|
||||
*/
|
||||
public function SetShowTabCounts($bShowTabCounts)
|
||||
{
|
||||
$this->bShowTabCounts = $bShowTabCounts;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a grouping.
|
||||
@@ -181,7 +304,8 @@ class ManageBrick extends PortalBrick
|
||||
*
|
||||
* @param string $sName (Must be "tabs" or -Not implemented yet, implicit grouping on y axis-)
|
||||
* @param array $aGrouping
|
||||
* @return \Combodo\iTop\Portal\Brick\ManageBrick
|
||||
*
|
||||
* @return ManageBrick
|
||||
*/
|
||||
public function AddGrouping($sName, $aGrouping)
|
||||
{
|
||||
@@ -190,8 +314,7 @@ class ManageBrick extends PortalBrick
|
||||
// Sorting
|
||||
if (!$this->IsGroupingByDistinctValues($sName))
|
||||
{
|
||||
usort($this->aGrouping[$sName]['groups'], function($a, $b)
|
||||
{
|
||||
usort($this->aGrouping[$sName]['groups'], function ($a, $b) {
|
||||
return $a['rank'] > $b['rank'];
|
||||
});
|
||||
}
|
||||
@@ -203,7 +326,8 @@ class ManageBrick extends PortalBrick
|
||||
* Removes a grouping by its name
|
||||
*
|
||||
* @param string $sName
|
||||
* @return \Combodo\iTop\Portal\Brick\ManageBrick
|
||||
*
|
||||
* @return ManageBrick
|
||||
*/
|
||||
public function RemoveGrouping($sName)
|
||||
{
|
||||
@@ -211,6 +335,7 @@ class ManageBrick extends PortalBrick
|
||||
{
|
||||
unset($this->aGrouping[$sName]);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -218,7 +343,8 @@ class ManageBrick extends PortalBrick
|
||||
* Adds a field to display from its attribute_code.
|
||||
*
|
||||
* @param string $sAttCode
|
||||
* @return \Combodo\iTop\Portal\Brick\ManageBrick
|
||||
*
|
||||
* @return ManageBrick
|
||||
*/
|
||||
public function AddField($sAttCode)
|
||||
{
|
||||
@@ -234,7 +360,8 @@ class ManageBrick extends PortalBrick
|
||||
* Removes a field
|
||||
*
|
||||
* @param string $sAttCode
|
||||
* @return \Combodo\iTop\Portal\Brick\ManageBrick
|
||||
*
|
||||
* @return ManageBrick
|
||||
*/
|
||||
public function RemoveField($sAttCode)
|
||||
{
|
||||
@@ -242,9 +369,31 @@ class ManageBrick extends PortalBrick
|
||||
{
|
||||
unset($this->aFields[$sAttCode]);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function AddExportField($sAttCode)
|
||||
{
|
||||
if (!in_array($sAttCode, $this->aExportFields))
|
||||
{
|
||||
$this->aExportFields[] = $sAttCode;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function RemoveExportField($sAttCode)
|
||||
{
|
||||
if (isset($this->aExportFields[$sAttCode]))
|
||||
{
|
||||
unset($this->aExportFields[$sAttCode]);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns if the brick has grouping tabs or not.
|
||||
*
|
||||
@@ -290,6 +439,7 @@ class ManageBrick extends PortalBrick
|
||||
* This is supposed to be called by the IsGroupingTabsByDistinctValues / IsGroupingAreasByDistinctValues function.
|
||||
*
|
||||
* @param string $sGroupingName
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function IsGroupingByDistinctValues($sGroupingName)
|
||||
@@ -299,7 +449,8 @@ class ManageBrick extends PortalBrick
|
||||
|
||||
/**
|
||||
* Returns true is the groupings tabs properties exists and is of the form attribute => attribute_code.
|
||||
* This is mostly used to know if the tabs are grouped by attribute distinct values or by meta-groups (eg : status in ('accepted', 'opened')).
|
||||
* This is mostly used to know if the tabs are grouped by attribute distinct values or by meta-groups (eg : status
|
||||
* in ('accepted', 'opened')).
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
@@ -310,7 +461,8 @@ class ManageBrick extends PortalBrick
|
||||
|
||||
/**
|
||||
* Returns true is the groupings areas properties exists and is of the form attribute => attribute_code.
|
||||
* This is mostly used to know if the areas are grouped by attribute distinct values or by meta-groups (eg : finalclass in ('Server', 'Router')).
|
||||
* This is mostly used to know if the areas are grouped by attribute distinct values or by meta-groups (eg :
|
||||
* finalclass in ('Server', 'Router')).
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
@@ -324,11 +476,18 @@ class ManageBrick extends PortalBrick
|
||||
* This is used to set all the brick attributes at once.
|
||||
*
|
||||
* @param \Combodo\iTop\DesignElement $oMDElement
|
||||
*
|
||||
* @return ManageBrick
|
||||
* @throws DOMFormatException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public function LoadFromXml(DesignElement $oMDElement)
|
||||
{
|
||||
parent::LoadFromXml($oMDElement);
|
||||
$this->sDisplayType = 'default';
|
||||
$this->iGroupLimit = 0;
|
||||
$this->bGroupShowOthers = true;
|
||||
$bUseListFieldsForExport = false;
|
||||
|
||||
// Checking specific elements
|
||||
foreach ($oMDElement->GetNodes('./*') as $oBrickSubNode)
|
||||
@@ -339,53 +498,90 @@ class ManageBrick extends PortalBrick
|
||||
$sClass = $oBrickSubNode->GetText();
|
||||
if ($sClass === '')
|
||||
{
|
||||
throw new DOMFormatException('ManageBrick : class tag is empty. Must contain Classname', null, null, $oBrickSubNode);
|
||||
throw new DOMFormatException('ManageBrick : class tag is empty. Must contain Classname', null,
|
||||
null, $oBrickSubNode);
|
||||
}
|
||||
|
||||
$this->SetOql('SELECT ' . $sClass);
|
||||
$this->SetOql('SELECT '.$sClass);
|
||||
break;
|
||||
|
||||
case 'oql':
|
||||
$sOql = $oBrickSubNode->GetText();
|
||||
if ($sOql === '')
|
||||
{
|
||||
throw new DOMFormatException('ManageBrick : oql tag is empty. Must contain OQL statement', null, null, $oBrickSubNode);
|
||||
throw new DOMFormatException('ManageBrick : oql tag is empty. Must contain OQL statement', null,
|
||||
null, $oBrickSubNode);
|
||||
}
|
||||
|
||||
$this->SetOql($sOql);
|
||||
break;
|
||||
|
||||
case 'opening_mode':
|
||||
$sOpeningMode = $oBrickSubNode->GetText(static::DEFAULT_OPENING_MODE);
|
||||
if (!in_array($sOpeningMode, array(static::ENUM_ACTION_VIEW, static::ENUM_ACTION_EDIT)))
|
||||
{
|
||||
throw new DOMFormatException('ManageBrick : opening_mode tag value must be edit|view ("' . $sOpeningMode . '" given)', null, null, $oBrickSubNode);
|
||||
}
|
||||
case 'opening_mode':
|
||||
$sOpeningMode = $oBrickSubNode->GetText(static::DEFAULT_OPENING_MODE);
|
||||
if (!in_array($sOpeningMode, array(static::ENUM_ACTION_VIEW, static::ENUM_ACTION_EDIT)))
|
||||
{
|
||||
throw new DOMFormatException('ManageBrick : opening_mode tag value must be edit|view ("'.$sOpeningMode.'" given)',
|
||||
null, null, $oBrickSubNode);
|
||||
}
|
||||
|
||||
$this->SetOpeningMode($sOpeningMode);
|
||||
break;
|
||||
$this->SetOpeningMode($sOpeningMode);
|
||||
break;
|
||||
|
||||
case 'display_type':
|
||||
$this->sDisplayType = $oBrickSubNode->GetText();
|
||||
$aDisplayParameterForType = $this->GetPresentationDataForDisplayType($this->sDisplayType);
|
||||
$this->SetTileTemplatePath($aDisplayParameterForType['tileTemplate']);
|
||||
$this->SetPageTemplatePath($aDisplayParameterForType['layoutTemplate']);
|
||||
break;
|
||||
|
||||
case 'fields':
|
||||
foreach ($oBrickSubNode->GetNodes('./field') as $oFieldNode)
|
||||
{
|
||||
if (!$oFieldNode->hasAttribute('id'))
|
||||
{
|
||||
throw new DOMFormatException('ManageBrick : Field must have a unique ID attribute', null, null, $oFieldNode);
|
||||
throw new DOMFormatException('ManageBrick : Field must have a unique ID attribute', null,
|
||||
null, $oFieldNode);
|
||||
}
|
||||
$this->AddField($oFieldNode->getAttribute('id'));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'export':
|
||||
foreach ($oBrickSubNode->GetNodes('./*') as $oExportNode)
|
||||
{
|
||||
switch ($oExportNode->nodeName)
|
||||
{
|
||||
case 'fields':
|
||||
foreach ($oExportNode->GetNodes('./field') as $oFieldNode)
|
||||
{
|
||||
if (!$oFieldNode->hasAttribute('id'))
|
||||
{
|
||||
throw new DOMFormatException('ManageBrick : Field must have a unique ID attribute',
|
||||
null,
|
||||
null, $oFieldNode);
|
||||
}
|
||||
$this->AddExportField($oFieldNode->getAttribute('id'));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'export_default_fields':
|
||||
$bUseListFieldsForExport = (strtolower($oExportNode->GetText()) === 'true' ? true : false);
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case 'grouping':
|
||||
// Tabs grouping
|
||||
foreach ($oBrickSubNode->GetNodes('./tabs/*') as $oGroupingNode)
|
||||
{
|
||||
switch ($oGroupingNode->nodeName)
|
||||
{
|
||||
case 'show_tab_counts';
|
||||
$bShowTabCounts = ( $oGroupingNode->GetText(static::DEFAULT_SHOW_TAB_COUNTS) === 'true' ) ? true : false;
|
||||
$this->SetShowTabCounts($bShowTabCounts);
|
||||
break;
|
||||
case 'show_tab_counts';
|
||||
$bShowTabCounts = ($oGroupingNode->GetText(static::DEFAULT_SHOW_TAB_COUNTS) === 'true') ? true : false;
|
||||
$this->SetShowTabCounts($bShowTabCounts);
|
||||
break;
|
||||
case 'attribute':
|
||||
$sAttribute = $oGroupingNode->GetText();
|
||||
if ($sAttribute !== '')
|
||||
@@ -393,13 +589,24 @@ class ManageBrick extends PortalBrick
|
||||
$this->AddGrouping('tabs', array('attribute' => $sAttribute));
|
||||
}
|
||||
break;
|
||||
case 'limit':
|
||||
$iLimit = $oGroupingNode->GetText();
|
||||
if (is_numeric($iLimit))
|
||||
{
|
||||
$this->iGroupLimit = $iLimit;
|
||||
}
|
||||
break;
|
||||
case 'show_others':
|
||||
$this->bGroupShowOthers = ($oGroupingNode->GetText() === 'true') ? true : false;
|
||||
break;
|
||||
case 'groups':
|
||||
$aGroups = array();
|
||||
foreach ($oGroupingNode->GetNodes('./group') as $oGroupNode)
|
||||
{
|
||||
if (!$oGroupNode->hasAttribute('id'))
|
||||
{
|
||||
throw new DOMFormatException('ManageBrick : Group must have a unique ID attribute', null, null, $oGroupNode);
|
||||
throw new DOMFormatException('ManageBrick : Group must have a unique ID attribute',
|
||||
null, null, $oGroupNode);
|
||||
}
|
||||
$sGroupId = $oGroupNode->getAttribute('id');
|
||||
|
||||
@@ -410,7 +617,7 @@ class ManageBrick extends PortalBrick
|
||||
switch ($oGroupProperty->nodeName)
|
||||
{
|
||||
case 'rank':
|
||||
$aGroup[$oGroupProperty->nodeName] = (int) $oGroupProperty->GetText(0);
|
||||
$aGroup[$oGroupProperty->nodeName] = (int)$oGroupProperty->GetText(0);
|
||||
break;
|
||||
case 'title':
|
||||
case 'condition':
|
||||
@@ -422,11 +629,13 @@ class ManageBrick extends PortalBrick
|
||||
// Checking constitancy
|
||||
if (!isset($aGroup['title']) || $aGroup['title'] === '')
|
||||
{
|
||||
throw new DOMFormatException('ManageBrick : Group must have a title tag and it must not be empty', null, null, $oGroupNode);
|
||||
throw new DOMFormatException('ManageBrick : Group must have a title tag and it must not be empty',
|
||||
null, null, $oGroupNode);
|
||||
}
|
||||
if (!isset($aGroup['condition']) || $aGroup['condition'] === '')
|
||||
{
|
||||
throw new DOMFormatException('ManageBrick : Group must have a condition tag and it must not be empty', null, null, $oGroupNode);
|
||||
throw new DOMFormatException('ManageBrick : Group must have a condition tag and it must not be empty',
|
||||
null, null, $oGroupNode);
|
||||
}
|
||||
$aGroups[] = $aGroup;
|
||||
}
|
||||
@@ -448,11 +657,42 @@ class ManageBrick extends PortalBrick
|
||||
if (empty($this->aFields))
|
||||
{
|
||||
$sClass = DBSearch::FromOQL($this->GetOql());
|
||||
$aFields = MetaModel::FlattenZList(MetaModel::GetZListItems($sClass->GetClass(), static::DEFAULT_ZLIST_FIELDS));
|
||||
$aFields = MetaModel::FlattenZList(MetaModel::GetZListItems($sClass->GetClass(),
|
||||
static::DEFAULT_ZLIST_FIELDS));
|
||||
$this->SetFields($aFields);
|
||||
}
|
||||
|
||||
// Default Export Fields
|
||||
if ($bUseListFieldsForExport)
|
||||
{
|
||||
foreach ($this->GetFields() as $sAttCode)
|
||||
{
|
||||
$this->AddExportField($sAttCode);
|
||||
}
|
||||
}
|
||||
|
||||
// Checking the navigation icon
|
||||
$sDecorationClassNavigationMenu = $this->GetDecorationClassNavigationMenu();
|
||||
if (empty($sDecorationClassNavigationMenu) && isset($this->aPresentationData[$this->sDisplayType]))
|
||||
{
|
||||
$sDecorationClassNavigationMenu = $this->aPresentationData[$this->sDisplayType]['decorationCssClass'];
|
||||
if (!empty($sDecorationClassNavigationMenu))
|
||||
{
|
||||
$this->SetDecorationClassNavigationMenu($sDecorationClassNavigationMenu);
|
||||
}
|
||||
}
|
||||
|
||||
$sTitle = $this->GetTitleHome();
|
||||
if (empty($sTitle))
|
||||
{
|
||||
$sOql = $this->GetOql();
|
||||
$oSeach = DBSearch::FromOQL($sOql);
|
||||
$sClassName = MetaModel::GetName($oSeach->GetClass());
|
||||
$this->SetTitleHome($sClassName);
|
||||
$this->SetTitleNavigationMenu($sClassName);
|
||||
$this->SetTitle($sClassName);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
// Copyright (C) 2010-2017 Combodo SARL
|
||||
// Copyright (C) 2010-2018 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
@@ -19,17 +19,23 @@
|
||||
|
||||
namespace Combodo\iTop\Portal\Router;
|
||||
|
||||
use Silex\Application;
|
||||
|
||||
class ManageBrickRouter extends AbstractRouter
|
||||
{
|
||||
static $aRoutes = array(
|
||||
array('pattern' => '/manage/{sBrickId}/{sGroupingTab}',
|
||||
array(
|
||||
'pattern' => '/manage/{sBrickId}/{sDisplayType}/{sGroupingTab}',
|
||||
'callback' => 'Combodo\\iTop\\Portal\\Controller\\ManageBrickController::DisplayAction',
|
||||
'bind' => 'p_manage_brick',
|
||||
'values' => array('sGroupingTab' => null)
|
||||
'asserts' => array(
|
||||
'sDisplayType' => 'badge|pie-chart|bar-chart|top-list|default'
|
||||
),
|
||||
'values' => array(
|
||||
'sDisplayType' => null, // will be set using brick's XML config
|
||||
'sGroupingTab' => null
|
||||
)
|
||||
),
|
||||
array('pattern' => '/manage/{sBrickId}/{sGroupingTab}/{sGroupingArea}/page/{iPageNumber}/show/{iListLength}',
|
||||
array(
|
||||
'pattern' => '/manage/{sBrickId}/{sGroupingTab}/{sGroupingArea}/page/{iPageNumber}/show/{iListLength}',
|
||||
'callback' => 'Combodo\\iTop\\Portal\\Controller\\ManageBrickController::DisplayAction',
|
||||
'bind' => 'p_manage_brick_lazy',
|
||||
'asserts' => array(
|
||||
@@ -41,7 +47,14 @@ class ManageBrickRouter extends AbstractRouter
|
||||
'iPageNumber' => '1',
|
||||
'iListLength' => '20'
|
||||
)
|
||||
)
|
||||
),
|
||||
array(
|
||||
'pattern' => '/manage/export/excel/start/{sBrickId}/{sGroupingTab}/{sGroupingArea}',
|
||||
'callback' => 'Combodo\\iTop\\Portal\\Controller\\ManageBrickController::ExcelExportStartAction',
|
||||
'bind' => 'p_manage_brick_excel_export_start',
|
||||
'asserts' => array(),
|
||||
'values' => array(),
|
||||
),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
{# itop-portal-base/portal/src/views/bricks/manage/layout-chart.html.twig #}
|
||||
{# Manage brick base layout #}
|
||||
{% extends 'itop-portal-base/portal/src/views/bricks/manage/layout.html.twig' %}
|
||||
|
||||
{% block pPageBodyClass %}{{ parent() }} page_manage_brick{% endblock %}
|
||||
|
||||
|
||||
{% block pMainContentHolder %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
{% include 'itop-portal-base/portal/src/views/bricks/manage/mode-' ~ sDisplayType ~ '.html.twig' with {'oBrick': oBrick, 'aColumns': aColumns, 'aNames': aNames, 'aUrls': aUrls, 'aDisplayValues': aDisplayValues} %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -0,0 +1,339 @@
|
||||
{# itop-portal-base/portal/src/views/bricks/manage/layout-table.html.twig #}
|
||||
{# Manage brick base layout #}
|
||||
{% extends 'itop-portal-base/portal/src/views/bricks/manage/layout.html.twig' %}
|
||||
|
||||
{% block pPageBodyClass %}{{ parent() }} page_manage_brick{% endblock %}
|
||||
|
||||
{% block pMainContentHolder %}
|
||||
{% if aGroupingTabsValues|length > 1 %}
|
||||
<ul class="nav nav-pills">
|
||||
{% for aGroupingTab in aGroupingTabsValues %}
|
||||
<li{% if sGroupingTab is defined and sGroupingTab == aGroupingTab.value %} class="active"{% endif %}>
|
||||
<a href="{{ app.url_generator.generate('p_manage_brick', {'sBrickId': sBrickId, 'sDisplayType': 'default', 'sGroupingTab': aGroupingTab.value}) }}"
|
||||
id="btn_tab_for_{{ aGroupingTab.value }}">
|
||||
{{ aGroupingTab.label|raw }}
|
||||
{% if oBrick.GetShowTabCounts() %}
|
||||
<span class="badge">{{ aGroupingTab.count|raw }}</span>
|
||||
{% endif %}
|
||||
</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{% endif %}
|
||||
{% set iTableCount = 0 %}
|
||||
{% if aGroupingAreasData|length > 0 %}
|
||||
{% for aAreaData in aGroupingAreasData %}
|
||||
{% if aAreaData.iItemsCount > 0 %}
|
||||
{% set iTableCount = iTableCount + 1 %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading clearfix">
|
||||
<h3 class="panel-title" style="float: left;">{{ aAreaData.sTitle }}</h3>
|
||||
{% if bCanExport %}
|
||||
<a href="{{ app.url_generator.generate('p_manage_brick_excel_export_start', {'sBrickId': sBrickId, 'sGroupingTab': sGroupingTab, 'sGroupingArea': aAreaData.sId})|raw }}"
|
||||
id="btn_export_excel_for_{{ aAreaData.sId }}"
|
||||
data-toggle="modal" data-target="#modal-for-all">
|
||||
<span class="fa fa-download fa-lg" style="float: right;"
|
||||
data-toggle="tooltip" data-delay="300" data-placement="left"
|
||||
title="{{ 'ExcelExporter:ExportMenu'|dict_s }}"></span>
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<table id="table-{{ aAreaData.sId }}" class="table table-striped table-bordered responsive"
|
||||
width="100%"></table>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if iTableCount == 0 %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<h3 class="text-center">{{ 'Brick:Portal:Manage:Table:NoData'|dict_s }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block pPageLiveScripts %}
|
||||
{{ parent() }}
|
||||
|
||||
<script type="text/javascript">
|
||||
var sDataLoading = '{{ sDataLoading }}';
|
||||
// Used for ajax throttling
|
||||
var iSearchThrottle = 300;
|
||||
var oKeyTimeout;
|
||||
var aKeyTimeoutFilteredKeys = [16, 17, 18, 19, 27, 33, 34, 35, 36, 37, 38, 39, 40]; // Shift, Ctrl, Alt, Pause, Esc, Page Up/Down, Home, End, Left/Up/Right/Down arrows
|
||||
|
||||
var columnsProperties = {
|
||||
{% for aAreaData in aGroupingAreasData %}
|
||||
'{{ aAreaData.sId }}': {{ aAreaData.aColumnsDefinition|json_encode()|raw }},
|
||||
{% endfor %}
|
||||
};
|
||||
var rawData = {
|
||||
{% for aAreaData in aGroupingAreasData %}
|
||||
'{{ aAreaData.sId }}': {{ aAreaData.aItems|json_encode()|raw }},
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
// Show a loader inside the table
|
||||
var showTableLoader = function (oElem) {
|
||||
oElem.children('tbody').html('<tr><td class="datatables_overlay" colspan="100">' + $('#page_overlay').html() + '</td></tr>');
|
||||
};
|
||||
// Columns definition for the table from the columnsProperties
|
||||
var getColumnsDefinition = function (tableName) {
|
||||
var tableProperties = columnsProperties[tableName];
|
||||
|
||||
if (tableProperties === undefined && window.console) {
|
||||
console.log('Could not retrieve columns properties for table "' + tableName + '"');
|
||||
return false;
|
||||
}
|
||||
if (rawData[tableName] === undefined && window.console) {
|
||||
console.log('Could not retrieve data for table "' + tableName + '"');
|
||||
return false;
|
||||
}
|
||||
|
||||
var columnsDefinition = [];
|
||||
|
||||
for (key in tableProperties) {
|
||||
// Regular attribute columns
|
||||
if (key !== '_ui_extensions') {
|
||||
columnsDefinition.push({
|
||||
"width": "auto",
|
||||
"searchable": true,
|
||||
"sortable": (sDataLoading === '{{ constant('Combodo\\iTop\\Portal\\Brick\\AbstractBrick::ENUM_DATA_LOADING_FULL') }}'),
|
||||
"title": tableProperties[key].title,
|
||||
"defaultContent": "",
|
||||
"type": "html",
|
||||
"data": "attributes." + key + ".att_code",
|
||||
"render": function (att_code, type, row) {
|
||||
var cellElem;
|
||||
var itemActions;
|
||||
var itemPrimarayAction;
|
||||
|
||||
// Preparing action on the cell
|
||||
// Note : For now we will use only one action, the secondary actions are therefore not implemented. Only the data structure is done.
|
||||
itemActions = row.attributes[att_code].actions;
|
||||
|
||||
// Preparing the cell data
|
||||
cellElem = (itemActions.length > 0) ? $('<a></a>') : $('<span></span>');
|
||||
cellElem.html(row.attributes[att_code].value);
|
||||
// Building actions
|
||||
if (itemActions.length > 0) {
|
||||
// - Primary action
|
||||
itemPrimaryAction = itemActions[0];
|
||||
switch (itemPrimaryAction.type) {
|
||||
case '{{ constant('Combodo\\iTop\\Portal\\Brick\\ManageBrick::ENUM_ACTION_VIEW') }}':
|
||||
url = '{{ app.url_generator.generate('p_object_view', {'sObjectClass': '-objectClass-', 'sObjectId': '-objectId-'})|raw }}'.replace(/-objectClass-/, itemPrimaryAction.class).replace(/-objectId-/, itemPrimaryAction.id);
|
||||
break;
|
||||
case '{{ constant('Combodo\\iTop\\Portal\\Brick\\ManageBrick::ENUM_ACTION_EDIT') }}':
|
||||
url = '{{ app.url_generator.generate('p_object_edit', {'sObjectClass': '-objectClass-', 'sObjectId': '-objectId-'})|raw }}'.replace(/-objectClass-/, itemPrimaryAction.class).replace(/-objectId-/, itemPrimaryAction.id);
|
||||
break;
|
||||
default:
|
||||
url = '#';
|
||||
//console.log('Action "'+itemPrimaryAction+'" not implemented');
|
||||
break;
|
||||
}
|
||||
SetActionUrl(cellElem, url);
|
||||
SetActionOpeningTarget(cellElem, itemPrimaryAction.opening_target);
|
||||
|
||||
// - Secondary actions
|
||||
// Not done for now, only the data structure is ready in case we need it later
|
||||
}
|
||||
|
||||
return cellElem.prop('outerHTML');
|
||||
},
|
||||
});
|
||||
}
|
||||
// UI extensions buttons
|
||||
else {
|
||||
columnsDefinition.push({
|
||||
"width": "auto",
|
||||
"searchable": false,
|
||||
"sortable": (sDataLoading === '{{ constant('Combodo\\iTop\\Portal\\Brick\\AbstractBrick::ENUM_DATA_LOADING_FULL') }}'),
|
||||
"title": tableProperties[key].title,
|
||||
"defaultContent": "",
|
||||
"type": "html",
|
||||
"data": "attributes." + key + ".att_code",
|
||||
"render": function (att_code, type, row) {
|
||||
var cellElem = $('<div class="group-actions-wrapper"></div>');
|
||||
var actionsCount = row.actions.length;
|
||||
|
||||
// Adding menu wrapper in case there are several actions
|
||||
var actionsElem = $('<div></div>');
|
||||
actionsElem.appendTo(cellElem);
|
||||
if (actionsCount > 1) {
|
||||
actionsElem.addClass('group-actions pull-right');
|
||||
|
||||
// Adding hamburger icon toggler
|
||||
actionsElem.append(
|
||||
$('<a class="glyphicon glyphicon-menu-hamburger" data-toggle="collapse" data-target="#item-actions-menu-' + row.id + '"></a>')
|
||||
);
|
||||
|
||||
// Adding sub menu
|
||||
var actionsSSMenuElem = $('<div id="item-actions-menu-' + row.id + '" class="item-action-wrapper panel panel-default"></div>')
|
||||
.appendTo(actionsElem);
|
||||
var actionsSSMenuContainerElem = $('<div class="panel-body"></div>')
|
||||
.appendTo(actionsSSMenuElem);
|
||||
}
|
||||
|
||||
// Adding actions
|
||||
for (var i in row.actions) {
|
||||
var actionDef = row.actions[i];
|
||||
var actionElem = $('<a></a>')
|
||||
.attr('href', actionDef.url)
|
||||
.append($('<span></span>').html(actionDef.label));
|
||||
|
||||
// Adding css classes to action
|
||||
for (var j in actionDef.css_classes) {
|
||||
actionElem.addClass(actionDef.css_classes[j]);
|
||||
}
|
||||
|
||||
// Performing specific treatment regarding the action type
|
||||
if (actionDef.type === 'button') {
|
||||
// External files
|
||||
// Note: Not supported yet
|
||||
|
||||
// On click callback
|
||||
actionElem.attr('onclick', actionDef.onclick);
|
||||
}
|
||||
else if (actionDef.type === 'link') {
|
||||
actionElem.attr('target', actionDef.target);
|
||||
}
|
||||
|
||||
if (actionsCount > 1) {
|
||||
actionsSSMenuContainerElem.append($('<p></p>').append(actionElem));
|
||||
}
|
||||
else {
|
||||
actionsElem.append(actionElem);
|
||||
}
|
||||
}
|
||||
|
||||
return cellElem.prop('outerHTML');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return columnsDefinition;
|
||||
};
|
||||
|
||||
$(document).ready(function () {
|
||||
{% for aAreaData in aGroupingAreasData %}
|
||||
{% set sAreaId = aAreaData.sId %}
|
||||
|
||||
$(function () {
|
||||
$('[data-toggle="tooltip"]').tooltip()
|
||||
})
|
||||
|
||||
showTableLoader($('#table-{{ sAreaId }}'));
|
||||
var oTable{{ sAreaId }} = $('#table-{{ sAreaId }}').dataTable({
|
||||
"language": {
|
||||
"processing": "{{ 'Portal:Datatables:Language:Processing'|dict_s }}",
|
||||
"search": "{{ 'Portal:Datatables:Language:Search'|dict_s }}",
|
||||
"lengthMenu": "{{ 'Portal:Datatables:Language:LengthMenu'|dict_s }}",
|
||||
"zeroRecords": "{{ 'Portal:Datatables:Language:ZeroRecords'|dict_s }}",
|
||||
"info": "{{ 'Portal:Datatables:Language:Info'|dict_s }}",
|
||||
"infoEmpty": "{{ 'Portal:Datatables:Language:InfoEmpty'|dict_s }}",
|
||||
"infoFiltered": "({{ 'Portal:Datatables:Language:InfoFiltered'|dict_s }})",
|
||||
"emptyTable": "{{ 'Portal:Datatables:Language:EmptyTable'|dict_s }}",
|
||||
"paginate": {
|
||||
"first": "{{ 'Portal:Datatables:Language:Paginate:First'|dict_s }}",
|
||||
"previous": "{{ 'Portal:Datatables:Language:Paginate:Previous'|dict_s }}",
|
||||
"next": "{{ 'Portal:Datatables:Language:Paginate:Next'|dict_s }}",
|
||||
"last": "{{ 'Portal:Datatables:Language:Paginate:Last'|dict_s }}"
|
||||
},
|
||||
"aria": {
|
||||
"sortAscending": ": {{ 'Portal:Datatables:Language:Sort:Ascending'|dict_s }}",
|
||||
"sortDescending": ": {{ 'Portal:Datatables:Language:Sort:Descending'|dict_s }}"
|
||||
}
|
||||
},
|
||||
"lengthMenu": [[10, 20, 50, -1], [10, 20, 50, "{{ 'Portal:Datatables:Language:DisplayLength:All'|dict_s }}"]],
|
||||
"displayLength": {{ constant('Combodo\\iTop\\Portal\\Brick\\ManageBrick::DEFAULT_LIST_LENGTH') }},
|
||||
"dom": '<"row"<"col-sm-6"l><"col-sm-6"<f><"visible-xs"p>>>t<"row"<"col-sm-6"i><"col-sm-6"p>>',
|
||||
"columns": getColumnsDefinition('{{ sAreaId }}'),
|
||||
"order": [[0, "desc"]],
|
||||
"rowCallback": function (oRow, oData) {
|
||||
if (oData.highlight_class !== undefined) {
|
||||
var sHighlightClass = oData.highlight_class;
|
||||
var sBSHiglightClass = '';
|
||||
|
||||
// Adding classic iTop class
|
||||
$(oRow).addClass(sHighlightClass);
|
||||
// Adding mapped BS class
|
||||
if (sHighlightClass === '{{ constant('HILIGHT_CLASS_CRITICAL') }}') {
|
||||
sBSHiglightClass = 'danger';
|
||||
}
|
||||
else if (sHighlightClass === '{{ constant('HILIGHT_CLASS_WARNING') }}') {
|
||||
sBSHiglightClass = 'warning';
|
||||
}
|
||||
else if (sHighlightClass === '{{ constant('HILIGHT_CLASS_OK') }}') {
|
||||
sBSHiglightClass = 'success';
|
||||
}
|
||||
$(oRow).addClass(sBSHiglightClass);
|
||||
}
|
||||
},
|
||||
"drawCallback": function (settings) {
|
||||
// Hiding pagination if only one page
|
||||
if ($(this).closest('.dataTables_wrapper').find('.dataTables_paginate:last .paginate_button:not(.previous):not(.next)').length < 2) {
|
||||
$(this).closest('.dataTables_wrapper').find('.dataTables_paginate, .dataTables_info').hide();
|
||||
}
|
||||
else {
|
||||
$(this).closest('.dataTables_wrapper').find('.dataTables_paginate, .dataTables_info').show();
|
||||
}
|
||||
},
|
||||
{% if sDataLoading == constant('Combodo\\iTop\\Portal\\Brick\\AbstractBrick::ENUM_DATA_LOADING_FULL') %}
|
||||
"data": rawData['{{ sAreaId }}'],
|
||||
{% else %}
|
||||
"processing": true,
|
||||
"serverSide": true,
|
||||
{#"searchDelay": 1000, // can be used to increase time between server calls when typing search query#}
|
||||
"ajax": {
|
||||
"url": "{{ app.url_generator.generate('p_manage_brick_lazy', {'sBrickId': sBrickId, 'sGroupingTab': sGroupingTab, 'sGroupingArea': sAreaId})|raw }}",
|
||||
"data": function (d) {
|
||||
d.iPageNumber = Math.floor(d.start / d.length) + 1;
|
||||
d.iListLength = d.length;
|
||||
d.columns = null;
|
||||
d.orders = null;
|
||||
|
||||
{% if sSearchValue is not null %}
|
||||
// Sets default filter value
|
||||
if (d.draw === 1) {
|
||||
$('#table-{{ sAreaId }}_filter input').val('{{ sSearchValue }}');
|
||||
d.search.value = $('#table-{{ sAreaId }}_filter input').val();
|
||||
}
|
||||
{% endif %}
|
||||
if (d.search.value) {
|
||||
d.sSearchValue = d.search.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
});
|
||||
|
||||
// Overrides filter input to apply throttle. Otherwise, an ajax request is send each time a key is pressed
|
||||
// Also removes accents from search string
|
||||
// Note : The '.off()' call is to unbind event from DataTables that where triggered before we could intercept anything
|
||||
$('#table-{{ sAreaId }}_filter input').off().on('keyup', function () {
|
||||
var me = this;
|
||||
|
||||
clearTimeout(oKeyTimeout);
|
||||
oKeyTimeout = setTimeout(function () {
|
||||
oTable{{ sAreaId }}.search(me.value.latinise()).draw();
|
||||
}, iSearchThrottle);
|
||||
});// Shows a loader in the table when processing
|
||||
$('#table-{{ sAreaId }}').on('processing.dt', function (event, settings, processing) {
|
||||
if (processing === true) {
|
||||
showTableLoader($(this));
|
||||
}
|
||||
});
|
||||
{% endfor %}
|
||||
|
||||
// Auto collapse item actions popup
|
||||
$('body').click(function () {
|
||||
$('table .item-action-wrapper.collapse.in').collapse('hide');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -1,361 +1,17 @@
|
||||
{# itop-portal-base/portal/src/views/bricks/manage/layout.html.twig #}
|
||||
{# Manage brick base layout #}
|
||||
{% extends 'itop-portal-base/portal/src/views/bricks/layout.html.twig' %}
|
||||
|
||||
{% block pPageBodyClass %}{{ parent() }} page_manage_brick{% endblock %}
|
||||
|
||||
{% block pMainHeaderTitle %}
|
||||
{{ oBrick.GetTitle()|dict_s }}
|
||||
{% endblock %}
|
||||
{% block pMainHeaderTitle %}{{ oBrick.GetTitle()|dict_s }} ({{ iCount }}) {% endblock %}
|
||||
|
||||
{% block pMainHeaderActions %}
|
||||
{% if aGroupingTabsValues|length > 1 %}
|
||||
<div class="btn-group {#btn-group-sm#} btn_group_explicit">
|
||||
{% for aGroupingTab in aGroupingTabsValues %}
|
||||
<a href="{{ app.url_generator.generate('p_manage_brick', {'sBrickId': sBrickId, 'sGroupingTab': aGroupingTab.value}) }}" id="btn_tab_for_{{ aGroupingTab.value }}" class="btn btn-default {% if sGroupingTab is defined and sGroupingTab == aGroupingTab.value %}active{% endif %}">
|
||||
{{ aGroupingTab.label|raw }}
|
||||
{% if oBrick.GetShowTabCounts() %}
|
||||
<span class="btn_tab_count">{{ aGroupingTab.count|raw }}</span>
|
||||
{% endif %}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="btn-group btn_group_explicit">
|
||||
{% for sDisplay in oBrick.ListLayoutDisplayTypes %}
|
||||
<a href="{{ app.url_generator.generate('p_manage_brick', {'sBrickId': sBrickId, 'sDisplayType': sDisplay}) }}{% if app['combodo.portal.instance.routes'][oBrick.GetRouteName]['hash'] is defined %}#{{ app['combodo.portal.instance.routes'][oBrick.GetRouteName]['hash'] }}{% endif %}"
|
||||
id="btn_tab_for_{{ sDisplay }}"
|
||||
class="btn btn-default {% if sDisplay == oBrick.GetPresentationDataForDisplayType(sDisplayType).layoutDisplayType %}active{% endif %}">
|
||||
{{ ('Brick:Portal:Manage:DisplayType:' ~ sDisplay)|dict_s }}
|
||||
</a>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block pMainContentHolder%}
|
||||
{% set iTableCount = 0 %}
|
||||
{% if aGroupingAreasData|length > 0 %}
|
||||
{% for aAreaData in aGroupingAreasData %}
|
||||
{% if aAreaData.iItemsCount > 0 %}
|
||||
{% set iTableCount = iTableCount + 1 %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title">{{ aAreaData.sTitle }}</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
{# We decided not to show empty tables anymore #}
|
||||
{#
|
||||
{% if aAreaData.iItemsCount > 0 %}
|
||||
#}
|
||||
<table id="table-{{ aAreaData.sId }}" class="table table-striped table-bordered responsive" width="100%"></table>
|
||||
{#
|
||||
{% else %}
|
||||
<div class="text-center">
|
||||
{{ 'Brick:Portal:Manage:Table:NoData'|dict_s }}
|
||||
</div>
|
||||
{% endif %}
|
||||
#}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
{% if iTableCount == 0 %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
<h3 class="text-center">{{ 'Brick:Portal:Manage:Table:NoData'|dict_s }}</h3>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
||||
{% block pPageLiveScripts %}
|
||||
{{ parent() }}
|
||||
|
||||
<script type="text/javascript">
|
||||
var sDataLoading = '{{ sDataLoading }}';
|
||||
// Used for ajax throttling
|
||||
var iSearchThrottle = 300;
|
||||
var oKeyTimeout;
|
||||
var aKeyTimeoutFilteredKeys = [9, 16, 17, 18, 19, 27, 33, 34, 35, 36, 37, 38, 39, 40]; // Tab, Shift, Ctrl, Alt, Pause, Esc, Page Up/Down, Home, End, Left/Up/Right/Down arrows
|
||||
|
||||
var columnsProperties = {
|
||||
{% for aAreaData in aGroupingAreasData %}
|
||||
'{{ aAreaData.sId }}': {{ aAreaData.aColumnsDefinition|json_encode()|raw }},
|
||||
{% endfor %}
|
||||
};
|
||||
var rawData = {
|
||||
{% for aAreaData in aGroupingAreasData %}
|
||||
'{{ aAreaData.sId }}': {{ aAreaData.aItems|json_encode()|raw }},
|
||||
{% endfor %}
|
||||
};
|
||||
|
||||
// Show a loader inside the table
|
||||
var showTableLoader = function(oElem)
|
||||
{
|
||||
oElem.children('tbody').html('<tr><td class="datatables_overlay" colspan="100">' + $('#page_overlay').html() + '</td></tr>');
|
||||
};
|
||||
// Columns definition for the table from the columnsProperties
|
||||
var getColumnsDefinition = function(tableName)
|
||||
{
|
||||
var tableProperties = columnsProperties[tableName];
|
||||
|
||||
if(tableProperties === undefined && window.console)
|
||||
{
|
||||
console.log('Could not retrieve columns properties for table "'+tableName+'"');
|
||||
return false;
|
||||
}
|
||||
if(rawData[tableName] === undefined && window.console)
|
||||
{
|
||||
console.log('Could not retrieve data for table "'+tableName+'"');
|
||||
return false;
|
||||
}
|
||||
|
||||
var columnsDefinition = [];
|
||||
|
||||
for(key in tableProperties)
|
||||
{
|
||||
// Regular attribute columns
|
||||
if(key !== '_ui_extensions') {
|
||||
columnsDefinition.push({
|
||||
"width": "auto",
|
||||
"searchable": true,
|
||||
"sortable": (sDataLoading === '{{ constant('Combodo\\iTop\\Portal\\Brick\\AbstractBrick::ENUM_DATA_LOADING_FULL') }}'),
|
||||
"title": tableProperties[key].title,
|
||||
"defaultContent": "",
|
||||
"type": "html",
|
||||
"data": "attributes." + key + ".att_code",
|
||||
"render": function (att_code, type, row) {
|
||||
var cellElem;
|
||||
var itemActions;
|
||||
var itemPrimarayAction;
|
||||
|
||||
// Preparing action on the cell
|
||||
// Note : For now we will use only one action, the secondary actions are therefore not implemented. Only the data structure is done.
|
||||
itemActions = row.attributes[att_code].actions;
|
||||
|
||||
// Preparing the cell data
|
||||
cellElem = (itemActions.length > 0) ? $('<a></a>') : $('<span></span>');
|
||||
cellElem.html(row.attributes[att_code].value);
|
||||
// Building actions
|
||||
if (itemActions.length > 0) {
|
||||
// - Primary action
|
||||
itemPrimaryAction = itemActions[0];
|
||||
switch (itemPrimaryAction.type) {
|
||||
case '{{ constant('Combodo\\iTop\\Portal\\Brick\\ManageBrick::ENUM_ACTION_VIEW') }}':
|
||||
url = '{{ app.url_generator.generate('p_object_view', {'sObjectClass': '-objectClass-', 'sObjectId': '-objectId-'})|raw }}'.replace(/-objectClass-/, itemPrimaryAction.class).replace(/-objectId-/, itemPrimaryAction.id);
|
||||
break;
|
||||
case '{{ constant('Combodo\\iTop\\Portal\\Brick\\ManageBrick::ENUM_ACTION_EDIT') }}':
|
||||
url = '{{ app.url_generator.generate('p_object_edit', {'sObjectClass': '-objectClass-', 'sObjectId': '-objectId-'})|raw }}'.replace(/-objectClass-/, itemPrimaryAction.class).replace(/-objectId-/, itemPrimaryAction.id);
|
||||
break;
|
||||
default:
|
||||
url = '#';
|
||||
//console.log('Action "'+itemPrimaryAction+'" not implemented');
|
||||
break;
|
||||
}
|
||||
SetActionUrl(cellElem, url);
|
||||
SetActionOpeningTarget(cellElem, itemPrimaryAction.opening_target);
|
||||
|
||||
// - Secondary actions
|
||||
// Not done for now, only the data structure is ready in case we need it later
|
||||
}
|
||||
|
||||
return cellElem.prop('outerHTML');
|
||||
},
|
||||
});
|
||||
}
|
||||
// UI extensions buttons
|
||||
else
|
||||
{
|
||||
columnsDefinition.push({
|
||||
"width": "auto",
|
||||
"searchable": false,
|
||||
"sortable": (sDataLoading === '{{ constant('Combodo\\iTop\\Portal\\Brick\\AbstractBrick::ENUM_DATA_LOADING_FULL') }}'),
|
||||
"title": tableProperties[key].title,
|
||||
"defaultContent": "",
|
||||
"type": "html",
|
||||
"data": "attributes." + key + ".att_code",
|
||||
"render": function (att_code, type, row) {
|
||||
var cellElem = $('<div class="group-actions-wrapper"></div>');
|
||||
var actionsCount = row.actions.length;
|
||||
|
||||
// Adding menu wrapper in case there are several actions
|
||||
var actionsElem = $('<div></div>');
|
||||
actionsElem.appendTo(cellElem);
|
||||
if(actionsCount > 1) {
|
||||
actionsElem.addClass('group-actions pull-right');
|
||||
|
||||
// Adding hamburger icon toggler
|
||||
actionsElem.append(
|
||||
$('<a class="glyphicon glyphicon-menu-hamburger" data-toggle="collapse" data-target="#item-actions-menu-' + row.id + '"></a>')
|
||||
);
|
||||
|
||||
// Adding sub menu
|
||||
var actionsSSMenuElem = $('<div id="item-actions-menu-' + row.id + '" class="item-action-wrapper panel panel-default"></div>')
|
||||
.appendTo(actionsElem);
|
||||
var actionsSSMenuContainerElem = $('<div class="panel-body"></div>')
|
||||
.appendTo(actionsSSMenuElem);
|
||||
}
|
||||
|
||||
// Adding actions
|
||||
for(var i in row.actions)
|
||||
{
|
||||
var actionDef = row.actions[i];
|
||||
var actionElem = $('<a></a>')
|
||||
.attr('href', actionDef.url)
|
||||
.append( $('<span></span>').html(actionDef.label) );
|
||||
|
||||
// Adding css classes to action
|
||||
for(var j in actionDef.css_classes)
|
||||
{
|
||||
actionElem.addClass(actionDef.css_classes[j]);
|
||||
}
|
||||
|
||||
// Performing specific treatment regarding the action type
|
||||
if(actionDef.type === 'button')
|
||||
{
|
||||
// External files
|
||||
// Note: Not supported yet
|
||||
|
||||
// On click callback
|
||||
actionElem.attr('onclick', actionDef.onclick);
|
||||
}
|
||||
else if(actionDef.type === 'link')
|
||||
{
|
||||
actionElem.attr('target', actionDef.target);
|
||||
}
|
||||
|
||||
if(actionsCount > 1)
|
||||
{
|
||||
actionsSSMenuContainerElem.append( $('<p></p>').append(actionElem) );
|
||||
}
|
||||
else
|
||||
{
|
||||
actionsElem.append( actionElem );
|
||||
}
|
||||
}
|
||||
|
||||
return cellElem.prop('outerHTML');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return columnsDefinition;
|
||||
};
|
||||
|
||||
$(document).ready(function(){
|
||||
{% for aAreaData in aGroupingAreasData %}
|
||||
{% set sAreaId = aAreaData.sId %}
|
||||
|
||||
showTableLoader( $('#table-{{ sAreaId }}') );
|
||||
var oTable{{ sAreaId }} = $('#table-{{ sAreaId }}').DataTable( {
|
||||
"language": {
|
||||
"processing": "{{ 'Portal:Datatables:Language:Processing'|dict_s }}",
|
||||
"search": "{{ 'Portal:Datatables:Language:Search'|dict_s }}",
|
||||
"lengthMenu": "{{ 'Portal:Datatables:Language:LengthMenu'|dict_s }}",
|
||||
"zeroRecords": "{{ 'Portal:Datatables:Language:ZeroRecords'|dict_s }}",
|
||||
"info": "{{ 'Portal:Datatables:Language:Info'|dict_s }}",
|
||||
"infoEmpty": "{{ 'Portal:Datatables:Language:InfoEmpty'|dict_s }}",
|
||||
"infoFiltered": "({{ 'Portal:Datatables:Language:InfoFiltered'|dict_s }})",
|
||||
"emptyTable": "{{ 'Portal:Datatables:Language:EmptyTable'|dict_s }}",
|
||||
"paginate": {
|
||||
"first": "{{ 'Portal:Datatables:Language:Paginate:First'|dict_s }}",
|
||||
"previous": "{{ 'Portal:Datatables:Language:Paginate:Previous'|dict_s }}",
|
||||
"next": "{{ 'Portal:Datatables:Language:Paginate:Next'|dict_s }}",
|
||||
"last": "{{ 'Portal:Datatables:Language:Paginate:Last'|dict_s }}"
|
||||
},
|
||||
"aria": {
|
||||
"sortAscending": ": {{ 'Portal:Datatables:Language:Sort:Ascending'|dict_s }}",
|
||||
"sortDescending": ": {{ 'Portal:Datatables:Language:Sort:Descending'|dict_s }}"
|
||||
}
|
||||
},
|
||||
"lengthMenu": [[10, 20, 50, -1], [10, 20, 50, "{{ 'Portal:Datatables:Language:DisplayLength:All'|dict_s }}"]],
|
||||
"displayLength": {{ constant('Combodo\\iTop\\Portal\\Brick\\ManageBrick::DEFAULT_LIST_LENGTH') }},
|
||||
"dom": '<"row"<"col-sm-6"l><"col-sm-6"<f><"visible-xs"p>>>t<"row"<"col-sm-6"i><"col-sm-6"p>>',
|
||||
"columns": getColumnsDefinition('{{ sAreaId }}'),
|
||||
"order": [[0, "desc"]],
|
||||
"rowCallback": function(oRow, oData){
|
||||
if(oData.highlight_class !== undefined)
|
||||
{
|
||||
var sHighlightClass = oData.highlight_class;
|
||||
var sBSHiglightClass = '';
|
||||
|
||||
// Adding classic iTop class
|
||||
$(oRow).addClass(sHighlightClass);
|
||||
// Adding mapped BS class
|
||||
if(sHighlightClass === '{{ constant('HILIGHT_CLASS_CRITICAL') }}')
|
||||
{
|
||||
sBSHiglightClass = 'danger';
|
||||
}
|
||||
else if(sHighlightClass === '{{ constant('HILIGHT_CLASS_WARNING') }}')
|
||||
{
|
||||
sBSHiglightClass = 'warning';
|
||||
}
|
||||
else if(sHighlightClass === '{{ constant('HILIGHT_CLASS_OK') }}')
|
||||
{
|
||||
sBSHiglightClass = 'success';
|
||||
}
|
||||
$(oRow).addClass(sBSHiglightClass);
|
||||
}
|
||||
},
|
||||
"drawCallback": function(settings){
|
||||
// Hiding pagination if only one page
|
||||
if($(this).closest('.dataTables_wrapper').find('.dataTables_paginate:last .paginate_button:not(.previous):not(.next)').length < 2)
|
||||
{
|
||||
$(this).closest('.dataTables_wrapper').find('.dataTables_paginate, .dataTables_info').hide();
|
||||
}
|
||||
else
|
||||
{
|
||||
$(this).closest('.dataTables_wrapper').find('.dataTables_paginate, .dataTables_info').show();
|
||||
}
|
||||
},
|
||||
{% if sDataLoading == constant('Combodo\\iTop\\Portal\\Brick\\AbstractBrick::ENUM_DATA_LOADING_FULL') %}
|
||||
"data": rawData['{{ sAreaId }}'],
|
||||
{% else %}
|
||||
"processing": true,
|
||||
"serverSide": true,
|
||||
{#"searchDelay": 1000, // can be used to increase time between server calls when typing search query#}
|
||||
"ajax": {
|
||||
"url": "{{ app.url_generator.generate('p_manage_brick_lazy', {'sBrickId': sBrickId, 'sGroupingTab': sGroupingTab, 'sGroupingArea': sAreaId})|raw }}",
|
||||
"data": function(d){
|
||||
d.iPageNumber = Math.floor(d.start/d.length) + 1;
|
||||
d.iListLength = d.length;
|
||||
d.columns = null;
|
||||
d.orders = null;
|
||||
|
||||
{% if sSearchValue is not null %}
|
||||
// Sets default filter value
|
||||
if(d.draw === 1)
|
||||
{
|
||||
$('#table-{{ sAreaId }}_filter input').val('{{ sSearchValue }}');
|
||||
d.search.value = $('#table-{{ sAreaId }}_filter input').val();
|
||||
}
|
||||
{% endif %}
|
||||
if(d.search.value)
|
||||
{
|
||||
d.sSearchValue = d.search.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
{% endif %}
|
||||
} );
|
||||
|
||||
// Overrides filter input to apply throttle. Otherwise, an ajax request is send each time a key is pressed
|
||||
// Also removes accents from search string
|
||||
// Note : The '.off()' call is to unbind event from DataTables that where triggered before we could intercept anything
|
||||
$('#table-{{ sAreaId }}_filter input').off().on('keyup', function(){
|
||||
var me = this;
|
||||
|
||||
clearTimeout(oKeyTimeout);
|
||||
oKeyTimeout = setTimeout(function() {
|
||||
oTable{{ sAreaId }}.search(me.value.latinise()).draw();
|
||||
}, iSearchThrottle);
|
||||
});// Shows a loader in the table when processing
|
||||
$('#table-{{ sAreaId }}').on('processing.dt', function(event, settings, processing){
|
||||
if(processing === true)
|
||||
{
|
||||
showTableLoader($(this));
|
||||
}
|
||||
});
|
||||
{% endfor %}
|
||||
|
||||
// Auto collapse item actions popup
|
||||
$('body').click(function(){
|
||||
$('table .item-action-wrapper.collapse.in').collapse('hide');
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,62 @@
|
||||
{% if aNames|length > 0 %}
|
||||
<div id="bar-{{ oBrick.GetId }}"></div>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function(){
|
||||
$('#bar-{{ oBrick.GetId }}').on('click', function(oEvent){
|
||||
oEvent.preventDefault();
|
||||
oEvent.stopPropagation();
|
||||
});
|
||||
window.setTimeout(function() {
|
||||
var chart = c3.generate({
|
||||
bindto: d3.select('#bar-{{ oBrick.GetId }}'),
|
||||
data: {
|
||||
json: {{ aDisplayValues | json_encode() | raw }},
|
||||
keys: {
|
||||
x: 'label',
|
||||
value: ["value"]
|
||||
},
|
||||
onclick: function (d, element) {
|
||||
var aURLs = {{ aUrls | json_encode() | raw }};
|
||||
window.location.href = aURLs[d.index];
|
||||
},
|
||||
selection: {
|
||||
enabled: true
|
||||
},
|
||||
type: 'bar'
|
||||
},
|
||||
axis: {
|
||||
x: {
|
||||
tick: {
|
||||
culling: {max: 25}, // Maximum 24 labels on x axis (2 years).
|
||||
centered: true,
|
||||
rotate: 90,
|
||||
multiline: false
|
||||
},
|
||||
type: 'category' // this needed to load string x value
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
y: {
|
||||
show: true
|
||||
}
|
||||
},
|
||||
legend: {
|
||||
show: false,
|
||||
},
|
||||
tooltip: {
|
||||
grouped: false,
|
||||
format: {
|
||||
title: function() { return '' },
|
||||
name: function (name, ratio, id, index) {
|
||||
var aNames = {{ aNames | json_encode() | raw }};
|
||||
return aNames['series_' + index];
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
</script>
|
||||
{% else %}
|
||||
<h3 class="text-center">{{ 'Brick:Portal:Manage:Table:NoData'|dict_s }}</h3>
|
||||
{% endif %}
|
||||
@@ -0,0 +1,36 @@
|
||||
{% if aNames|length > 0 %}
|
||||
<div id="pie-{{ oBrick.GetId }}"></div>
|
||||
<script type="text/javascript">
|
||||
$(document).ready(function () {
|
||||
$('#pie-{{ oBrick.GetId }}').on('click', function(oEvent){
|
||||
oEvent.preventDefault();
|
||||
oEvent.stopPropagation();
|
||||
});
|
||||
window.setTimeout(function () {
|
||||
var chart = c3.generate({
|
||||
bindto: d3.select('#pie-{{ oBrick.GetId }}'),
|
||||
data: {
|
||||
columns: {{ aColumns | json_encode | raw }},
|
||||
type: 'pie',
|
||||
names: {{ aNames | json_encode() | raw }},
|
||||
onclick: function (d, element) {
|
||||
var aURLs = {{ aUrls | json_encode() | raw }};
|
||||
window.location.href= aURLs[d.index];
|
||||
},
|
||||
},
|
||||
legend: {
|
||||
show: true,
|
||||
position: 'right',
|
||||
},
|
||||
tooltip: {
|
||||
format: {
|
||||
value: function (value, ratio, id) { return value; }
|
||||
}
|
||||
}
|
||||
});
|
||||
}, 100);
|
||||
});
|
||||
</script>
|
||||
{% else %}
|
||||
<h3 class="text-center">{{ 'Brick:Portal:Manage:Table:NoData'|dict_s }}</h3>
|
||||
{% endif %}
|
||||
@@ -0,0 +1,57 @@
|
||||
{# itop-portal-base/popup-export-excel.html.twig #}
|
||||
{# Export Excel popup layout #}
|
||||
|
||||
<div class="modal-header clearfix">
|
||||
<h4 class="modal-title" style="float: left;">{{ 'ExcelExporter:ExportDialogTitle'|dict_s }}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div id="export-text-result" style="display:none;">
|
||||
<p>{{ 'Core:BulkExport:ExportResult'|dict_s }}</p>
|
||||
<p id="export-error" class="alert alert-danger" role="alert"></p>
|
||||
</div>
|
||||
|
||||
<div id="export-feedback">
|
||||
<p class="export-message" style="text-align:center;">{{ 'ExcelExport:PreparingExport'|dict_s }}</p>
|
||||
<div class="progress">
|
||||
<div class="progress-bar" role="progressbar" style="width: 0%"
|
||||
aria-valuenow="0" aria-valuemin="0" aria-valuemax="100">
|
||||
<span class="progress-message">0%</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button id="export-close" type="button" class="btn btn-primary" data-dismiss="modal" style="display:none;">{{ 'Portal:Button:Close'|dict_s }}</button>
|
||||
<button id="export-cancel" type="button" class="btn btn-secondary export-cancel">{{ 'Portal:Button:Cancel'|dict_s }}</button>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
var sDataState = 'not-yet-started';
|
||||
var sOQL = "{{ sOQL|raw }}";
|
||||
var sFormat = 'xlsx';
|
||||
var sFields = "{{ sFields }}";
|
||||
|
||||
$(document).ready(function () {
|
||||
window.setTimeout(function () {
|
||||
$('.progress').progressbar({
|
||||
value: 0,
|
||||
change: function () {
|
||||
$('.progress-message').text($(this).progressbar("value") + "%");
|
||||
$('.progress-bar').attr('aria-valuenow', $(this).progressbar("value"));
|
||||
$('.progress-bar').width($(this).progressbar("value") + "%");
|
||||
},
|
||||
complete: function () {
|
||||
$('.progress-message').text('100 %');
|
||||
$('.progress-bar').attr('aria-valuenow', '100');
|
||||
$('.progress-bar').width('100%');
|
||||
}
|
||||
});
|
||||
|
||||
$('.export-cancel').on('click', function () {
|
||||
sDataState = 'cancelled';
|
||||
});
|
||||
|
||||
ExportStartExport();
|
||||
}, 100);
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,28 @@
|
||||
{# itop-portal-dashlet-basic/tile.html.twig #}
|
||||
{# Image brick tile layout #}
|
||||
|
||||
<div class="col-xs-12 col-sm-{{ oBrick.GetWidth }} tile-badge">
|
||||
{% block pTileWrapper %}
|
||||
<a href="{{ app.url_generator.generate('p_manage_brick', {'sBrickId': sBrickId, 'sDisplayType': oBrick.GetDisplayType}) }}{% if app['combodo.portal.instance.routes'][oBrick.GetRouteName]['hash'] is defined %}#{{ app['combodo.portal.instance.routes'][oBrick.GetRouteName]['hash'] }}{% endif %}"
|
||||
{% if app['combodo.portal.instance.routes'][oBrick.GetRouteName]['navigation_menu_attr'] is defined %}{% for key, value in app['combodo.portal.instance.routes'][oBrick.GetRouteName]['navigation_menu_attr'] %} {{ key }}="{{ value }}"{% endfor %}{% endif %}
|
||||
{% if oBrick.GetModal %}data-toggle="modal" data-target="#modal-for-all"{% endif %}
|
||||
class="tile{# vertical-center#}"
|
||||
id="brick-{{ oBrick.GetId }}"
|
||||
data-brick-id="{{ oBrick.GetId }}">
|
||||
<div>
|
||||
<div class="tile_decoration">{% if oBrick.GetDecorationClassHome %}<span
|
||||
class="icon {{ oBrick.GetDecorationClassHome }}"></span>{% else %}<img src="{{ sIconURL }}"
|
||||
style="vertical-align:middle;"
|
||||
alt="Class Icon">{% endif %}
|
||||
</div>
|
||||
<div class="tile_body">
|
||||
<div>
|
||||
<div class="tile_description">{{ oBrick.GetTitle()|dict_s }}</div>
|
||||
<div class="tile_title">{{ iCount }}</div>
|
||||
</div>
|
||||
<div class="tile_description"><p>{{ oBrick.GetDescription|dict_s|raw }}</p></div>
|
||||
</div>
|
||||
</div>
|
||||
</a>
|
||||
{% endblock %}
|
||||
</div>
|
||||
@@ -0,0 +1,20 @@
|
||||
{# itop-portal-dashlet-basic/tile.html.twig #}
|
||||
{# Image brick tile layout #}
|
||||
|
||||
<div class="col-xs-12 col-sm-{{ oBrick.GetWidth }}">
|
||||
{% block pTileWrapper %}
|
||||
<a href="{{ app.url_generator.generate('p_manage_brick', {'sBrickId': sBrickId, 'sDisplayType': oBrick.GetDisplayType}) }}{% if app['combodo.portal.instance.routes'][oBrick.GetRouteName]['hash'] is defined %}#{{ app['combodo.portal.instance.routes'][oBrick.GetRouteName]['hash'] }}{% endif %}"
|
||||
{% if app['combodo.portal.instance.routes'][oBrick.GetRouteName]['navigation_menu_attr'] is defined %}{% for key, value in app['combodo.portal.instance.routes'][oBrick.GetRouteName]['navigation_menu_attr'] %} {{ key }}="{{ value }}"{% endfor %}{% endif %}
|
||||
{% if oBrick.GetModal %}data-toggle="modal" data-target="#modal-for-all"{% endif %}
|
||||
class="tile{# vertical-center#}"
|
||||
id="brick-{{ oBrick.GetId }}"
|
||||
data-brick-id="{{ oBrick.GetId }}">
|
||||
<div style="background-color:#fff;padding:0.25em;">
|
||||
<div class="tile_title"><span
|
||||
class="icon fa fa-{{ oBrick.GetDisplayType }}"></span> {{ oBrick.GetTitle()|dict_s }}
|
||||
({{ iCount }})</span> </div>
|
||||
{% include 'itop-portal-base/portal/src/views/bricks/manage/mode-' ~ oBrick.GetDisplayType ~ '.html.twig' with {'oBrick': oBrick, 'aColumns': aColumns, 'aNames': aNames, 'aUrls': aUrls, 'aDisplayValues': aDisplayValues} %}
|
||||
</div>
|
||||
</a>
|
||||
{% endblock %}
|
||||
</div>
|
||||
@@ -0,0 +1,21 @@
|
||||
{# itop-portal-base/portal/src/views/bricks/tile.html.twig #}
|
||||
{# Base brick tile layout #}
|
||||
|
||||
<div class="col-xs-12 col-sm-{{ oBrick.GetWidth }}">
|
||||
{% block pTileWrapper %}
|
||||
<a href="{{ app.url_generator.generate(oBrick.GetRouteName, {sBrickId: oBrick.GetId}) }}{% if app['combodo.portal.instance.routes'][oBrick.GetRouteName]['hash'] is defined %}#{{ app['combodo.portal.instance.routes'][oBrick.GetRouteName]['hash'] }}{% endif %}"
|
||||
{% if app['combodo.portal.instance.routes'][oBrick.GetRouteName]['navigation_menu_attr'] is defined %}{% for key, value in app['combodo.portal.instance.routes'][oBrick.GetRouteName]['navigation_menu_attr'] %} {{ key }}="{{ value }}"{% endfor %}{% endif %}
|
||||
{% if oBrick.GetModal %}data-toggle="modal" data-target="#modal-for-all"{% endif %}
|
||||
class="tile{# vertical-center#}" id="brick-{{ oBrick.GetId }}" data-brick-id="{{ oBrick.GetId }}">
|
||||
<div class="tile_decoration">
|
||||
<span class="icon {{ oBrick.GetDecorationClassHome }}"></span>
|
||||
</div>
|
||||
<div class="tile_body">
|
||||
<div class="tile_title">{{ oBrick.GetTitleHome|dict_s }}</div>
|
||||
{% if oBrick.HasDescription %}
|
||||
<div class="tile_description">{{ oBrick.GetDescription|dict_s|raw }}</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</a>
|
||||
{% endblock %}
|
||||
</div>
|
||||
@@ -0,0 +1,40 @@
|
||||
{# itop-portal-dashlet-basic/tile.html.twig #}
|
||||
{# Topx List tile layout #}
|
||||
|
||||
<div class="col-xs-12 col-sm-{{ oBrick.GetWidth }}">
|
||||
{% block pTileWrapper %}
|
||||
<a href="{{ app.url_generator.generate('p_manage_brick', {'sBrickId': sBrickId, 'sDisplayType': oBrick.GetDisplayType}) }}{% if app['combodo.portal.instance.routes'][oBrick.GetRouteName]['hash'] is defined %}#{{ app['combodo.portal.instance.routes'][oBrick.GetRouteName]['hash'] }}{% endif %}"
|
||||
{% if app['combodo.portal.instance.routes'][oBrick.GetRouteName]['navigation_menu_attr'] is defined %}{% for key, value in app['combodo.portal.instance.routes'][oBrick.GetRouteName]['navigation_menu_attr'] %} {{ key }}="{{ value }}"{% endfor %}{% endif %}
|
||||
{% if oBrick.GetModal %}data-toggle="modal" data-target="#modal-for-all"{% endif %}
|
||||
class="tile{# vertical-center#}"
|
||||
id="brick-{{ oBrick.GetId }}"
|
||||
data-brick-id="{{ oBrick.GetId }}">
|
||||
<div style="background-color:#fff;padding:0.25em;">
|
||||
<div class="tile_title">
|
||||
<span class="icon fa fa-signal fa-rotate-270"></span> {{ oBrick.GetTitle()|dict_s }}
|
||||
({{ iCount }})</span> </div>
|
||||
<table class="table table-sm">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">#</th>
|
||||
<th scope="col">{{ 'Brick:Portal:Manage:Group'|dict_s }}</th>
|
||||
<th scope="col">{{ ('Brick:Portal:Manage:fct:' ~ sFct)|dict_s }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% set iLineCount = 0 %}
|
||||
{% for aDisplayValue in aDisplayValues %}
|
||||
{% set sURL = aUrls[iLineCount] %}
|
||||
{% set iLineCount = iLineCount + 1 %}
|
||||
<tr>
|
||||
<th scope="row">{{ iLineCount }}</th>
|
||||
<td><a href="{{ sURL }}">{{ aDisplayValue.label_html }}</a></td>
|
||||
<td>{{ aDisplayValue.value }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</a>
|
||||
{% endblock %}
|
||||
</div>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -355,10 +355,65 @@ footer{
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.home .tile .tile_title > span.icon {
|
||||
color: $combodo-orange;
|
||||
}
|
||||
|
||||
.home .tile .tile_description{
|
||||
display: none;
|
||||
color: #555555;
|
||||
}
|
||||
|
||||
.home div.tile-badge > a.tile {
|
||||
display: table;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.home div.tile-badge > a.tile > div {
|
||||
display: table-row;
|
||||
}
|
||||
|
||||
.home div.tile-badge > a.tile > div > div {
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
.home div.tile-badge > a.tile > div > div.tile_decoration {
|
||||
text-align: center;
|
||||
vertical-align: top;
|
||||
position: inherit;
|
||||
float: inherit;
|
||||
}
|
||||
|
||||
.home div.tile-badge > a.tile > div > div.tile_body {
|
||||
text-align: right;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.home div.tile-badge > a.tile > div > div.tile_body > div:first-child {
|
||||
text-align: center;
|
||||
margin: 0 auto;
|
||||
margin-left: 10%;
|
||||
}
|
||||
|
||||
.home div.tile-badge > a.tile > div > div.tile_body > div:first-child > div {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.home div.tile-badge > a.tile > div > div.tile_body > div:first-child > div.tile_description {
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
|
||||
.home div.tile-badge > a.tile > div > div.tile_body > div:first-child > div.tile_title {
|
||||
font-size: 1.5em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.home div.tile-badge > a.tile > div > div.tile_body > div.tile_description {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.home .tile{
|
||||
display: block;
|
||||
|
||||
109
datamodels/2.x/itop-portal-base/portal/web/js/export.js
Normal file
109
datamodels/2.x/itop-portal-base/portal/web/js/export.js
Normal file
@@ -0,0 +1,109 @@
|
||||
// Copyright (c) 2010-2017 Combodo SARL
|
||||
//
|
||||
// This file is part of iTop.
|
||||
//
|
||||
// iTop is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Affero General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// iTop is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Affero General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
//
|
||||
|
||||
function ExportStartExport() {
|
||||
var oParams = {};
|
||||
oParams.operation = 'export_build';
|
||||
oParams.format = sFormat;
|
||||
oParams.expression = sOQL;
|
||||
oParams.fields = sFields;
|
||||
$.post(GetAbsoluteUrlAppRoot() + 'pages/ajax.render.php', oParams, function (data) {
|
||||
if (data == null) {
|
||||
ExportError('Export failed (no data provided), please contact your administrator');
|
||||
}
|
||||
else {
|
||||
ExportRun(data);
|
||||
}
|
||||
}, 'json')
|
||||
.fail(function () {
|
||||
ExportError('Export failed, please contact your administrator');
|
||||
});
|
||||
}
|
||||
|
||||
function ExportError(sMessage) {
|
||||
sDataState = 'error';
|
||||
$('#export-feedback').hide();
|
||||
$('#export-text-result').show();
|
||||
$('#export-error').html(sMessage);
|
||||
}
|
||||
|
||||
function ExportRun(data) {
|
||||
switch (data.code) {
|
||||
case 'run':
|
||||
// Continue
|
||||
$('.progress').progressbar({value: data.percentage});
|
||||
$('.export-message').html(data.message);
|
||||
oParams = {};
|
||||
oParams.token = data.token;
|
||||
if (sDataState == 'cancelled') {
|
||||
oParams.operation = 'export_cancel';
|
||||
$('#export-cancel').hide();
|
||||
$('#export-close').show();
|
||||
}
|
||||
else {
|
||||
oParams.operation = 'export_build';
|
||||
}
|
||||
|
||||
$.post(GetAbsoluteUrlAppRoot() + 'pages/ajax.render.php', oParams, function (data) {
|
||||
ExportRun(data);
|
||||
},
|
||||
'json');
|
||||
break;
|
||||
|
||||
case 'done':
|
||||
sDataState = 'done';
|
||||
$('#export-cancel').hide();
|
||||
$('#export-close').show();
|
||||
$('.progress').progressbar({value: data.percentage});
|
||||
sMessage = '<a href="' + GetAbsoluteUrlAppRoot() + 'pages/ajax.render.php?operation=export_download&token=' + data.token + '" target="_blank">' + data.message + '</a>';
|
||||
$('.export-message').html(sMessage);
|
||||
if (data.text_result != undefined) {
|
||||
if (data.mime_type == 'text/html') {
|
||||
$('#export-content').parent().html(data.text_result);
|
||||
$('#export-text-result').show();
|
||||
$('#export-text-result .listResults').tableHover();
|
||||
$('#export-text-result .listResults').tablesorter({widgets: ['myZebra']});
|
||||
}
|
||||
else {
|
||||
if ($('#export-text-result').closest('ui-dialog').length == 0) {
|
||||
// not inside a dialog box, adjust the height... approximately
|
||||
var jPane = $('#export-text-result').closest('.ui-layout-content');
|
||||
var iTotalHeight = jPane.height();
|
||||
jPane.children(':visible').each(function () {
|
||||
if ($(this).attr('id') != '') {
|
||||
iTotalHeight -= $(this).height();
|
||||
}
|
||||
});
|
||||
$('#export-content').height(iTotalHeight - 80);
|
||||
}
|
||||
$('#export-content').val(data.text_result);
|
||||
$('#export-text-result').show();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 'error':
|
||||
sDataState = 'error';
|
||||
$('#export-feedback').hide();
|
||||
$('#export-text-result').show();
|
||||
$('#export-error').html(data.message);
|
||||
$('#export-cancel').hide();
|
||||
$('#export-close').show();
|
||||
default:
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user