Allow dashboard to refresh from backend, or refresh with new data format when switching from custom to default

This commit is contained in:
Stephen Abello
2026-02-03 09:15:41 +01:00
parent 2ff183a78a
commit 73e6a0af8a
6 changed files with 190 additions and 53 deletions

View File

@@ -18,7 +18,10 @@ use Combodo\iTop\Application\UI\Base\Layout\UIContentBlockUIBlockFactory;
use Combodo\iTop\Application\WebPage\AjaxPage;
use Combodo\iTop\Application\WebPage\DownloadPage;
use Combodo\iTop\Application\WebPage\JsonPage;
use Combodo\iTop\DesignDocument;
use Combodo\iTop\DesignElement;
use Combodo\iTop\Forms\Block\FormBlockService;
use Combodo\iTop\PropertyType\PropertyTypeDesign;
use Combodo\iTop\PropertyType\Serializer\XMLSerializer;
use Combodo\iTop\Service\ServiceLocator\ServiceLocator;
use DBObjectSearch;
@@ -163,7 +166,7 @@ class DashboardController extends Controller
throw new SecurityException('Invalid dashboard file !');
}
if (!appUserPreferences::GetPref('display_original_dashboard_'.$sDashboardId, false)) {
if (!filter_var(appUserPreferences::GetPref('display_original_dashboard_'.$sDashboardId, false), FILTER_VALIDATE_BOOLEAN)) {
// Search for an eventual user defined dashboard
$oUDSearch = new DBObjectSearch('UserDashboard');
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
@@ -192,6 +195,85 @@ class DashboardController extends Controller
return $oPage;
}
public function OperationLoad()
{
$sDashboardId = utils::ReadParam('id', '', false, utils::ENUM_SANITIZATION_FILTER_RAW_DATA);
$bIsCustom = utils::ReadParam('is_custom', 'false', false, utils::ENUM_SANITIZATION_FILTER_RAW_DATA) === 'true';
$sDashboardFile = APPROOT.utils::ReadParam('file', '', false, utils::ENUM_SANITIZATION_FILTER_RAW_DATA);
$sDashboardFileSanitized = utils::RealPath($sDashboardFile, APPROOT);
if (false === $sDashboardFileSanitized) {
throw new SecurityException('Invalid dashboard file !');
}
$sStatus = 'error';
$sMessage = 'Unknown error';
$aData = [];
try {
if ($bIsCustom) {
// Search for an eventual user defined dashboard
$oUDSearch = new DBObjectSearch('UserDashboard');
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
$oUDSearch->AddCondition('menu_code', $sDashboardId, '=');
$oUDSet = new DBObjectSet($oUDSearch);
if ($oUDSet->Count() > 0) {
// Assuming there is at most one couple {user, menu}!
$oUserDashboard = $oUDSet->Fetch();
$sDashboardDefinition = $oUserDashboard->Get('contents');
} else {
$sDashboardDefinition = @file_get_contents($sDashboardFileSanitized);
}
}
else {
$sDashboardDefinition = @file_get_contents($sDashboardFileSanitized);
}
// TODO 3.3 If the dashboard definition is previous schema, we need to convert it to the new one
$oDoc = new PropertyTypeDesign();
$oDoc->loadXML($sDashboardDefinition);
$oMainNode = $oDoc->getElementsByTagName('dashboard')->item(0);
$aData = $this->oXMLSerializer->Deserialize($oMainNode, 'DashboardGrid', 'Dashboard');
// TODO 3.3 Re-render every dashlet to have their latest representation
// Let's render every dashlet to prevent frontend from having to do it for each in individual ajax call
// if (array_key_exists('pos_dashlets', $aData)) {
// foreach ($aData['pos_dashlets'] as $sDashletId => $sPosValues) {
// if(array_key_exists('dashlet', $sPosValues)) {
// $sDashletClass = $sPosValues['dashlet']['type'];
// $aValues = $sPosValues['dashlet']['properties'];
//
// $oDashlet = DashletFactory::GetInstance()->CreateDashlet($sDashletClass, $sDashletId);
// $oDashlet->FromModelData($aValues);
//
//
// }
// }
// }
$sStatus = 'ok';
$sMessage = 'Dashboard loaded';
} catch (Exception $e) {
IssueLog::Exception($e->getMessage(), $e);
$sStatus = 'error';
$sMessage = $e->getMessage();
}
$oPage = new JsonPage();
$oPage->SetData([
'status' => $sStatus,
'message' => $sMessage,
'data' => $aData
]);
$oPage->SetOutputDataOnly(true);
return $oPage;
}
public function OperationImport()
{
$oPage = new JsonPage();

View File

@@ -364,6 +364,8 @@ abstract class Dashboard
}
$oDashboard = $oLayout->Render($oPage, $aDashlets, $bEditMode, $aExtraParams);
$oDashboard->SetFile(utils::LocalPath($this->GetDefinitionFile()));
$oPage->AddUiBlock($oDashboard);
$bFromDashboardPage = isset($aExtraParams['from_dashboard_page']) ? isset($aExtraParams['from_dashboard_page']) : false;

View File

@@ -245,6 +245,10 @@ class RuntimeDashboard extends Dashboard
$oDashboard = parent::Render($oPage, $bEditMode, $aRenderParams);
if($this->HasCustomDashboard() && !filter_var(appUserPreferences::GetPref('display_original_dashboard_'.$this->GetId(), false), FILTER_VALIDATE_BOOLEAN)) {
$oDashboard->SetIsCustom(true);
}
if (isset($aExtraParams['query_params']['this->object()'])) {
/** @var \DBObject $oObj */
$oObj = $aExtraParams['query_params']['this->object()'];
@@ -321,15 +325,12 @@ EOF
$sSwitchToStandard = Dict::S('UI:Toggle:SwitchToStandardDashboard');
$sSwitchToCustom = Dict::S('UI:Toggle:SwitchToCustomDashboard');
$bStandardSelected = appUserPreferences::GetPref('display_original_dashboard_'.$sId, false);
$bStandardSelected = filter_var(appUserPreferences::GetPref('display_original_dashboard_'.$sId, false), FILTER_VALIDATE_BOOLEAN);
$sSelectorHtml = '<div id="ibo-dashboard-selector'.$sDivId.'" class="ibo-dashboard--selector" data-tooltip-content="'.($bStandardSelected ? $sSwitchToCustom : $sSwitchToStandard).'">';
$sSelectorHtml .= '<label class="ibo-dashboard--switch"><input type="checkbox" onchange="ToggleDashboardSelector'.$sDivId.'();" '.($bStandardSelected ? '' : 'checked').'><span class="ibo-dashboard--slider"></span></label></input></label>';
$sSelectorHtml = '<div class="ibo-dashboard--selector" data-dashboard-id="'.$sDivId.'" data-tooltip-content="'.($bStandardSelected ? $sSwitchToCustom : $sSwitchToStandard).'">';
$sSelectorHtml .= '<label class="ibo-dashboard--switch"><input type="checkbox" '.($bStandardSelected ? '' : 'checked').'><span class="ibo-dashboard--slider"></span></label></input></label>';
$sSelectorHtml .= '</div>';
$sFile = addslashes($this->GetDefinitionFile());
$sReloadURL = json_encode($this->GetReloadURL());
$bFromDashboardPage = isset($aAjaxParams['from_dashboard_page']) ? isset($aAjaxParams['from_dashboard_page']) : false;
if ($bFromDashboardPage) {
if ($oPage instanceof iTopWebPage) {
@@ -340,29 +341,6 @@ EOF
$oToolbar = $oDashboard->GetToolbar();
$oToolbar->AddHtml($sSelectorHtml);
}
$oPage->add_script(
<<<JS
function ToggleDashboardSelector$sDivId()
{
var dashboard = $('.ibo-dashboard#$sDivId')
dashboard.block();
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php',
{ operation: 'toggle_dashboard', dashboard_id: '$sId', file: '$sFile', extra_params: $sExtraParams, reload_url: '$sReloadURL' },
function(data) {
dashboard.html(data);
dashboard.unblock();
if ($('#ibo-dashboard-selector$sDivId input').prop("checked")) {
$('#ibo-dashboard-selector$sDivId').attr('data-tooltip-content', '$sSwitchToStandard');
} else {
$('#ibo-dashboard-selector$sDivId').attr('data-tooltip-content', '$sSwitchToCustom');
}
CombodoTooltip.InitAllNonInstantiatedTooltips($('#ibo-dashboard-selector$sDivId').parent(), true);
}
);
}
JS
);
}
/**
@@ -370,6 +348,7 @@ JS
*/
protected function HasCustomDashboard()
{
// TODO 3.3 Make it more efficient by caching the result
try {
// Search for an eventual user defined dashboard
$oUDSearch = new DBObjectSearch('UserDashboard');