Cleanup Dashboard and dashlet unused methods and ajax end points

This commit is contained in:
Eric Espie
2026-01-27 17:52:36 +01:00
parent 814f91bd48
commit 3fa658edb5
13 changed files with 10 additions and 1558 deletions

View File

@@ -1312,37 +1312,6 @@ class DashboardMenuNode extends MenuNode
$oPage->p("Error: failed to load dashboard file: '{$this->sDashboardFile}'");
}
}
/**
* @param WebPage $oPage
* @throws CoreException
* @throws Exception
*/
public function RenderEditor(WebPage $oPage)
{
$oDashboard = $this->GetDashboard();
if ($oDashboard != null) {
//$oDashboard->RenderEditor($oPage);
} else {
$oPage->p("Error: failed to load dashboard file: '{$this->sDashboardFile}'");
}
}
/**
* @param $oDashlet
* @throws Exception
*/
public function AddDashlet($oDashlet)
{
$oDashboard = $this->GetDashboard();
if ($oDashboard != null) {
$oDashboard->AddDashlet($oDashlet);
$oDashboard->Save();
} else {
throw new Exception("Error: failed to load dashboard file: '{$this->sDashboardFile}'");
}
}
}
/**

View File

@@ -904,50 +904,6 @@ try {
}
break;
case 'save_dashboard':
$sDashboardId = utils::ReadParam('dashboard_id', '', false, 'context_param');
$aExtraParams = utils::ReadParam('extra_params', [], false, 'raw_data');
$sReloadURL = utils::ReadParam('reload_url', '', false, utils::ENUM_SANITIZATION_FILTER_URL);
appUserPreferences::SetPref('display_original_dashboard_'.$sDashboardId, false);
$sJSExtraParams = json_encode($aExtraParams);
$aParams = [];
$aParams['layout_class'] = utils::ReadParam('layout_class', '');
$aParams['title'] = utils::ReadParam('title', '', false, 'raw_data');
$aParams['auto_reload'] = utils::ReadParam('auto_reload', false);
$aParams['auto_reload_sec'] = utils::ReadParam('auto_reload_sec', 300);
$aParams['cells'] = utils::ReadParam('cells', [], false, 'raw_data');
$oDashboard = new RuntimeDashboard($sDashboardId);
$oDashboard->FromParams($aParams);
$bIsNew = $oDashboard->Save();
$sDashboardFile = addslashes(utils::ReadParam('file', '', false, 'string'));
$sDashboardDivId = preg_replace('/[^a-zA-Z0-9_]/', '', $sDashboardId);
$sOperation = 'reload_dashboard';
if ($bIsNew) {
// Trigger a reload of the current page since the dashboard just changed
$oPage->add_script(
<<<JS
window.location.reload();
JS
);
} else {
$oPage->add_script(
<<<JS
$('.ibo-dashboard#{$sDashboardDivId}').block();
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
{ operation: 'reload_dashboard', dashboard_id: '{$sDashboardId}', file: '{$sDashboardFile}', extra_params: {$sJSExtraParams}, reload_url: '{$sReloadURL}'},
function(data){
$('.ibo-dashboard#{$sDashboardDivId}').html(data);
$('.ibo-dashboard#{$sDashboardDivId}').unblock();
}
);
JS
);
}
break;
case 'revert_dashboard':
$sDashboardId = utils::ReadParam('dashboard_id', '', false, 'raw_data');
$sReloadURL = utils::ReadParam('reload_url', '', false, utils::ENUM_SANITIZATION_FILTER_URL);
@@ -971,157 +927,6 @@ EOF
);
break;
case 'render_dashboard':
$sDashboardId = utils::ReadParam('dashboard_id', '', false, 'raw_data');
$aExtraParams = utils::ReadParam('extra_params', [], false, 'raw_data');
$aParams = [];
$aParams['layout_class'] = utils::ReadParam('layout_class', '');
$aParams['title'] = utils::ReadParam('title', '', false, 'raw_data');
$aParams['cells'] = utils::ReadParam('cells', [], false, 'raw_data');
$aParams['auto_reload'] = utils::ReadParam('auto_reload', false);
$aParams['auto_reload_sec'] = utils::ReadParam('auto_reload_sec', 300);
$sReloadURL = utils::ReadParam('reload_url', '', false, utils::ENUM_SANITIZATION_FILTER_URL);
$oDashboard = new RuntimeDashboard($sDashboardId);
$oDashboard->FromParams($aParams);
$oDashboard->SetReloadURL($sReloadURL);
$oDashboard->Render($oPage, true /* bEditMode */, $aExtraParams);
break;
case 'dashboard_editor':
$sId = utils::ReadParam('id', '', false, 'context_param');
$aExtraParams = utils::ReadParam('extra_params', [], false, 'raw_data');
$aExtraParams['dashboard_div_id'] = utils::Sanitize($sId, '', 'element_identifier');
$sDashboardFile = utils::ReadParam('file', '', false, 'string');
$sReloadURL = utils::ReadParam('reload_url', '', false, utils::ENUM_SANITIZATION_FILTER_URL);
$oDashboard = RuntimeDashboard::GetDashboardToEdit($sDashboardFile, $sId);
if (!is_null($oDashboard)) {
if (!empty($sReloadURL)) {
$oDashboard->SetReloadURL($sReloadURL);
}
$oDashboard->RenderEditor($oPage, $aExtraParams);
}
break;
case 'new_dashlet_id':
$sDashboardDivId = utils::ReadParam("dashboardid");
$bIsCustomized = true; // Only called at runtime when customizing a dashboard
$iRow = utils::ReadParam("iRow", 0, false, utils::ENUM_SANITIZATION_FILTER_INTEGER);
$iCol = utils::ReadParam("iCol", 0, false, utils::ENUM_SANITIZATION_FILTER_INTEGER);
$sDashletIdOrig = utils::ReadParam("dashletid", '', false, utils::ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER);
$sFinalDashletId = Dashboard::GetDashletUniqueId($bIsCustomized, $sDashboardDivId, $iRow, $iCol, $sDashletIdOrig);
$oPage = new AjaxPage('');
$oPage->SetOutputDataOnly(true);
$oPage->add($sFinalDashletId);
break;
case 'new_dashlet':
require_once(APPROOT.'application/forms.class.inc.php');
require_once(APPROOT.'application/dashlet.class.inc.php');
$sDashletClass = utils::ReadParam('dashlet_class', '', false, utils::ENUM_SANITIZATION_FILTER_PHP_CLASS);
$sDashletId = utils::ReadParam('dashlet_id', '', false, utils::ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER);
if (is_subclass_of($sDashletClass, 'Dashlet')) {
$oDashlet = new $sDashletClass(new ModelReflectionRuntime(), $sDashletId);
$offset = $oPage->start_capture();
$oDashlet->DoRender($oPage, true /* bEditMode */, false /* bEnclosingDiv */);
$sHtml = addslashes($oPage->end_capture($offset));
$sHtml = str_replace("\n", '', $sHtml);
$sHtml = str_replace("\r", '', $sHtml);
$oPage->add_script("$('#dashlet_$sDashletId').html('$sHtml');"); // in ajax web page add_script has the same effect as add_ready_script
// but is executed BEFORE all 'ready_scripts'
$oForm = $oDashlet->GetForm(); // Rebuild the form since the values/content changed
$oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', ['operation' => 'update_dashlet_property']);
$sHtml = addslashes($oForm->RenderAsPropertySheet($oPage, true /* bReturnHtml */, '.itop-dashboard'));
$sHtml = str_replace("\n", '', $sHtml);
$sHtml = str_replace("\r", '', $sHtml);
$oPage->add_script("$('#dashlet_properties_$sDashletId').html('$sHtml')"); // in ajax web page add_script has the same effect as add_ready_script // but is executed BEFORE all 'ready_scripts'
}
break;
case 'update_dashlet_property':
require_once(APPROOT.'application/forms.class.inc.php');
require_once(APPROOT.'application/dashlet.class.inc.php');
$aExtraParams = utils::ReadParam('extra_params', [], false, utils::ENUM_SANITIZATION_FILTER_RAW_DATA);
$aParams = utils::ReadParam('params', [], false, utils::ENUM_SANITIZATION_FILTER_RAW_DATA); // raw_data because we need different filter depending on the options
$sDashletClass = utils::Sanitize($aParams['attr_dashlet_class'], DashletUnknown::class, utils::ENUM_SANITIZATION_FILTER_PHP_CLASS); // Dashlet PHP class or DashletUnknown if impl isn't present in the installed extensions
$sDashletType = utils::Sanitize($aParams['attr_dashlet_type'], '', utils::ENUM_SANITIZATION_FILTER_PHP_CLASS); // original Dashlet PHP class, could be non-existing on the iTop instance (XML definition loading)
$sDashletId = utils::Sanitize($aParams['attr_dashlet_id'], '', utils::ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER);
$aUpdatedProperties = utils::Sanitize($aParams['updated'], [], utils::ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER); // Code of the changed properties as an array: 'attr_xxx', 'attr_xxy' etc
$aPreviousValues = utils::Sanitize($aParams['previous_values'], [], utils::ENUM_SANITIZATION_FILTER_RAW_DATA); // hash array: 'attr_xxx' => 'old_value' - no sanitization as values will be handled in the Dashlet object
if (is_subclass_of($sDashletClass, 'Dashlet')) {
/** @var \Dashlet $oDashlet */
$oDashlet = new $sDashletClass(new ModelReflectionRuntime(), $sDashletId);
$oDashlet->SetDashletType($sDashletType);
$oForm = $oDashlet->GetForm();
$aValues = $oForm->ReadParams(); // hash array: 'xxx' => 'new_value'
$aCurrentValues = $aValues;
$aUpdatedDecoded = [];
foreach ($aUpdatedProperties as $sProp) {
$sDecodedProp = str_replace('attr_', '', $sProp); // Remove the attr_ prefix
// Set the previous value
if (isset($aPreviousValues[$sProp]) && $aPreviousValues[$sProp] != '') {
$aCurrentValues[$sDecodedProp] = $aPreviousValues[$sProp];
} else {
if (gettype($aCurrentValues[$sDecodedProp]) == "array") {
$aCurrentValues[$sDecodedProp] = [];
} else {
$aCurrentValues[$sDecodedProp] = '';
}
}
$aUpdatedDecoded[] = $sDecodedProp;
}
$oDashlet->FromParams($aCurrentValues);
$sPrevClass = get_class($oDashlet);
$oDashlet = $oDashlet->Update($aValues, $aUpdatedDecoded);
$sNewClass = get_class($oDashlet);
if ($sNewClass != $sPrevClass) {
$oPage->add_ready_script("$('#dashlet_$sDashletId').dashlet('option', {dashlet_class: '$sNewClass'});");
}
if ($oDashlet->IsRedrawNeeded()) {
$oBlock = $oDashlet->DoRender($oPage, true, false, $aExtraParams);
$sHtml = ConsoleBlockRenderer::RenderBlockTemplateInPage($oPage, $oBlock);
$sHtml = json_encode($sHtml);
$oPage->add_script("$('#dashlet_$sDashletId').html({$sHtml});");
}
if ($oDashlet->IsFormRedrawNeeded()) {
$oForm = $oDashlet->GetForm(); // Rebuild the form since the values/content changed
$oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', ['operation' => 'update_dashlet_property', 'extra_params' => $aExtraParams]);
$sHtml = $oForm->RenderAsPropertySheet($oPage, true, '.itop-dashboard');
$sHtml = json_encode($sHtml);
$oPage->add_script("$('#dashlet_properties_$sDashletId').html({$sHtml});");
}
}
break;
case 'dashlet_creation_dlg':
$sOQL = utils::ReadParam('oql', '', false, 'raw_data');
RuntimeDashboard::GetDashletCreationDlgFromOQL($oPage, $sOQL);
break;
case 'add_dashlet':
$oForm = RuntimeDashboard::GetDashletCreationForm();
$aValues = $oForm->ReadParams();
$sDashletClass = $aValues['dashlet_class'];
$sMenuId = $aValues['menu_id'];
if (is_subclass_of($sDashletClass, 'Dashlet')) {
$oDashlet = new $sDashletClass(new ModelReflectionRuntime(), 0);
$oDashlet->FromParams($aValues);
ApplicationMenu::LoadAdditionalMenus();
$index = ApplicationMenu::GetMenuIndexById($sMenuId);
$oMenu = ApplicationMenu::GetMenuNode($index);
$oMenu->AddDashlet($oDashlet);
// navigate to the dashboard page
if ($aValues['open_editor']) {
$oPage->add_ready_script("window.location.href='".addslashes(utils::GetAbsoluteUrlAppRoot().'pages/UI.php?c[menu]='.urlencode($sMenuId))."&edit=1';"); // reloads the page, doing a GET even if we arrived via a POST
}
}
break;
case 'shortcut_list_dlg':
$sOQL = utils::ReadParam('oql', '', false, 'raw_data');
$sTableSettings = utils::ReadParam('table_settings', '', false, 'raw_data');

View File

@@ -19,16 +19,10 @@ use Combodo\iTop\DesignElement;
use Combodo\iTop\PropertyType\PropertyTypeDesign;
use Combodo\iTop\PropertyType\Serializer\XMLSerializer;
use DashboardLayout;
use DesignerBooleanField;
use DesignerForm;
use DesignerHiddenField;
use DesignerIntegerField;
use DesignerTextField;
use Dict;
use DOMException;
use InvalidParameterException;
use MetaModel;
use ReflectionClass;
use utils;
/**
@@ -154,7 +148,7 @@ abstract class Dashboard
$oNewDashlet = $this->InitDashletFromDOMNode($oDomNode);
$aDashletOrder[] = ['rank' => $iRank, 'dashlet' => $oNewDashlet];
}
usort($aDashletOrder, [get_class($this), 'SortOnRank']);
usort($aDashletOrder, [$this, 'SortOnRank']);
$aDashletList = [];
foreach ($aDashletOrder as $aItem) {
$aDashletList[] = $aItem['dashlet'];
@@ -162,7 +156,7 @@ abstract class Dashboard
$aCellOrder[] = ['rank' => $iCellRank, 'dashlets' => $aDashletList];
}
}
usort($aCellOrder, [get_class($this), 'SortOnRank']);
usort($aCellOrder, [$this, 'SortOnRank']);
foreach ($aCellOrder as $aItem) {
$this->aCells[] = $aItem['dashlets'];
}
@@ -206,7 +200,7 @@ abstract class Dashboard
*
* @return int
*/
public static function SortOnRank($aItem1, $aItem2)
public function SortOnRank($aItem1, $aItem2)
{
return ($aItem1['rank'] > $aItem2['rank']) ? +1 : -1;
}
@@ -231,21 +225,6 @@ abstract class Dashboard
}
}
/**
* @return string
* @throws \Exception
*/
public function ToXml()
{
$oMainNode = $this->CreateEmptyDashboard();
$this->ToDOMNode($oMainNode);
$sXml = $oMainNode->ownerDocument->saveXML();
return $sXml;
}
/**
* @return DesignElement
* @throws \DOMException
@@ -264,95 +243,6 @@ abstract class Dashboard
return $oMainNode;
}
/**
* @param \DOMElement $oDefinition
*/
public function ToDOMNode($oDefinition)
{
/** @var \DOMDocument $oDoc */
$oDoc = $oDefinition->ownerDocument;
$oNode = $oDoc->createElement('layout', $this->sLayoutClass);
$oDefinition->appendChild($oNode);
$oNode = $oDoc->createElement('title', $this->sTitle);
$oDefinition->appendChild($oNode);
$oAutoReloadNode = $oDoc->createElement('auto_reload');
$oDefinition->appendChild($oAutoReloadNode);
$oNode = $oDoc->createElement('enabled', $this->bAutoReload ? 'true' : 'false');
$oAutoReloadNode->appendChild($oNode);
$oNode = $oDoc->createElement('interval', $this->iAutoReloadSec);
$oAutoReloadNode->appendChild($oNode);
$oCellsNode = $oDoc->createElement('cells');
$oDefinition->appendChild($oCellsNode);
$iCellRank = 0;
foreach ($this->aCells as $aCell) {
$oCellNode = $oDoc->createElement('cell');
$oCellNode->setAttribute('id', $iCellRank);
$oCellsNode->appendChild($oCellNode);
$oCellRank = $oDoc->createElement('rank', $iCellRank);
$oCellNode->appendChild($oCellRank);
$iCellRank++;
$iDashletRank = 0;
$oDashletsNode = $oDoc->createElement('dashlets');
$oCellNode->appendChild($oDashletsNode);
/** @var \Dashlet $oDashlet */
foreach ($aCell as $oDashlet) {
$oNode = $oDoc->createElement('dashlet');
$oDashletsNode->appendChild($oNode);
$oNode->setAttribute('id', $oDashlet->GetID());
$oNode->setAttribute('xsi:type', $oDashlet->GetDashletType());
$oDashletRank = $oDoc->createElement('rank', $iDashletRank);
$oNode->appendChild($oDashletRank);
$iDashletRank++;
$oDashlet->ToDOMNode($oNode);
}
}
}
/**
* @param array $aParams
*/
public function FromParams($aParams)
{
$this->sLayoutClass = $aParams['layout_class'];
if (!is_subclass_of($this->sLayoutClass, DashboardLayout::class)) {
throw new InvalidParameterException('Invalid parameter layout_class "'.$aParams['layout_class'].'"');
}
$this->sTitle = $aParams['title'];
$this->bAutoReload = $aParams['auto_reload'] == 'true';
$this->iAutoReloadSec = max(MetaModel::GetConfig()->Get('min_reload_interval'), (int)$aParams['auto_reload_sec']);
foreach ($aParams['cells'] as $aCell) {
$aCellDashlets = [];
foreach ($aCell as $aDashletParams) {
$sDashletClass = $aDashletParams['dashlet_class'];
$sId = $aDashletParams['dashlet_id'];
/** @var \Dashlet $oNewDashlet */
$oNewDashlet = $this->oDashletFactory->CreateDashlet($sDashletClass, $sId);
if (isset($aDashletParams['dashlet_type'])) {
$oNewDashlet->SetDashletType($aDashletParams['dashlet_type']);
}
$oForm = $oNewDashlet->GetForm();
$oForm->SetParamsContainer($sId);
$oForm->SetPrefix('');
$aValues = $oForm->ReadParams();
$oNewDashlet->FromParams($aValues);
$aCellDashlets[] = $oNewDashlet;
}
$this->aCells[] = $aCellDashlets;
}
}
public function Save()
{
}
public function PersistDashboard(string $sXml): bool
{
return true;
@@ -441,106 +331,6 @@ abstract class Dashboard
$this->iAutoReloadSec = max(MetaModel::GetConfig()->Get('min_reload_interval'), (int)$iAutoReloadSec);
}
/**
* @param \Dashlet $oDashlet
*/
public function AddDashlet($oDashlet)
{
$sId = $this->GetNewDashletId();
$oDashlet->SetId($sId);
$this->aCells[] = [$oDashlet];
}
/**
* @param WebPage $oPage *
* @param array $aExtraParams
*
* @throws \ReflectionException
* @throws \Exception
*/
public function RenderProperties($oPage, $aExtraParams = [])
{
// menu to pick a layout and edit other properties of the dashboard
$oPage->add('<div class="ui-widget-content ui-corner-all ibo-dashboard-editor--properties"><div class="ui-widget-header ui-corner-all ibo-dashboard-editor--properties-title">'.Dict::S('UI:DashboardEdit:Properties').'</div>');
$sUrl = utils::GetAbsoluteUrlAppRoot();
$oPage->add('<div class="ibo-dashboard-editor--properties-subtitle" data-role="ibo-dashboard-editor--properties-subtitle">'.Dict::S('UI:DashboardEdit:Layout').'</div>');
$oPage->add('<div id="select_layout" class="ibo-dashboard-editor--layout-list" data-role="ibo-dashboard-editor--layout-list">');
foreach (get_declared_classes() as $sLayoutClass) {
if (is_subclass_of($sLayoutClass, 'DashboardLayout')) {
$oReflection = new ReflectionClass($sLayoutClass);
if (!$oReflection->isAbstract()) {
$aCallSpec = [$sLayoutClass, 'GetInfo'];
$aInfo = call_user_func($aCallSpec);
$sChecked = ($this->sLayoutClass == $sLayoutClass) ? 'checked' : '';
$oPage->add('<input type="radio" name="layout_class" '.$sChecked.' value="'.$sLayoutClass.'" id="layout_'.$sLayoutClass.'"><label for="layout_'.$sLayoutClass.'"><img src="'.$sUrl.$aInfo['icon'].'" class="ibo-dashboard--properties--icon" data-role="ibo-dashboard--properties--icon"/></label>'); // title="" on either the img or the label does nothing !
}
}
}
$oPage->add('</div>');
$oForm = new DesignerForm();
$oField = new DesignerHiddenField('dashboard_id', '', $this->sId);
$oForm->AddField($oField);
$oField = new DesignerTextField('dashboard_title', Dict::S('UI:DashboardEdit:DashboardTitle'), $this->sTitle);
$oForm->AddField($oField);
$oField = new DesignerBooleanField('auto_reload', Dict::S('UI:DashboardEdit:AutoReload'), $this->bAutoReload);
$oForm->AddField($oField);
$oField = new DesignerIntegerField('auto_reload_sec', Dict::S('UI:DashboardEdit:AutoReloadSec'), $this->iAutoReloadSec);
$oField->SetBoundaries(MetaModel::GetConfig()->Get('min_reload_interval'), null); // no upper limit
$oForm->AddField($oField);
$this->SetFormParams($oForm, $aExtraParams);
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
$oPage->add('</div>');
$sRateTitle = addslashes(Dict::Format('UI:DashboardEdit:AutoReloadSec+', MetaModel::GetConfig()->Get('min_reload_interval')));
$oPage->add_ready_script(
<<<EOF
// Note: the title gets deleted by the validation mechanism
$("#attr_auto_reload_sec").attr('data-tooltip-content', '$sRateTitle');
CombodoTooltip.InitTooltipFromMarkup($("#attr_auto_reload_sec"));
$("#attr_auto_reload_sec").prop('disabled', !$('#attr_auto_reload').is(':checked'));
$('#attr_auto_reload').on('change', function(ev) {
$("#attr_auto_reload_sec").prop('disabled', !$(this).is(':checked'));
} );
$('#select_layout').controlgroup();
$('#select_dashlet').droppable({
accept: '.dashlet',
drop: function(event, ui) {
$( this ).find( ".placeholder" ).remove();
var oDashlet = ui.draggable.data('itopDashlet');
oDashlet._remove_dashlet();
},
});
$('#event_bus').on('dashlet-selected', function(event, data){
var sDashletId = data.dashlet_id;
var sPropId = 'dashlet_properties_'+sDashletId;
$('.dashlet_properties').each(function() {
var sId = $(this).attr('id');
var bShow = (sId == sPropId);
if (bShow)
{
$(this).show();
}
else
{
$(this).hide();
}
});
});
EOF
);
}
/**
* @param WebPage $oPage
* @param bool $bEditMode
@@ -548,6 +338,7 @@ EOF
* @param bool $bCanEdit
*
* @return \Combodo\iTop\Application\UI\Base\Layout\Dashboard\DashboardLayout
* @throws \Exception
*/
public function Render($oPage, $bEditMode = false, $aExtraParams = [], $bCanEdit = true)
{
@@ -572,9 +363,9 @@ EOF
$oDashboard = $oLayout->Render($oPage, $aDashlets, $bEditMode, $aExtraParams);
$oPage->AddUiBlock($oDashboard);
$bFromDasboardPage = isset($aExtraParams['from_dashboard_page']) ? isset($aExtraParams['from_dashboard_page']) : false;
$bFromDashboardPage = isset($aExtraParams['from_dashboard_page']) ? isset($aExtraParams['from_dashboard_page']) : false;
if ($bFromDasboardPage) {
if ($bFromDashboardPage) {
$sTitleForHTML = utils::HtmlEntities(Dict::S($this->sTitle));
$sHtml = "<div class=\"ibo-top-bar--toolbar-dashboard-title\" title=\"{$sTitleForHTML}\">{$sTitleForHTML}</div>";
if ($oPage instanceof iTopWebPage) {
@@ -602,89 +393,6 @@ JS
return $oDashboard;
}
/**
* @param WebPage $oPage
*
* @throws \ReflectionException
* @throws \Exception
*/
public function RenderDashletsSelection(WebPage $oPage)
{
// Toolbox/palette to drag and drop dashlets
$oPage->add('<div class="ui-widget-content ui-corner-all ibo-dashboard--available-dashlets"><div class="ui-widget-header ui-corner-all ibo-dashboard--available-dashlet--title">'.Dict::S('UI:DashboardEdit:Dashlets').'</div>');
$sUrl = utils::GetAbsoluteUrlAppRoot();
$oPage->add('<div id="select_dashlet" class="ibo-dashboard--available-dashlets--list" data-role="ibo-dashboard--available-dashlets--list">');
$aAvailableDashlets = $this->GetAvailableDashlets();
foreach ($aAvailableDashlets as $sDashletClass => $aInfo) {
$oPage->add('<span dashlet_class="'.$sDashletClass.'" class="ibo-dashboard-editor--available-dashlet-icon dashlet_icon ui-widget-content ui-corner-all" data-role="ibo-dashboard-editor--available-dashlet-icon" id="dashlet_'.$sDashletClass.'" data-tooltip-content="'.$aInfo['label'].'" title="'.$aInfo['label'].'"><img src="'.$sUrl.$aInfo['icon'].'" /></span>');
}
$oPage->add('</div>');
$oPage->add('</div>');
$oPage->add_ready_script("$('.dashlet_icon').draggable({cursor: 'move', helper: 'clone', appendTo: 'body', zIndex: 10000, revert:'invalid'});");
}
/**
* @param WebPage $oPage
* @param array $aExtraParams
*/
public function RenderDashletsProperties(WebPage $oPage, $aExtraParams = [])
{
// Toolbox/palette to edit the properties of each dashlet
$oPage->add('<div class="ui-widget-content ui-corner-all ibo-dashlet--properties"><div class="ui-widget-header ui-corner-all ibo-dashlet--properties--title">'.Dict::S('UI:DashboardEdit:DashletProperties').'</div>');
/** @var \DashboardLayoutMultiCol $oLayout */
$oLayout = new $this->sLayoutClass();
$oPage->add('<div id="dashlet_properties">');
foreach ($this->aCells as $iCellIdx => $aCell) {
/** @var \Dashlet $oDashlet */
foreach ($aCell as $oDashlet) {
if ($oDashlet->IsVisible()) {
$oPage->add('<div class="dashlet_properties" id="dashlet_properties_'.$oDashlet->GetID().'" style="display:none">');
$oForm = $oDashlet->GetForm();
$this->SetFormParams($oForm, $aExtraParams);
$oForm->RenderAsPropertySheet($oPage, false, '.itop-dashboard');
$oPage->add('</div>');
}
}
}
$oPage->add('</div>');
$oPage->add('</div>');
}
/**
* Return an array of dashlets available for selection.
*
* @return array
* @throws \Combodo\iTop\Application\Dashlet\DashletException
* @throws \DOMFormatException
*/
protected function GetAvailableDashlets(): array
{
/** @var DashletService $oDashletService */
$oDashletService = MetaModel::GetService('DashletService');
return $oDashletService->GetAvailableDashlets();
}
/**
* @return int|mixed
*/
protected function GetNewDashletId()
{
$iNewId = 0;
foreach ($this->aCells as $aDashlets) {
/** @var \Dashlet $oDashlet */
foreach ($aDashlets as $oDashlet) {
$iNewId = max($iNewId, (int)$oDashlet->GetID());
}
}
return $iNewId + 1;
}
/**
* Prepare dashlet for rendering (eg. change its ID or another processing).
* Meant to be overloaded.
@@ -771,27 +479,4 @@ JS
$this->aGridDashlets[] = $aGridDashlet;
}
}
public function ToModelData(): mixed
{
$this->sLayoutClass = DashboardLayoutGrid::class;
$this->sTitle = $aDashboardValues['title'];
$iRefresh = $aDashboardValues['refresh'];
$this->bAutoReload = $iRefresh > 0;
$this->iAutoReloadSec = $iRefresh;
foreach ($aDashboardValues['pos_dashlets'] as $sId => $aPosDashlet) {
$aGridDashlet = [];
$aGridDashlet['position_x'] = $aPosDashlet['position_x'] ?? 0;
$aGridDashlet['position_y'] = $aPosDashlet['position_y'] ?? 0;
$aGridDashlet['width'] = $aPosDashlet['width'] ?? 2;
$aGridDashlet['height'] = $aPosDashlet['height'] ?? 1;
$aDashlet = $aPosDashlet['dashlet'];
$sType = $aDashlet['type'];
$oDashlet = DashletFactory::GetInstance()->CreateDashlet($sType, $sId);
$oDashlet->FromModelData($aDashlet['properties']);
$aGridDashlet['dashlet'] = $oDashlet;
$this->aGridDashlets[] = $aGridDashlet;
}
}
}

View File

@@ -66,18 +66,6 @@ class RuntimeDashboard extends Dashboard
$oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', ['operation' => 'update_dashlet_property', 'extra_params' => $aExtraParams]);
}
/**
* @inheritDoc
* @return bool $bIsNew
* @throws \Exception
*/
public function Save()
{
$sXml = $this->ToXml();
return $this->PersistDashboard($sXml);
}
/**
* @param string $sXml
*
@@ -530,152 +518,6 @@ EOF
);
}
/**
* @param WebPage $oPage
*
* @param array $aExtraParams
*
* @throws \ArchivedObjectException
* @throws \CoreException
* @throws \ReflectionException
* @throws \Exception
*/
public function RenderEditor($oPage, $aExtraParams = [])
{
if (isset($aExtraParams['this->class'])) {
$oObj = MetaModel::GetObject($aExtraParams['this->class'], $aExtraParams['this->id']);
$aRenderParams = ['query_params' => $oObj->ToArgsForQuery()];
} else {
$aRenderParams = $aExtraParams;
}
$aRenderParams['dashboard_div_id'] = $aExtraParams['dashboard_div_id'];
$sJSExtraParams = json_encode($aExtraParams);
$oPage->add('<div id="dashboard_editor" class="ibo-dashboard-editor" data-role="ibo-dashboard-editor">');
$oPage->add('<div class="ui-layout-center">');
$this->SetCustomFlag(true);
$this->Render($oPage, true, $aRenderParams);
$oPage->add('</div>');
$oPage->add('<div class="ui-layout-east ibo-dashboard-editor--pane" data-role="ibo-dashboard-editor--pane">');
$this->RenderProperties($oPage, $aExtraParams);
$this->RenderDashletsSelection($oPage);
$this->RenderDashletsProperties($oPage, $aExtraParams);
$oPage->add('</div>');
$oPage->add('<div id="event_bus"/>'); // For exchanging messages between the panes, same as in the designer
$oPage->add('</div>');
$sDialogTitle = Dict::S('UI:DashboardEdit:Title');
$sOkButtonLabel = Dict::S('UI:Button:Save');
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
$sId = json_encode($this->sId);
$sLayoutClass = json_encode($this->sLayoutClass);
$sAutoReload = $this->bAutoReload ? 'true' : 'false';
$sAutoReloadSec = (string)$this->iAutoReloadSec;
$sTitle = json_encode($this->sTitle);
$sFile = json_encode($this->GetDefinitionFile());
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php';
$sReloadURL = json_encode($this->GetReloadURL());
$sExitConfirmationMessage = addslashes(Dict::S('UI:NavigateAwayConfirmationMessage'));
$sCancelConfirmationMessage = addslashes(Dict::S('UI:CancelConfirmationMessage'));
$sAutoApplyConfirmationMessage = addslashes(Dict::S('UI:AutoApplyConfirmationMessage'));
$oPage->add_ready_script(
<<<JS
window.bLeavingOnUserAction = false;
$('#dashboard_editor').dialog({
height: $('body').height() - 50,
width: $('body').width() - 50,
modal: true,
title: '$sDialogTitle',
buttons: [
{ text: "$sCancelButtonLabel",
class: "ibo-is-alternative",
click: function() {
var oDashboard = $('.itop-dashboard').data('itopRuntimedashboard');
if (oDashboard.is_modified())
{
if (!confirm('$sCancelConfirmationMessage'))
{
return;
}
}
window.bLeavingOnUserAction = true;
$(this).dialog( "close" );
$(this).remove();
} },
{ text: "$sOkButtonLabel",
class: "ibo-is-primary",
click: function() {
var oDashboard = $('.itop-dashboard').data('itopRuntimedashboard');
if (oDashboard.is_dirty())
{
if (!confirm('$sAutoApplyConfirmationMessage'))
{
return;
}
else
{
oDashboard.apply_changes();
}
}
window.bLeavingOnUserAction = true;
oDashboard.save($(this));
} },
],
close: function() { $(this).remove(); }
});
$('#dashboard_editor .ui-layout-center').runtimedashboard({
dashboard_id: $sId,
layout_class: $sLayoutClass,
title: $sTitle,
auto_reload: $sAutoReload,
auto_reload_sec: $sAutoReloadSec,
submit_to: '$sUrl',
submit_parameters: {operation: 'save_dashboard', file: $sFile, extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
render_to: '$sUrl',
render_parameters: {operation: 'render_dashboard', file: $sFile, extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
new_dashlet_parameters: {operation: 'new_dashlet'}
});
var dashboard_prop_size = GetUserPreference('dashboard_prop_size', 400);
$('#dashboard_editor > .itop-dashboard').width($('#dashboard_editor').width() - dashboard_prop_size);
// We check when we finish click on the pane with the resize slider
// if the pane size changed (% 5px), if it's the case we save the value in userpref
$('#dashboard_editor > .itop-dashboard').on('mouseup',function (){
var iWidthDiff = $(this).width() - ($('#dashboard_editor').width() - dashboard_prop_size);
if( Math.abs(iWidthDiff) > 5){
dashboard_prop_size = iWidthDiff;
SetUserPreference('dashboard_prop_size', $('#dashboard_editor').width() - $(this).width(), true);
}
});
window.onbeforeunload = function() {
if (!window.bLeavingOnUserAction)
{
var oDashboard = $('.itop-dashboard').data('itopRuntimedashboard');
if (oDashboard)
{
if (oDashboard.is_dirty())
{
return '$sExitConfirmationMessage';
}
if (oDashboard.is_modified())
{
return '$sExitConfirmationMessage';
}
}
}
// return nothing ! safer for IE
};
JS
);
$oPage->add_ready_script("");
}
/**
* @param string|null $sOQL
*
@@ -902,6 +744,10 @@ JS
*
* @param array $aExtraParams
*
* @throws \CoreException
* @throws \CoreUnexpectedValue
* @throws \MySQLException
* @throws \OQLException
* @since 2.7.0 N°2735
*/
private function UpdateDashletUserPrefs(Dashlet $oDashlet, $sDashletIdOrig, array $aExtraParams)

View File

@@ -60,67 +60,4 @@ class DashletBadge extends Dashlet
return $oDashletContainer;
}
/**
* @inheritdoc
*/
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = [])
{
$oDashletContainer = new DashletContainer($this->sId, ['dashlet-content']);
$sClass = $this->aProperties['class'];
$sIconUrl = utils::HtmlEntities($this->oModelReflection->GetClassIcon($sClass, false));
$sClassLabel = $this->oModelReflection->GetName($sClass);
$sId = $this->sId;
$sClassCreate = Dict::Format('UI:ClickToCreateNew', $sClassLabel);
$sHtml = <<<HTML
<div id="block_fake_$sId" class="display_block">
<div class="ibo-dashlet-badge--body" data-role="ibo-dashlet-badge--body" title="$sClassLabel">
<div class="ibo-dashlet-badge--icon-container"><img class="ibo-dashlet-badge--icon" src="$sIconUrl"></div>
<div class="ibo-dashlet-badge--actions"><a class="ibo-dashlet-badge--action-list" href="#" data-role="ibo-dashlet-badge--action-list"><span class="ibo-dashlet-badge--action-list-count">4</span><span class="ibo-dashlet-badge--action-list-label">$sClassLabel</span></a><a class="ibo-dashlet-badge--action-create" href="#"><span class="ibo-dashlet-badge--action-create-icon fas fa-plus"></span><span class="ibo-dashlet-badge--action-create-label"> $sClassCreate </span></a></div>
</div>
</div>
HTML;
$oDashletContainer->AddHtml($sHtml);
return $oDashletContainer;
}
protected static $aClassList = null;
/**
* @inheritdoc
*
* @throws \Exception
*/
public function GetPropertiesFields(DesignerForm $oForm)
{
if (is_null(self::$aClassList)) {
// Cache the ordered list of classes (ordered on the label)
// (has a significant impact when editing a page with lots of badges)
//
$aClasses = [];
foreach ($this->oModelReflection->GetClasses('bizmodel', true /*exclude links*/) as $sClass) {
$aClasses[$sClass] = $this->oModelReflection->GetName($sClass);
}
asort($aClasses);
self::$aClassList = [];
foreach ($aClasses as $sClass => $sLabel) {
$sIconUrl = $this->oModelReflection->GetClassIcon($sClass, false);
if ($sIconUrl == '') {
// The icon does not exist, let's use a transparent one of the same size.
$sIconUrl = utils::GetAbsoluteUrlAppRoot().'images/transparent_32_32.png';
}
self::$aClassList[] = ['value' => $sClass, 'label' => $sLabel, 'icon' => $sIconUrl];
}
}
$oField = new DesignerIconSelectionField('class', Dict::S('UI:DashletBadge:Prop-Class'), $this->aProperties['class']);
$oField->SetAllowedValues(self::$aClassList);
$oForm->AddField($oField);
}
}

View File

@@ -258,297 +258,6 @@ abstract class DashletGroupBy extends Dashlet
return $oPanel;
}
/**
* @return array
*/
protected function MakeSimulatedData()
{
$sQuery = $this->aProperties['query'];
$oQuery = $this->oModelReflection->GetQuery($sQuery);
$sClass = $oQuery->GetClass();
$aDisplayValues = [];
if ($this->oModelReflection->IsValidAttCode($sClass, $this->sGroupByAttCode)) {
$aAttributeTypes = $this->oModelReflection->ListAttributes($sClass);
$sAttributeType = $aAttributeTypes[$this->sGroupByAttCode];
if (is_subclass_of($sAttributeType, 'AttributeDateTime') || $sAttributeType == 'AttributeDateTime') {
// Note: an alternative to this somewhat hardcoded way of doing things would be to implement...
//$oExpr = Expression::FromOQL($this->sGroupByExpr);
//$aTranslationData = array($oQuery->GetClassAlias() => array($this->sGroupByAttCode => new ScalarExpression(date('Y-m-d H:i:s', $iTime))));
//$sRawValue = CMDBSource::QueryToScalar('SELECT '.$oExpr->Translate($aTranslationData)->Render());
//$sValueLabel = $oExpr->MakeValueLabel(oFilter, $sRawValue, $sRawValue);
// Anyhow, this requires :
// - an update to the prototype of MakeValueLabel() so that it takes ModelReflection parameters
// - propose clever date/times samples
$aValues = [];
switch ($this->sFunction) {
case 'hour':
$aValues = [8, 9, 15, 18];
break;
case 'month':
$aValues = ['2013 '.Dict::S('Month-11'), '2013 '.Dict::S('Month-12'), '2014 '.Dict::S('Month-01'), '2014 '.Dict::S('Month-02'), '2014 '.Dict::S('Month-03')];
break;
case 'day_of_week':
$aValues = [Dict::S('DayOfWeek-Monday'), Dict::S('DayOfWeek-Wednesday'), Dict::S('DayOfWeek-Thursday'), Dict::S('DayOfWeek-Friday')];
break;
case 'day_of_month':
$aValues = [Dict::S('Month-03').' 30', Dict::S('Month-03').' 31', Dict::S('Month-04').' 01', Dict::S('Month-04').' 02', Dict::S('Month-04').' 03'];
break;
}
foreach ($aValues as $sValue) {
$aDisplayValues[] = ['label' => $sValue, 'value' => (int)rand(1, 15)];
}
} elseif (is_subclass_of($sAttributeType, 'AttributeEnum') || $sAttributeType == 'AttributeEnum') {
$aAllowed = $this->oModelReflection->GetAllowedValues_att($sClass, $this->sGroupByAttCode);
if ($aAllowed) { // null for non enums
foreach ($aAllowed as $sValue => $sValueLabel) {
$iCount = (int)rand(2, 100);
$aDisplayValues[] = [
'label' => $sValueLabel,
'value' => $iCount,
];
}
}
} else {
$aDisplayValues[] = ['label' => 'a', 'value' => 123];
$aDisplayValues[] = ['label' => 'b', 'value' => 321];
$aDisplayValues[] = ['label' => 'c', 'value' => 456];
}
}
return $aDisplayValues;
}
/**
* @inheritdoc
*/
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = [])
{
$oDashletContainer = new DashletContainer(null, ['dashlet-content']);
$oDashletContainer->AddHtml('error!');
return $oDashletContainer;
}
/**
* @inheritdoc
*/
public function GetPropertiesFields(DesignerForm $oForm)
{
$oField = new DesignerTextField('title', Dict::S('UI:DashletGroupBy:Prop-Title'), $this->aProperties['title']);
$oForm->AddField($oField);
$oField = new DesignerLongTextField('query', Dict::S('UI:DashletGroupBy:Prop-Query'), $this->aProperties['query']);
$oField->SetMandatory();
$oField->AddCSSClass("ibo-query-oql");
$oField->AddCSSClass("ibo-is-code");
$oForm->AddField($oField);
try {
// Group by field: build the list of possible values (attribute codes + ...)
$aGroupBy = $this->GetGroupByOptions($this->aProperties['query']);
$oField = new DesignerComboField('group_by', Dict::S('UI:DashletGroupBy:Prop-GroupBy'), $this->aProperties['group_by']);
$oField->SetMandatory();
$oField->SetAllowedValues($aGroupBy);
} catch (Exception $e) {
$oField = new DesignerTextField('group_by', Dict::S('UI:DashletGroupBy:Prop-GroupBy'), $this->aProperties['group_by']);
$oField->SetReadOnly();
$aGroupBy = [];
}
$oForm->AddField($oField);
$aStyles = [
'pie' => Dict::S('UI:DashletGroupByPie:Label'),
'bars' => Dict::S('UI:DashletGroupByBars:Label'),
'table' => Dict::S('UI:DashletGroupByTable:Label'),
];
$oField = new DesignerComboField('style', Dict::S('UI:DashletGroupBy:Prop-Style'), $this->aProperties['style']);
$oField->SetMandatory();
$oField->SetAllowedValues($aStyles);
$oForm->AddField($oField);
$aFunctionAttributes = $this->GetNumericAttributes($this->aProperties['query']);
$aFunctions = $this->GetAllowedFunctions($aFunctionAttributes);
$oSelectorField = new DesignerFormSelectorField('aggregation_function', Dict::S('UI:DashletGroupBy:Prop-Function'), $this->aProperties['aggregation_function']);
$oForm->AddField($oSelectorField);
$oSelectorField->SetMandatory();
// Count sub-menu
$oSubForm = new DesignerForm();
$oSelectorField->AddSubForm($oSubForm, Dict::S('UI:GroupBy:count'), 'count');
foreach ($aFunctions as $sFct => $sLabel) {
$oSubForm = new DesignerForm();
$oField = new DesignerComboField('aggregation_attribute', Dict::S('UI:DashletGroupBy:Prop-FunctionAttribute'), $this->aProperties['aggregation_attribute']);
$oField->SetMandatory();
$oField->SetAllowedValues($aFunctionAttributes);
$oSubForm->AddField($oField);
$oSelectorField->AddSubForm($oSubForm, $sLabel, $sFct);
}
$aOrderField = [];
if (isset($this->aProperties['group_by']) && isset($aGroupBy[$this->aProperties['group_by']])) {
$aOrderField['attribute'] = $aGroupBy[$this->aProperties['group_by']];
}
if ($this->aProperties['aggregation_function'] == 'count') {
$aOrderField['function'] = Dict::S('UI:GroupBy:count');
} else {
$aOrderField['function'] = $aFunctions[$this->aProperties['aggregation_function']];
}
$oSelectorField = new DesignerFormSelectorField('order_by', Dict::S('UI:DashletGroupBy:Prop-OrderField'), $this->aProperties['order_by']);
$oForm->AddField($oSelectorField);
$oSelectorField->SetMandatory();
foreach ($aOrderField as $sField => $sLabel) {
$oSubForm = new DesignerForm();
if ($sField == 'function') {
$oField = new DesignerIntegerField('limit', Dict::S('UI:DashletGroupBy:Prop-Limit'), $this->aProperties['limit']);
$oSubForm->AddField($oField);
}
$oSelectorField->AddSubForm($oSubForm, $sLabel, $sField);
}
$aOrderDirections = [
'asc' => Dict::S('UI:DashletGroupBy:Order:asc'),
'desc' => Dict::S('UI:DashletGroupBy:Order:desc'),
];
$sOrderDirection = empty($this->aProperties['order_direction']) ? $this->sOrderDirection : $this->aProperties['order_direction'];
$oField = new DesignerComboField('order_direction', Dict::S('UI:DashletGroupBy:Prop-OrderDirection'), $sOrderDirection);
$oField->SetMandatory();
$oField->SetAllowedValues($aOrderDirections);
$oForm->AddField($oField);
}
/**
* @return array
*/
protected function GetOrderBy()
{
if (is_null($this->sClass)) {
return [];
}
return [
$this->aProperties['group_by'] => $this->oModelReflection->GetLabel($this->sClass, $this->aProperties['group_by']),
'_itop_'.$this->aProperties['aggregation_function'].'_' => Dict::S('UI:GroupBy:'.$this->aProperties['aggregation_function']),
];
}
/**
* @param array $aFunctionAttributes
*
* @return array
*/
protected function GetAllowedFunctions($aFunctionAttributes)
{
$aFunctions = [];
if (!empty($aFunctionAttributes) || is_null($this->sClass)) {
$aFunctions['sum'] = Dict::S('UI:GroupBy:sum');
$aFunctions['avg'] = Dict::S('UI:GroupBy:avg');
$aFunctions['min'] = Dict::S('UI:GroupBy:min');
$aFunctions['max'] = Dict::S('UI:GroupBy:max');
}
return $aFunctions;
}
/**
* @param string $sOql
*
* @return array
*/
protected function GetNumericAttributes($sOql)
{
$aFunctionAttributes = [];
try {
$oQuery = $this->oModelReflection->GetQuery($sOql);
$sClass = $oQuery->GetClass();
if (is_null($sClass)) {
return $aFunctionAttributes;
}
foreach ($this->oModelReflection->ListAttributes($sClass) as $sAttCode => $sAttType) {
switch ($sAttType) {
case 'AttributeDecimal':
case 'AttributeDuration':
case 'AttributeInteger':
case 'AttributePercentage':
case 'AttributeSubItem': // TODO: Known limitation: no unit displayed (values in sec)
$sLabel = $this->oModelReflection->GetLabel($sClass, $sAttCode);
$aFunctionAttributes[$sAttCode] = $sLabel;
break;
}
}
} catch (Exception $e) {
// In case the OQL is bad
}
return $aFunctionAttributes;
}
/**
* @inheritdoc
*/
public function Update($aValues, $aUpdatedFields)
{
if (in_array('query', $aUpdatedFields)) {
try {
$sCurrQuery = $aValues['query'];
$oCurrSearch = $this->oModelReflection->GetQuery($sCurrQuery);
$sCurrClass = $oCurrSearch->GetClass();
$sPrevQuery = $this->aProperties['query'];
$oPrevSearch = $this->oModelReflection->GetQuery($sPrevQuery);
$sPrevClass = $oPrevSearch->GetClass();
if ($sCurrClass != $sPrevClass) {
$this->bFormRedrawNeeded = true;
// wrong but not necessary - unset($aUpdatedFields['group_by']);
$this->aProperties['group_by'] = '';
}
} catch (Exception $e) {
$this->bFormRedrawNeeded = true;
}
}
$oDashlet = parent::Update($aValues, $aUpdatedFields);
if (in_array('style', $aUpdatedFields)) {
switch ($aValues['style']) {
// Style changed, mutate to the specified type of chart
case 'pie':
$oDashlet = new DashletGroupByPie($this->oModelReflection, $this->sId);
break;
case 'bars':
$oDashlet = new DashletGroupByBars($this->oModelReflection, $this->sId);
break;
case 'table':
$oDashlet = new DashletGroupByTable($this->oModelReflection, $this->sId);
break;
}
$oDashlet->FromParams($aValues);
$oDashlet->bRedrawNeeded = true;
$oDashlet->bFormRedrawNeeded = true;
}
if (in_array('aggregation_attribute', $aUpdatedFields) || in_array('order_direction', $aUpdatedFields) || in_array('order_by', $aUpdatedFields) || in_array('limit', $aUpdatedFields)) {
$oDashlet->bRedrawNeeded = true;
}
if (in_array('group_by', $aUpdatedFields) || in_array('aggregation_function', $aUpdatedFields)) {
$oDashlet->bRedrawNeeded = true;
$oDashlet->bFormRedrawNeeded = true;
}
return $oDashlet;
}
/**
* @inheritdoc
*/
@@ -556,35 +265,4 @@ abstract class DashletGroupBy extends Dashlet
{
return true;
}
/**
* @inheritdoc
*/
public function GetPropertiesFieldsFromOQL(DesignerForm $oForm, $sOQL = null)
{
$oField = new DesignerTextField('title', Dict::S('UI:DashletGroupBy:Prop-Title'), '');
$oForm->AddField($oField);
$oField = new DesignerHiddenField('query', Dict::S('UI:DashletGroupBy:Prop-Query'), $sOQL);
$oField->SetMandatory();
$oField->AddCSSClass("ibo-query-oql");
$oField->AddCSSClass("ibo-is-code");
$oForm->AddField($oField);
if (!is_null($sOQL)) {
$oField = new DesignerComboField('group_by', Dict::S('UI:DashletGroupBy:Prop-GroupBy'), null);
$aGroupBy = $this->GetGroupByOptions($sOQL);
$oField->SetAllowedValues($aGroupBy);
} else {
// Creating a form for reading parameters!
$oField = new DesignerTextField('group_by', Dict::S('UI:DashletGroupBy:Prop-GroupBy'), null);
}
$oField->SetMandatory();
$oForm->AddField($oField);
$oField = new DesignerHiddenField('style', '', $this->aProperties['style']);
$oField->SetMandatory();
$oForm->AddField($oField);
}
}

View File

@@ -33,80 +33,4 @@ class DashletGroupByBars extends DashletGroupBy
parent::__construct($oModelReflection, $sId);
$this->aProperties['style'] = 'bars';
}
/**
* @inheritdoc
*/
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = [])
{
$oDashletContainer = new DashletContainer(null, ['dashlet-content']);
$sTitle = $this->aProperties['title'];
$sBlockId = 'block_fake_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
$HTMLsTitle = ($sTitle != '') ? '<h1 style="text-align:center">'.utils::HtmlEntities($sTitle).'</h1>' : '';
$oDashletContainer->AddHtml("<div style=\"background-color:#fff;padding:0.25em;\">$HTMLsTitle<div id=\"$sBlockId\" style=\"background-color:#fff;\"></div></div>");
$aDisplayValues = $this->MakeSimulatedData();
$aNames = [];
foreach ($aDisplayValues as $idx => $aValue) {
$aNames[$idx] = $aValue['label'];
}
$sJSNames = json_encode($aNames);
$sJson = json_encode($aDisplayValues);
$oPage->add_ready_script(
<<<EOF
window.setTimeout(function() {
var chart = c3.generate({
bindto: '#{$sBlockId}',
data: {
json: $sJson,
keys: {
x: 'label',
value: ["value"]
},
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 = $sJSNames;
return aNames[index];
}
}
}
});
}, 100);
EOF
);
return $oDashletContainer;
}
}

View File

@@ -56,54 +56,4 @@ class DashletGroupByPie extends DashletGroupBy
WebResourcesHelper::GetCSSFilesRelPathsForC3JS()
);
}
/**
* @inheritdoc
*/
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = [])
{
$oDashletContainer = new DashletContainer(null, ['dashlet-content']);
$sTitle = $this->aProperties['title'];
$sBlockId = 'block_fake_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
$HTMLsTitle = ($sTitle != '') ? '<h1 style="text-align:center">'.utils::HtmlEntities($sTitle).'</h1>' : '';
$oDashletContainer->AddHtml("<div style=\"background-color:#fff;padding:0.25em;\">$HTMLsTitle<div id=\"$sBlockId\" style=\"background-color:#fff;\"></div></div>");
$aDisplayValues = $this->MakeSimulatedData();
$aColumns = [];
$aNames = [];
foreach ($aDisplayValues as $idx => $aValue) {
$aColumns[] = ['series_'.$idx, (int)$aValue['value']];
$aNames['series_'.$idx] = $aValue['label'];
}
$sJSColumns = json_encode($aColumns);
$sJSNames = json_encode($aNames);
$oPage->add_ready_script(
<<<EOF
window.setTimeout(function() {
var chart = c3.generate({
bindto: '#{$sBlockId}',
data: {
columns: $sJSColumns,
type: 'pie',
names: $sJSNames,
},
legend: {
show: true,
position: 'right',
},
tooltip: {
format: {
value: function (value, ratio, id) { return value; }
}
}
});}, 100);
EOF
);
return $oDashletContainer;
}
}

View File

@@ -32,48 +32,4 @@ class DashletGroupByTable extends DashletGroupBy
parent::__construct($oModelReflection, $sId);
$this->aProperties['style'] = 'table';
}
/**
* @inheritdoc
*/
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = [])
{
$oDashletContainer = new DashletContainer();
$aDisplayValues = $this->MakeSimulatedData();
$iTotal = 0;
foreach ($aDisplayValues as $iRow => $aDisplayData) {
$iTotal += $aDisplayData['value'];
}
$sBlockId = 'block_fake_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
$sHtml = '';
$sHtml .= '<div id="'.$sBlockId.'" class="display_block">';
$sHtml .= '<div class="dashlet-content">';
$sHtml .= '<p>'.Dict::Format('UI:Pagination:HeaderNoSelection', $iTotal).'</p>';
$sHtml .= '<table class="listResults">';
$sHtml .= '<thead>';
$sHtml .= '<tr>';
$sHtml .= '<th class="header" title="">'.$this->sGroupByLabel.'</th>';
$sHtml .= '<th class="header" title="'.Dict::S('UI:GroupBy:Count+').'">'.Dict::S('UI:GroupBy:Count').'</th>';
$sHtml .= '</tr>';
$sHtml .= '</thead>';
$sHtml .= '<tbody>';
foreach ($aDisplayValues as $aDisplayData) {
$sHtml .= '<tr class="even">';
$sHtml .= '<td class=""><span title="Active">'.$aDisplayData['label'].'</span></td>';
$sHtml .= '<td class=""><a>'.$aDisplayData['value'].'</a></td>';
$sHtml .= '</tr>';
}
$sHtml .= '</tbody>';
$sHtml .= '</table>';
$sHtml .= '</div>';
$sHtml .= '</div>';
$oDashletContainer->AddHtml($sHtml);
return $oDashletContainer;
}
}

View File

@@ -149,178 +149,4 @@ class DashletHeaderDynamic extends Dashlet
return $oPanel;
}
/**
* @inheritdoc
*/
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = [])
{
$sTitle = utils::HtmlEntities($this->aProperties['title']);
$sIcon = $this->aProperties['icon'];
$sSubtitle = utils::HtmlEntities($this->aProperties['subtitle']);
$sQuery = $this->aProperties['query'];
$sGroupBy = $this->aProperties['group_by'];
$aValueLabels = [];
$aValues = [];
try {
$oQuery = $this->oModelReflection->GetQuery($sQuery);
$sClass = $oQuery->GetClass();
$aValues = $this->GetValues();
foreach ($aValues as $sValue) {
$aValueLabels[] = $this->oModelReflection->GetValueLabel($sClass, $sGroupBy, $sValue);
}
} catch (UnknownClassOqlException $e) {
$aValueLabels[] = $e->GetUserFriendlyDescription();
$aValues[] = 1;
}
$oIconSelect = $this->oModelReflection->GetIconSelectionField('icon');
$sIconPath = utils::HtmlEntities($oIconSelect->MakeFileUrl($sIcon));
$oDashletContainer = new DashletContainer(null, ['dashlet-content']);
$sHtml = '';
$sHtml .= '<img src="'.$sIconPath.'">';
$sBlockId = 'block_fake_'.$this->sId.($bEditMode ? '_edit' : ''); // make a unique id (edition occuring in the same DOM)
$iTotal = 0;
$sHtml .= '<div class="display_block" id="'.$sBlockId.'">';
$sHtml .= '<div class="summary-details">';
$sHtml .= '<table><tbody>';
$sHtml .= '<tr>';
foreach ($aValueLabels as $sValueLabel) {
$sHtml .= ' <th>'.$sValueLabel.'</th>';
}
$sHtml .= '</tr>';
$sHtml .= '<tr>';
foreach ($aValues as $sValue) {
$iCount = rand(2, 100);
$iTotal += $iCount;
$sHtml .= ' <td>'.$iCount.'</td>';
}
$sHtml .= '</tr>';
$sHtml .= '</tbody></table>';
$sHtml .= '</div>';
$sTitle = $this->oModelReflection->DictString($sTitle);
$sSubtitle = $this->oModelReflection->DictFormat($sSubtitle, $iTotal);
$sHtml .= '<h1>'.utils::HtmlEntities($sTitle).'</h1>';
$sHtml .= '<a class="summary">'.utils::HtmlEntities($sSubtitle).'</a>';
$sHtml .= '</div>';
$oDashletContainer->AddHtml($sHtml);
return $oDashletContainer;
}
/**
* @inheritdoc
*/
public function GetPropertiesFields(DesignerForm $oForm)
{
$oField = new DesignerTextField('title', Dict::S('UI:DashletHeaderDynamic:Prop-Title'), $this->aProperties['title']);
$oForm->AddField($oField);
$oField = $this->oModelReflection->GetIconSelectionField('icon', Dict::S('UI:DashletHeaderDynamic:Prop-Icon'), $this->aProperties['icon']);
$oField->AddAllowedValue(['value' => '', 'label' => Dict::S('UI:DashletIcon:None'), 'icon' => '']);
$oForm->AddField($oField);
$oField = new DesignerTextField('subtitle', Dict::S('UI:DashletHeaderDynamic:Prop-Subtitle'), $this->aProperties['subtitle']);
$oForm->AddField($oField);
$oField = new DesignerLongTextField('query', Dict::S('UI:DashletHeaderDynamic:Prop-Query'), $this->aProperties['query']);
$oField->SetMandatory();
$oField->AddCSSClass("ibo-query-oql");
$oField->AddCSSClass("ibo-is-code");
$oForm->AddField($oField);
try {
// Group by field: build the list of possible values (attribute codes + ...)
$oQuery = $this->oModelReflection->GetQuery($this->aProperties['query']);
$sClass = $oQuery->GetClass();
$aGroupBy = $this->GetGroupByOptions($this->aProperties['query']);
$oField = new DesignerComboField('group_by', Dict::S('UI:DashletHeaderDynamic:Prop-GroupBy'), $this->aProperties['group_by']);
$oField->SetMandatory();
$oField->SetAllowedValues($aGroupBy);
} catch (Exception $e) {
$oField = new DesignerTextField('group_by', Dict::S('UI:DashletHeaderDynamic:Prop-GroupBy'), $this->aProperties['group_by']);
$oField->SetReadOnly();
}
$oForm->AddField($oField);
$oField = new DesignerComboField('values', Dict::S('UI:DashletHeaderDynamic:Prop-Values'), $this->aProperties['values']);
$oField->MultipleSelection(true);
if (isset($sClass) && $this->oModelReflection->IsValidAttCode($sClass, $this->aProperties['group_by'])) {
$aValues = $this->oModelReflection->GetAllowedValues_att($sClass, $this->aProperties['group_by']);
$oField->SetAllowedValues($aValues);
} else {
$oField->SetReadOnly();
}
$oForm->AddField($oField);
}
/**
* @inheritdoc
*/
public function Update($aValues, $aUpdatedFields)
{
if (in_array('query', $aUpdatedFields)) {
try {
$sCurrQuery = $aValues['query'];
$oCurrSearch = $this->oModelReflection->GetQuery($sCurrQuery);
$sCurrClass = $oCurrSearch->GetClass();
$sPrevQuery = $this->aProperties['query'];
$oPrevSearch = $this->oModelReflection->GetQuery($sPrevQuery);
$sPrevClass = $oPrevSearch->GetClass();
if ($sCurrClass != $sPrevClass) {
$this->bFormRedrawNeeded = true;
// wrong but not necessary - unset($aUpdatedFields['group_by']);
$this->aProperties['group_by'] = '';
$this->aProperties['values'] = [];
}
} catch (Exception $e) {
$this->bFormRedrawNeeded = true;
}
}
if (in_array('group_by', $aUpdatedFields)) {
$this->bFormRedrawNeeded = true;
$this->aProperties['values'] = [];
}
return parent::Update($aValues, $aUpdatedFields);
}
/**
* @inheritdoc
*/
protected function PropertyFromDOMNode($oDOMNode, $sProperty)
{
if ($sProperty == 'icon') {
$oIconField = $this->oModelReflection->GetIconSelectionField('icon');
return $oIconField->ValueFromDOMNode($oDOMNode);
} else {
return parent::PropertyFromDOMNode($oDOMNode, $sProperty);
}
}
/**
* @inheritdoc
*/
protected function PropertyToDOMNode($oDOMNode, $sProperty, $value)
{
if ($sProperty == 'icon') {
$oIconField = $this->oModelReflection->GetIconSelectionField('icon');
$oIconField->ValueToDOMNode($oDOMNode, $value);
} else {
parent::PropertyToDOMNode($oDOMNode, $sProperty, $value);
}
}
}

View File

@@ -55,44 +55,4 @@ class DashletHeaderStatic extends Dashlet
return DashletFactory::MakeForDashletHeaderStatic($this->oModelReflection->DictString($sTitle), $sIconPath);
}
/**
* @inheritdoc
*/
public function GetPropertiesFields(DesignerForm $oForm)
{
$oField = new DesignerTextField('title', Dict::S('UI:DashletHeaderStatic:Prop-Title'), $this->aProperties['title']);
$oForm->AddField($oField);
$oField = $this->oModelReflection->GetIconSelectionField('icon', Dict::S('UI:DashletHeaderStatic:Prop-Icon'), $this->aProperties['icon']);
$oField->AddAllowedValue(['value' => '', 'label' => Dict::S('UI:DashletIcon:None'), 'icon' => '']);
$oForm->AddField($oField);
}
/**
* @inheritdoc
*/
protected function PropertyFromDOMNode($oDOMNode, $sProperty)
{
if ($sProperty == 'icon') {
$oIconField = $this->oModelReflection->GetIconSelectionField('icon');
return $oIconField->ValueFromDOMNode($oDOMNode);
} else {
return parent::PropertyFromDOMNode($oDOMNode, $sProperty);
}
}
/**
* @inheritdoc
*/
protected function PropertyToDOMNode($oDOMNode, $sProperty, $value)
{
if ($sProperty == 'icon') {
$oIconField = $this->oModelReflection->GetIconSelectionField('icon');
$oIconField->ValueToDOMNode($oDOMNode, $value);
} else {
parent::PropertyToDOMNode($oDOMNode, $sProperty, $value);
}
}
}

View File

@@ -77,44 +77,6 @@ class DashletObjectList extends Dashlet
return $oPanel;
}
/**
* @inheritdoc
*/
public function RenderNoData($oPage, $bEditMode = false, $aExtraParams = [])
{
$oDashletContainer = new DashletContainer($this->sId, ['dashlet-content']);
$sTitle = $this->aProperties['title'];
$sQuery = $this->aProperties['query'];
$bShowMenu = $this->aProperties['menu'];
$sHtmlTitle = utils::HtmlEntities($this->oModelReflection->DictString($sTitle));
if ($sHtmlTitle != '') {
$sHtmlTitle = '<h1>'.$sHtmlTitle.'</h1>';
}
$oQuery = $this->oModelReflection->GetQuery($sQuery);
$sClass = $oQuery->GetClass();
$sId = $this->sId;
$sMessage = Dict::S('UI:NoObjectToDisplay');
$sMenu = '';
if ($bShowMenu) {
$sMenu = '<p><a>'.Dict::Format('UI:ClickToCreateNew', $this->oModelReflection->GetName($sClass)).'</a></p>';
}
$sHtml = <<<HTML
<div class="dashlet-content">
<h1>$sHtmlTitle</h1>
<div id="block_fake_$sId" class="display_block">
<p>$sMessage</p>
$sMenu
</div>
</div>
HTML;
$oDashletContainer->AddHtml($sHtml);
return $oDashletContainer;
}
public function GetDBSearch($aExtraParams = [])
{
$sQuery = $this->aProperties['query'];
@@ -130,24 +92,6 @@ HTML;
return DBObjectSearch::FromOQL($sQuery, $aQueryParams);
}
/**
* @inheritdoc
*/
public function GetPropertiesFields(DesignerForm $oForm)
{
$oField = new DesignerTextField('title', Dict::S('UI:DashletObjectList:Prop-Title'), $this->aProperties['title']);
$oForm->AddField($oField);
$oField = new DesignerLongTextField('query', Dict::S('UI:DashletObjectList:Prop-Query'), $this->aProperties['query']);
$oField->SetMandatory();
$oField->AddCSSClass("ibo-query-oql");
$oField->AddCSSClass("ibo-is-code");
$oForm->AddField($oField);
$oField = new DesignerBooleanField('menu', Dict::S('UI:DashletObjectList:Prop-Menu'), $this->aProperties['menu']);
$oForm->AddField($oField);
}
/**
* @inheritdoc
*/
@@ -155,22 +99,4 @@ HTML;
{
return true;
}
/**
* @inheritdoc
*/
public function GetPropertiesFieldsFromOQL(DesignerForm $oForm, $sOQL = null)
{
$oField = new DesignerTextField('title', Dict::S('UI:DashletObjectList:Prop-Title'), '');
$oForm->AddField($oField);
$oField = new DesignerHiddenField('query', Dict::S('UI:DashletObjectList:Prop-Query'), $sOQL);
$oField->SetMandatory();
$oField->AddCSSClass("ibo-query-oql");
$oField->AddCSSClass("ibo-is-code");
$oForm->AddField($oField);
$oField = new DesignerBooleanField('menu', Dict::S('UI:DashletObjectList:Prop-Menu'), $this->aProperties['menu']);
$oForm->AddField($oField);
}
}

View File

@@ -50,14 +50,4 @@ class DashletPlainText extends Dashlet
return DashletFactory::MakeForDashletPlainText($sText, $sId);
}
/**
* @inheritdoc
*/
public function GetPropertiesFields(DesignerForm $oForm)
{
$oField = new DesignerLongTextField('text', Dict::S('UI:DashletPlainText:Prop-Text'), $this->aProperties['text']);
$oField->SetMandatory();
$oForm->AddField($oField);
}
}