N°9167 Use ExtensionDetails UIBlocks instead of table

This commit is contained in:
Timmy38
2026-05-12 12:01:41 +02:00
parent fb7a38c83f
commit b3b7fef6e4
11 changed files with 189 additions and 122 deletions

View File

@@ -63,3 +63,14 @@ $ibo-extension-details--actions--button--padding-x: $ibo-button--padding-x !defa
.ibo-extension-details--actions:has(.toggler-install:not(:disabled)) .ibo-popover-menu--section a[data-resource-id="force_uninstall"] { .ibo-extension-details--actions:has(.toggler-install:not(:disabled)) .ibo-popover-menu--section a[data-resource-id="force_uninstall"] {
display: none; display: none;
} }
.ibo-extension-details .ibo-popover-menu ~ .ibo-button{
visibility: hidden;
}
.ibo-extension-details .ibo-popover-menu:has(.ibo-popover-menu--item) ~ .ibo-button{
visibility: visible;
}
.ibo-extension-details .ibo-toggler--wrapper:has(.ibo-toggler.ibo-is-hidden){
visibility: hidden;
}

View File

@@ -11,6 +11,8 @@ require_once APPROOT.'setup/feature_removal/SetupAudit.php';
require_once APPROOT.'setup/feature_removal/DryRemovalRuntimeEnvironment.php'; require_once APPROOT.'setup/feature_removal/DryRemovalRuntimeEnvironment.php';
use Combodo\iTop\Application\TwigBase\Controller\Controller; use Combodo\iTop\Application\TwigBase\Controller\Controller;
use Combodo\iTop\Application\UI\Base\Layout\Extension\ExtensionDetailsUIBlockFactory;
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalConfig;
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalException; use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalException;
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalHelper; use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalHelper;
use Combodo\iTop\DataFeatureRemoval\Service\DataCleanupService; use Combodo\iTop\DataFeatureRemoval\Service\DataCleanupService;
@@ -27,18 +29,22 @@ use utils;
class DataFeatureRemovalController extends Controller class DataFeatureRemovalController extends Controller
{ {
private array $aSelectedExtensionsForCheck = []; private array $aSelectedExtensionsForCheck = [];
private ?array $aExtensionsToCheck = null;
private bool $bForcedUninstallation = false;
private array $aCountClassesToCleanup = []; private array $aCountClassesToCleanup = [];
private array $aAnalysisDataTable = []; private array $aAnalysisDataTable = [];
private int $iCount = 0; private int $iCount = 0;
private int $iColumnCount = 2;
public function OperationMain($sErrorMessage = null): void public function OperationMain($sErrorMessage = null): void
{ {
$aParams = []; $aParams = [];
$this->ReadRemovedExtensions();
$this->AddAnalyzeParams(); $this->AddAnalyzeParams();
$aParams['sTransactionId'] = utils::GetNewTransactionId(); $aParams['sTransactionId'] = utils::GetNewTransactionId();
$aParams['aExtensions'] = $this->GetExtensionsTableToSelect(); $aParams['iColumnCount'] = $this->iColumnCount;
$aParams['aAvailableExtensions'] = $this->SplitArrayIntoColumns($this->GetAvailableExtensions(), $this->iColumnCount);
$aParams['aAnalysisDataTable'] = $this->aAnalysisDataTable; $aParams['aAnalysisDataTable'] = $this->aAnalysisDataTable;
$aParams['aClasses'] = array_keys($this->aCountClassesToCleanup); $aParams['aClasses'] = array_keys($this->aCountClassesToCleanup);
$aParams['DataFeatureRemovalErrorMessage'] = $sErrorMessage; $aParams['DataFeatureRemovalErrorMessage'] = $sErrorMessage;
@@ -70,12 +76,11 @@ class DataFeatureRemovalController extends Controller
public function OperationAnalyze(): void public function OperationAnalyze(): void
{ {
$this->ReadRemovedExtensions(); $iCount = $this->ReadExtensionsDiff();
$this->m_sOperation = 'Main'; $this->m_sOperation = 'Main';
try { try {
if (count($this->aSelectedExtensionsForCheck) > 0) { if ($iCount > 0) {
$this->Analyze(); $this->Analyze();
} }
$this->OperationMain(); $this->OperationMain();
@@ -88,7 +93,7 @@ class DataFeatureRemovalController extends Controller
private function Analyze(): void private function Analyze(): void
{ {
$sSourceEnv = MetaModel::GetEnvironment(); $sSourceEnv = MetaModel::GetEnvironment();
$oDryRemovalRuntimeEnvironment = new DryRemovalRuntimeEnvironment($sSourceEnv, $this->aSelectedExtensionsForCheck); $oDryRemovalRuntimeEnvironment = new DryRemovalRuntimeEnvironment($sSourceEnv, $this->aExtensionsToCheck['to_be_removed']);
$oDryRemovalRuntimeEnvironment->CompileFrom($sSourceEnv); $oDryRemovalRuntimeEnvironment->CompileFrom($sSourceEnv);
$oSetupAudit = new SetupAudit($sSourceEnv); $oSetupAudit = new SetupAudit($sSourceEnv);
@@ -143,9 +148,9 @@ class DataFeatureRemovalController extends Controller
$aParams['aClasses'] = $aGetRemovedClasses; $aParams['aClasses'] = $aGetRemovedClasses;
$aParams['iQueryCount'] = $iQueryCount; $aParams['iQueryCount'] = $iQueryCount;
$aParams['bDeletionPossible'] = !$bHasIssues; $aParams['bDeletionPossible'] = !$bHasIssues;
$aParams['aAddedExtensions'] = $aAddedExtensions;
$aParams['aRemovedExtensions'] = $aRemovedExtensions; $aParams['iColumnCount'] = $this->iColumnCount;
$aParams['aExtensions'] = $this->GetExtensionsTableDiff($aAddedExtensions, $aRemovedExtensions); $aParams['aAvailableExtensions'] = $this->SplitArrayIntoColumns($this->GetExtensionsDiff($aAddedExtensions, $aRemovedExtensions), $this->iColumnCount);
$this->DisplayPage($aParams); $this->DisplayPage($aParams);
} }
@@ -209,72 +214,46 @@ class DataFeatureRemovalController extends Controller
$this->DisplayPage($aParams); $this->DisplayPage($aParams);
} }
private function GetExtensionsTableDiff(array $aAddedExtensions, array $aRemovedExtensions): array private function GetAvailableExtensions(): array
{ {
$aExtensions = []; $aExtensions = [];
$aColumns = ['', 'Name', 'code', 'Badge' ];
foreach ($aAddedExtensions as $sAddedExtensionCode => $sAddedExtensionLabel) {
$aExtensions[] = [
<<<HTML
<input type="checkbox" disabled class="extension_check" checked/>
HTML,
$sAddedExtensionLabel,
$sAddedExtensionCode,
Dict::S('UI:Layout:ExtensionsDetails:BadgeToBeInstalled'),
];
}
foreach ($aRemovedExtensions as $sAddedExtensionCode => $sAddedExtensionLabel) {
$aExtensions[] = [
<<<HTML
<input type="checkbox" disabled class="extension_check"/>
HTML,
$sAddedExtensionLabel,
$sAddedExtensionCode,
Dict::S('UI:Layout:ExtensionsDetails:BadgeToBeUninstalled'),
];
}
return $this->GetTableData('Extensions', $aColumns, $aExtensions);
}
/**
* Get installed extensions from disk
*
* @return array structure for twig datatable
*/
private function GetExtensionsTableToSelect(): array
{
$aExtensions = [];
$aColumns = ['', 'Version', 'Name', 'Code'];
foreach (DataFeatureRemoverExtensionService::GetInstance()->ReadItopExtensions() as $sCode => $oExtension) { foreach (DataFeatureRemoverExtensionService::GetInstance()->ReadItopExtensions() as $sCode => $oExtension) {
/** @var \iTopExtension $oExtension */ /** @var \iTopExtension $oExtension */
$aExtensions[$sCode] = [
'version' => $oExtension->sVersion,
'label' => $oExtension->sLabel,
'code' => $sCode,
'description' => $oExtension->sDescription,
'source' => $oExtension->GetExtensionSourceLabel(),
'installed' => $oExtension->bInstalled,
'extra_flags' => [
//'selected' => in_array($sCode, $this->aSelectedExtensionsForCheck),
'uninstallable' => $oExtension->CanBeUninstalled(),
'missing' => $oExtension->bRemovedFromDisk,
],
$sChecked = '';
$sDisabledHtml = '';
if ($oExtension->bRemovedFromDisk) {
$sDisabledHtml = 'disabled=""';
$sChecked = 'checked';
} elseif (in_array($sCode, $this->aSelectedExtensionsForCheck)) {
$sChecked = 'checked';
}
$sLabel = $oExtension->sLabel;
$sVersion = $oExtension->sVersion;
$sIdEnable = "aExtensions[$sCode][enable]";
$aExtensions[] = [
<<<HTML
<input type="checkbox" $sDisabledHtml class="extension_check" $sChecked id="$sIdEnable" name="$sIdEnable"/>
HTML,
$sVersion,
$sLabel,
$sCode,
]; ];
} }
return $this->GetTableData('Extensions', $aColumns, $aExtensions); return $aExtensions;
}
private function GetExtensionsDiff(array $aAddedExtensions, array $aRemovedExtensions): array
{
$aExtensions = [];
foreach ($this->GetAvailableExtensions() as $sCode => $aExtension) {
if (isset($aAddedExtensions[$sCode])) {
$aExtension['extra_flags']['selected'] = true;
$aExtension['extra_flags']['disabled'] = true;
$aExtensions[$sCode] = $aExtension;
} elseif (isset($aRemovedExtensions[$sCode])) {
$aExtension['extra_flags']['selected'] = false;
$aExtension['extra_flags']['disabled'] = true;
$aExtensions[$sCode] = $aExtension;
}
}
return $aExtensions;
} }
private function GetTableData(string $sTableName, array $aColumns, array $aData): array private function GetTableData(string $sTableName, array $aColumns, array $aData): array
@@ -318,27 +297,59 @@ HTML,
} }
/** /**
* @return void * Read extensions selected from posted parameters
* @return int Number of extensions to be added or removed
*/ */
public function ReadRemovedExtensions(): void public function ReadExtensionsDiff(): int
{ {
if (count($this->aSelectedExtensionsForCheck) > 0) { if (!is_null($this->aExtensionsToCheck)) {
return; return count($this->aExtensionsToCheck['to_be_installed']) + count($this->aExtensionsToCheck['to_be_removed']);
} }
$aSelectedExtensionsFromUI = utils::ReadPostedParam('aExtensions', []); $aAvailableExtensions = $this->GetAvailableExtensions();
foreach ($aSelectedExtensionsFromUI as $sCode => $aData) {
$sValue = $aData['enable'] ?? 'off'; $aSelectedExtensionsFromUI = utils::ReadPostedParam('aSelectedExtensions', []);
if (($sValue) === 'on') { $this->aExtensionsToCheck = [
$this->aSelectedExtensionsForCheck[] = $sCode; 'to_be_installed' => [],
'to_be_removed' => [],
];
foreach ($aAvailableExtensions as $sCode => &$aExtensionData) {
if (!isset($aSelectedExtensionsFromUI[$sCode])) {
continue;
} }
if ($aExtensionData['installed'] && $aSelectedExtensionsFromUI[$sCode] !== 'on') {
$aExtensionData['extra_flags']['selected'] = false;
$this->aExtensionsToCheck['to_be_removed'][] = $sCode;
if (!$aExtensionData['extra_flags']['uninstallable']) {
$this->bForcedUninstallation = true;
}
} elseif (!$aExtensionData['installed'] && $aSelectedExtensionsFromUI[$sCode] === 'on') {
$aExtensionData['extra_flags']['selected'] = true;
$this->aExtensionsToCheck['to_be_installed'][] = $sCode;
}
}
return count($this->aExtensionsToCheck['to_be_installed']) + count($this->aExtensionsToCheck['to_be_removed']);
}
/**
* Divide an array into several sub arrays, distributing elements so that every sub array has an equal number of elements
* @param array $aInput
* @param int $iColNumber
*
* @return array
*/
private function SplitArrayIntoColumns(array $aInput, int $iColNumber)
{
$aOutput = array_fill(0, $iColNumber, []);
$iIndex = 0;
foreach ($aInput as $mItem) {
//Split extensions in two columns
$aOutput[$iIndex % $this->iColumnCount][] = $mItem;
$iIndex++;
} }
// Add source removed to check return $aOutput;
foreach (DataFeatureRemoverExtensionService::GetInstance()->ReadItopExtensions() as $sCode => $oExtension) {
if ($oExtension->bRemovedFromDisk) {
$this->aSelectedExtensionsForCheck[] = $sCode;
}
}
} }
} }

View File

@@ -6,9 +6,21 @@
{% UIInput ForHidden {sName:'operation', sValue:'Analyze'} %} {% UIInput ForHidden {sName:'operation', sValue:'Analyze'} %}
{% UIInput ForHidden {sName:'transaction_id', sValue:sTransactionId} %} {% UIInput ForHidden {sName:'transaction_id', sValue:sTransactionId} %}
{% UIFieldSet Standard {sLegend:'DataFeatureRemoval:Features:Title'|dict_s} %} {% UIPanel Neutral { sTitle:'DataFeatureRemoval:Features:Title'|dict_s, sSubTitle: '' } %}
{% UIDataTable ForForm { sRef:'aExtensions', aColumns:aExtensions.Columns, aData:aExtensions.Data} %}{% EndUIDataTable %} {% UIMultiColumn Standard {} %}
{% EndUIFieldSet %} {% for iColumnIndex in 0..iColumnCount-1 %}
{% UIColumn Standard {} %}
{% for aExtension in aAvailableExtensions[iColumnIndex] %}
{% if aExtension['installed'] %}
{% UIExtensionDetails Installed { sCode : aExtension['code'], sLabel : aExtension['label'], sDescription : aExtension['description'], aMetaData : [aExtension['version'], aExtension['source']], aExtraFlags : aExtension['extra_flags']} %}{% EndUIExtensionDetails %}
{% else %}
{% UIExtensionDetails NotInstalled { sCode : aExtension['code'], sLabel : aExtension['label'], sDescription : aExtension['description'], aMetaData : [aExtension['version'], aExtension['source']], aExtraFlags : aExtension['extra_flags']} %}{% EndUIExtensionDetails %}
{% endif %}
{% endfor %}
{% EndUIColumn %}
{% endfor %}
{% EndUIMultiColumn %}
{% EndUIPanel %}
{% UIToolbar ForButton {} %} {% UIToolbar ForButton {} %}
{% UIButton ForPrimaryAction {sLabel:'UI:Button:Analyze'|dict_s, sName:'btn_apply', sId:'btn_apply', bIsSubmit:true} %} {% UIButton ForPrimaryAction {sLabel:'UI:Button:Analyze'|dict_s, sName:'btn_apply', sId:'btn_apply', bIsSubmit:true} %}

View File

@@ -437,7 +437,7 @@ class iTopExtensionsMap
'default' => true, // by default offer to install all modules 'default' => true, // by default offer to install all modules
'modules' => $oExtension->aModules, 'modules' => $oExtension->aModules,
'mandatory' => $oExtension->bMandatory, 'mandatory' => $oExtension->bMandatory,
'source_label' => $this->GetExtensionSourceLabel($oExtension->sSource), 'source_label' => $oExtension->GetExtensionSourceLabel(),
'uninstallable' => $oExtension->CanBeUninstalled(), 'uninstallable' => $oExtension->CanBeUninstalled(),
'missing' => $oExtension->bRemovedFromDisk, 'missing' => $oExtension->bRemovedFromDisk,
'version' => $oExtension->sVersion, 'version' => $oExtension->sVersion,
@@ -447,21 +447,7 @@ class iTopExtensionsMap
return $aRes; return $aRes;
} }
protected function GetExtensionSourceLabel($sSource)
{
$sResult = '';
switch ($sSource) {
case iTopExtension::SOURCE_MANUAL:
$sResult = 'Local extensions folder';
break;
case iTopExtension::SOURCE_REMOTE:
$sResult = (ITOP_APPLICATION == 'iTop') ? 'iTop Hub' : 'ITSM Designer';
break;
}
return $sResult;
}
/** /**
* Mark the given extension as chosen * Mark the given extension as chosen

View File

@@ -8,7 +8,7 @@ use SetupUtils;
class DryRemovalRuntimeEnvironment extends RunTimeEnvironment class DryRemovalRuntimeEnvironment extends RunTimeEnvironment
{ {
protected array $aExtensionsByCode; protected array $aExtensionsToRemoveByCode;
/** /**
* Toolset for building a run-time environment * Toolset for building a run-time environment
@@ -18,7 +18,7 @@ class DryRemovalRuntimeEnvironment extends RunTimeEnvironment
public function __construct($sSourceEnv = 'production', array $aExtensionCodesToRemove = []) public function __construct($sSourceEnv = 'production', array $aExtensionCodesToRemove = [])
{ {
parent::__construct($sSourceEnv, false); parent::__construct($sSourceEnv, false);
$this->aExtensionsByCode = $aExtensionCodesToRemove; $this->aExtensionsToRemoveByCode = $aExtensionCodesToRemove;
$this->Prepare($sSourceEnv, $this->sBuildEnv); $this->Prepare($sSourceEnv, $this->sBuildEnv);
} }
@@ -34,7 +34,7 @@ class DryRemovalRuntimeEnvironment extends RunTimeEnvironment
SetupUtils::copydir(APPROOT."/data/$sSourceEnv-modules", APPROOT."/data/$sBuildEnv-modules"); SetupUtils::copydir(APPROOT."/data/$sSourceEnv-modules", APPROOT."/data/$sBuildEnv-modules");
SetupUtils::copydir(APPROOT."/conf/$sSourceEnv", APPROOT."/conf/$sBuildEnv"); SetupUtils::copydir(APPROOT."/conf/$sSourceEnv", APPROOT."/conf/$sBuildEnv");
$this->DeclareExtensionAsRemoved($this->aExtensionsByCode); $this->DeclareExtensionAsRemoved($this->aExtensionsToRemoveByCode);
} }
private function DeclareExtensionAsRemoved(array $aExtensionCodes): void private function DeclareExtensionAsRemoved(array $aExtensionCodes): void

View File

@@ -141,4 +141,12 @@ class iTopExtension
} }
return true; return true;
} }
public function GetExtensionSourceLabel(): string {
return match ($this->sSource) {
iTopExtension::SOURCE_MANUAL => 'Local extensions folder',
iTopExtension::SOURCE_REMOTE => (ITOP_APPLICATION == 'iTop') ? 'iTop Hub' : 'ITSM Designer',
default => 'Unknown',
};
}
} }

View File

@@ -179,32 +179,37 @@ class ExtensionDetails extends UIContentBlock
protected function InitializeToggler() protected function InitializeToggler()
{ {
$sName = 'aSelectedExtensions['.$this->GetCode().']';
$this->oToggler = new Toggler(); $this->oToggler = new Toggler();
$this->oToggler->SetName('ExtensionToggler'); $this->oToggler->SetName($sName);
$this->oToggler->AddCSSClass('toggler-install'); $this->oToggler->AddCSSClass('toggler-install');
} }
protected function InitializePopoverMenu() protected function InitializePopoverMenu()
{ {
$sModalLabel = Dict::Format('UI:Layout:ExtensionsDetails:MenuAboutTitle', $this->sLabel);
$sModalText = $this->sAbout;
$oModifyButton = new JSButtonItem(
'extension_details',
Dict::S('UI:Layout:ExtensionsDetails:MenuAbout'),
<<<JS
CombodoModal.OpenModal({
title: '$sModalLabel',
content: '$sModalText',
});
JS,
);
$this->oPopoverMenu = new PopoverMenu(); $this->oPopoverMenu = new PopoverMenu();
$this->oPopoverMenu->AddItem('more-actions', PopoverMenuItemFactory::MakeFromApplicationPopupMenuItem($oModifyButton));
$oPopoverOpenButton = ButtonUIBlockFactory::MakeIconAction('fas fa-ellipsis-v', 'Show more actions'); $oPopoverOpenButton = ButtonUIBlockFactory::MakeIconAction('fas fa-ellipsis-v', 'Show more actions');
$this->oPopoverMenu->SetTogglerFromBlock($oPopoverOpenButton); $this->oPopoverMenu->SetTogglerFromBlock($oPopoverOpenButton);
$this->oMoreActions = new UIContentBlock(); $this->oMoreActions = new UIContentBlock();
$this->oMoreActions->AddSubBlock($this->oPopoverMenu); $this->oMoreActions->AddSubBlock($this->oPopoverMenu);
$this->oMoreActions->AddSubBlock($oPopoverOpenButton); $this->oMoreActions->AddSubBlock($oPopoverOpenButton);
if (mb_strlen($this->sAbout) > 0) {
$sModalLabel = Dict::Format('UI:Layout:ExtensionsDetails:MenuAboutTitle', $this->sLabel);
$sModalText = $this->sAbout;
$oModifyButton = new JSButtonItem(
'extension_details',
Dict::S('UI:Layout:ExtensionsDetails:MenuAbout'),
<<<JS
CombodoModal.OpenModal({
title: '$sModalLabel',
content: '$sModalText',
});
JS,
);
$this->oPopoverMenu->AddItem('more-actions', PopoverMenuItemFactory::MakeFromApplicationPopupMenuItem($oModifyButton));
}
} }
public function AllowForceUninstall() public function AllowForceUninstall()
@@ -213,7 +218,8 @@ JS,
'force_uninstall', 'force_uninstall',
Dict::S('UI:Layout:ExtensionsDetails:MenuForce'), Dict::S('UI:Layout:ExtensionsDetails:MenuForce'),
<<<JS <<<JS
this.closest('.ibo-extension-details').querySelector('input[type=checkbox]').disabled = false this.closest('.ibo-extension-details').querySelector('input[type=checkbox]').disabled = false;
this.remove();
JS, JS,
); );
$this->oPopoverMenu->AddItem('more-actions', PopoverMenuItemFactory::MakeFromApplicationPopupMenuItem($oForceUninstallButton)); $this->oPopoverMenu->AddItem('more-actions', PopoverMenuItemFactory::MakeFromApplicationPopupMenuItem($oForceUninstallButton));

View File

@@ -18,6 +18,8 @@ class ExtensionDetailsUIBlockFactory extends AbstractUIBlockFactory
$aBadges = []; $aBadges = [];
$bUninstallable = $aExtraFlags['uninstallable'] ?? true; $bUninstallable = $aExtraFlags['uninstallable'] ?? true;
$bMissingFromDisk = $aExtraFlags['missing'] ?? false; $bMissingFromDisk = $aExtraFlags['missing'] ?? false;
$bSelected = $aExtraFlags['selected'] ?? true;
$bDisabled = $aExtraFlags['disabled'] ?? false;
self::AddExtraBadges($aBadges, $bUninstallable, $bMissingFromDisk); self::AddExtraBadges($aBadges, $bUninstallable, $bMissingFromDisk);
$oBadgeInstalled = BadgeUIBlockFactory::MakeGreen(Dict::S('UI:Layout:ExtensionsDetails:BadgeInstalled')); $oBadgeInstalled = BadgeUIBlockFactory::MakeGreen(Dict::S('UI:Layout:ExtensionsDetails:BadgeInstalled'));
$oBadgeInstalled->AddCSSClass('checked'); $oBadgeInstalled->AddCSSClass('checked');
@@ -28,10 +30,23 @@ class ExtensionDetailsUIBlockFactory extends AbstractUIBlockFactory
$oExtensionDetails = new ExtensionDetails($sCode, $sLabel, $sDescription, $aMetaData, $aBadges, $sAbout); $oExtensionDetails = new ExtensionDetails($sCode, $sLabel, $sDescription, $aMetaData, $aBadges, $sAbout);
$oExtensionDetails->GetToggler()->SetIsToggled(true); $oExtensionDetails->GetToggler()->SetIsToggled(true);
if (!$bUninstallable) { if ($bMissingFromDisk) {
$oExtensionDetails->GetToggler()->SetIsToggled(false);
$oExtensionDetails->GetToggler()->SetIsDisabled(true);
}
else if (!$bUninstallable) {
$oExtensionDetails->AllowForceUninstall(); $oExtensionDetails->AllowForceUninstall();
$oExtensionDetails->GetToggler()->SetIsDisabled(true); $oExtensionDetails->GetToggler()->SetIsDisabled(true);
} }
if (!$bSelected) {
$oExtensionDetails->GetToggler()->SetIsToggled(false);
}
if ($bDisabled) {
$oExtensionDetails->GetToggler()->SetIsDisabled(true);
$oExtensionDetails->GetToggler()->AddCSSClass('ibo-is-hidden');
}
return $oExtensionDetails; return $oExtensionDetails;
} }
@@ -39,6 +54,8 @@ class ExtensionDetailsUIBlockFactory extends AbstractUIBlockFactory
{ {
$aBadges = []; $aBadges = [];
$bUninstallable = $aExtraFlags['uninstallable'] ?? true; $bUninstallable = $aExtraFlags['uninstallable'] ?? true;
$bSelected = $aExtraFlags['selected'] ?? false;
$bDisabled = $aExtraFlags['disabled'] ?? false;
self::AddExtraBadges($aBadges, $bUninstallable, false); self::AddExtraBadges($aBadges, $bUninstallable, false);
$oBadgeInstalled = BadgeUIBlockFactory::MakeGrey(Dict::S('UI:Layout:ExtensionsDetails:BadgeNotInstalled')); $oBadgeInstalled = BadgeUIBlockFactory::MakeGrey(Dict::S('UI:Layout:ExtensionsDetails:BadgeNotInstalled'));
$oBadgeInstalled->AddCSSClass('unchecked'); $oBadgeInstalled->AddCSSClass('unchecked');
@@ -46,8 +63,17 @@ class ExtensionDetailsUIBlockFactory extends AbstractUIBlockFactory
$oBadgeToBeUninstalled = BadgeUIBlockFactory::MakeCyan(Dict::S('UI:Layout:ExtensionsDetails:BadgeToBeInstalled')); $oBadgeToBeUninstalled = BadgeUIBlockFactory::MakeCyan(Dict::S('UI:Layout:ExtensionsDetails:BadgeToBeInstalled'));
$oBadgeToBeUninstalled->AddCSSClass('checked'); $oBadgeToBeUninstalled->AddCSSClass('checked');
$aBadges[] = $oBadgeToBeUninstalled; $aBadges[] = $oBadgeToBeUninstalled;
$oExtensionDetails = new ExtensionDetails($sCode, $sLabel, $sDescription, $aMetaData, $aBadges, $sAbout);
return new ExtensionDetails($sCode, $sLabel, $sDescription, $aMetaData, $aBadges, $sAbout); if ($bSelected) {
$oExtensionDetails->GetToggler()->SetIsToggled(true);
}
if ($bDisabled) {
$oExtensionDetails->GetToggler()->SetIsDisabled(true);
$oExtensionDetails->GetToggler()->AddCSSClass('ibo-is-hidden');
}
return $oExtensionDetails;
} }
private static function AddExtraBadges(array &$aBadges, bool $bUninstallable, bool $bMissingFromDisk) private static function AddExtraBadges(array &$aBadges, bool $bUninstallable, bool $bMissingFromDisk)

View File

@@ -1,7 +1,8 @@
{% extends "base/components/input/layout.html.twig" %} {% extends "base/components/input/layout.html.twig" %}
{% block iboInput %} {% block iboInput %}
<span class="ibo-toggler--wrapper"> <span class="ibo-toggler--wrapper">
{{ parent() }} {{ parent() }}
<span class="ibo-toggler--slider"></span> <span class="ibo-toggler--slider"></span>
<input class="ibo-toggler--hidden" type="hidden" name="{{ oUIBlock.GetName() }}" value="{% if oUIBlock.IsChecked() %}on{% else %}off{% endif %}"/>
</span> </span>
{% endblock %} {% endblock %}

View File

@@ -1,8 +1,10 @@
$('#{{ oUIBlock.GetId() }}').parent().on('click', function() { $('#{{ oUIBlock.GetId() }}').parent().on('click', function() {
let oInput = $(this).find('.ibo-toggler'); let oInput = $(this).find('.ibo-toggler');
let oHiddenInput = $(this).find('.ibo-toggler--hidden');
if (!oInput.prop('disabled')) { if (!oInput.prop('disabled')) {
oInput.prop('checked', !oInput.prop('checked')); oInput.prop('checked', !oInput.prop('checked'));
oHiddenInput.val(oInput.prop('checked') ? 'on' : 'off');
oInput.trigger('change'); oInput.trigger('change');
} }
}); });

View File

@@ -639,6 +639,10 @@ $oPage->AddUiBlock($oMultiCol);
$oExtensionDetailInstalledFromFactory = ExtensionDetailsUIBlockFactory::MakeInstalled('itop-sample', 'My extension v2', 'This is for test only', ['v1.1.1', 'Designer', '12/12/2012'], ['uninstallable' => false,'missing' => true]); $oExtensionDetailInstalledFromFactory = ExtensionDetailsUIBlockFactory::MakeInstalled('itop-sample', 'My extension v2', 'This is for test only', ['v1.1.1', 'Designer', '12/12/2012'], ['uninstallable' => false,'missing' => true]);
$oColumnLeft->AddSubBlock($oExtensionDetailInstalledFromFactory); $oColumnLeft->AddSubBlock($oExtensionDetailInstalledFromFactory);
$oExtensionDetailInstalledFromFactory = ExtensionDetailsUIBlockFactory::MakeInstalled('itop-not-uninstallable', 'You cannot uninstall me', 'Click force uninstall to uninstall me', ['v9.9.9', 'Void', '12/12/2012'], ['uninstallable' => false,'missing' => false]);
$oColumnLeft->AddSubBlock($oExtensionDetailInstalledFromFactory);
$oExtensionDetailInstalledWithLongTitle = ExtensionDetailsUIBlockFactory::MakeNotInstalled('itop-sample', 'My extension with a very long title', 'This is for test only', ['v1.1.1', 'Designer', '12/12/2012'], ['uninstallable' => false]); $oExtensionDetailInstalledWithLongTitle = ExtensionDetailsUIBlockFactory::MakeNotInstalled('itop-sample', 'My extension with a very long title', 'This is for test only', ['v1.1.1', 'Designer', '12/12/2012'], ['uninstallable' => false]);
$oColumnRight->AddSubBlock($oExtensionDetailInstalledWithLongTitle); $oColumnRight->AddSubBlock($oExtensionDetailInstalledWithLongTitle);
$oPage->add('<hr id="page_bottom"/>'); $oPage->add('<hr id="page_bottom"/>');