N°9167 Use ExtensionDetails UIBlocks instead of table

This commit is contained in:
Timmy38
2026-05-20 17:25:12 +02:00
parent 9bc2cd0a38
commit cdf7d62b13
4 changed files with 105 additions and 81 deletions

View File

@@ -31,20 +31,23 @@ use utils;
class DataFeatureRemovalController extends Controller class DataFeatureRemovalController extends Controller
{ {
private array $aRemovedExtensionsForCheck = []; private array $aRemovedExtensionsForCheck = [];
private ?array $aExtensionsToCheck = null;
private bool $bForcedUninstallation = false;
private array $aCountClassesToCleanup = []; private array $aCountClassesToCleanup = [];
private array $aAnalysisDataTable = []; private array $aAnalysisDataTable = [];
private array $aDeletionExecutionSummary = []; private array $aDeletionExecutionSummary = [];
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;
@@ -76,12 +79,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->aRemovedExtensionsForCheck) > 0) { if ($iCount > 0) {
$this->Analyze(); $this->Analyze();
} }
$this->OperationMain(); $this->OperationMain();
@@ -93,7 +95,8 @@ class DataFeatureRemovalController extends Controller
private function Analyze(): void private function Analyze(): void
{ {
$this->Compile($this->aRemovedExtensionsForCheck); //TODO : Run data audit with added extension too, not just removed ones
$this->Compile($this->aExtensionsToCheck['to_be_removed']);
$sSourceEnv = MetaModel::GetEnvironment(); $sSourceEnv = MetaModel::GetEnvironment();
$oSetupAudit = new SetupAudit($sSourceEnv); $oSetupAudit = new SetupAudit($sSourceEnv);
$aGetRemovedClasses = $oSetupAudit->RunDataAudit(); $aGetRemovedClasses = $oSetupAudit->RunDataAudit();
@@ -148,7 +151,8 @@ class DataFeatureRemovalController extends Controller
$aParams['sTransactionId'] = utils::GetNewTransactionId(); $aParams['sTransactionId'] = utils::GetNewTransactionId();
$aParams['aClasses'] = $aGetRemovedClasses; $aParams['aClasses'] = $aGetRemovedClasses;
$aParams['aExtensions'] = $this->GetExtensionsTableDiff($aAddedExtensions, $aRemovedExtensions); $aParams['iColumnCount'] = $this->iColumnCount;
$aParams['aAvailableExtensions'] = $this->SplitArrayIntoColumns($this->GetExtensionsDiff($aAddedExtensions, $aRemovedExtensions), $this->iColumnCount);
new ContextTag(ContextTag::TAG_SETUP); new ContextTag(ContextTag::TAG_SETUP);
$aParams['sLaunchSetupUrl'] = utils::GetAbsoluteUrlAppRoot().'setup/wizard.php'; $aParams['sLaunchSetupUrl'] = utils::GetAbsoluteUrlAppRoot().'setup/wizard.php';
@@ -261,72 +265,52 @@ class DataFeatureRemovalController extends Controller
$this->OperationAnalysisResult(); $this->OperationAnalysisResult();
} }
private function GetExtensionsTableDiff(array $aAddedExtensions, array $aRemovedExtensions): array private function GetAvailableExtensions(bool $bIncludePackageExtensions = false): array
{ {
$aExtensions = []; $aExtensionsData = [];
$aColumns = ['', 'Name', 'code', 'Badge' ]; if ($bIncludePackageExtensions) {
$aExtensionsRef = DataFeatureRemoverExtensionService::GetInstance()->GetExtensionMap()->GetAllExtensionsWithPreviouslyInstalled();
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) { else {
$aExtensions[] = [ $aExtensionsRef = DataFeatureRemoverExtensionService::GetInstance()->ReadItopExtensions();
<<<HTML
<input type="checkbox" disabled class="extension_check"/>
HTML,
$sAddedExtensionLabel,
$sAddedExtensionCode,
Dict::S('UI:Layout:ExtensionsDetails:BadgeToBeUninstalled'),
];
} }
return $this->GetTableData('Extensions', $aColumns, $aExtensions); foreach ($aExtensionsRef as $oExtension) {
}
/**
* 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) {
/** @var \iTopExtension $oExtension */ /** @var \iTopExtension $oExtension */
$aExtensionsData[$oExtension->sCode] = [
'version' => $oExtension->sVersion,
'label' => $oExtension->sLabel,
'code' => $oExtension->sCode,
'description' => $oExtension->sDescription,
'source' => $oExtension->GetExtensionSourceLabel(),
'installed' => $oExtension->bInstalled,
'extra_flags' => [
'uninstallable' => $oExtension->CanBeUninstalled(),
'remote' => $oExtension->IsRemote(),
'missing' => $oExtension->bRemovedFromDisk,
],
$sChecked = '';
$sDisabledHtml = '';
if ($oExtension->bRemovedFromDisk) {
$sDisabledHtml = 'disabled=""';
$sChecked = 'checked';
} elseif (in_array($sCode, $this->aRemovedExtensionsForCheck)) {
$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 $aExtensionsData;
}
private function GetExtensionsDiff(array $aAddedExtensions, array $aRemovedExtensions): array
{
$aExtensions = [];
foreach ($this->GetAvailableExtensions(true) as $sCode => $aExtension) {
$aExtension['extra_flags']['disabled'] = true;
if (isset($aAddedExtensions[$sCode])) {
$aExtension['extra_flags']['selected'] = true;
$aExtensions[$sCode] = $aExtension;
} elseif (isset($aRemovedExtensions[$sCode])) {
$aExtension['extra_flags']['selected'] = false;
$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
@@ -370,27 +354,56 @@ 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->aRemovedExtensionsForCheck) > 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) { $aSelectedExtensionsFromUI = utils::ReadPostedParam('aSelectedExtensions', []);
$sValue = $aData['enable'] ?? 'off'; $this->aExtensionsToCheck = [
if (($sValue) === 'on') { 'to_be_installed' => [],
$this->aRemovedExtensionsForCheck[] = $sCode; 'to_be_removed' => [],
} ];
foreach ($aAvailableExtensions as $sCode => &$aExtensionData) {
if (!isset($aSelectedExtensionsFromUI[$sCode])) {
continue;
} }
// Add source removed to check if ($aExtensionData['installed'] && $aSelectedExtensionsFromUI[$sCode] !== 'on') {
foreach (DataFeatureRemoverExtensionService::GetInstance()->ReadItopExtensions() as $sCode => $oExtension) { $aExtensionData['extra_flags']['selected'] = false;
if ($oExtension->bRemovedFromDisk) { $this->aExtensionsToCheck['to_be_removed'][] = $sCode;
$this->aRemovedExtensionsForCheck[] = $sCode; if (!$aExtensionData['extra_flags']['uninstallable'] || $aExtensionData['extra_flags']['remote']) {
$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 amount of elements
* @param mixed[] $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 $iColNumber columns
$aOutput[$iIndex % $this->iColumnCount][] = $mItem;
$iIndex++;
}
return $aOutput;
} }
} }

View File

@@ -14,7 +14,7 @@ use MetaModel;
class DataFeatureRemoverExtensionService class DataFeatureRemoverExtensionService
{ {
private static DataFeatureRemoverExtensionService $oInstance; private static DataFeatureRemoverExtensionService $oInstance;
private ?iTopExtensionsMap $oMap = null;
private array $aItopExtensions = []; private array $aItopExtensions = [];
private array $aIncludingExtensionsByModuleName = []; private array $aIncludingExtensionsByModuleName = [];
@@ -60,15 +60,25 @@ class DataFeatureRemoverExtensionService
return $this->aIncludingExtensionsByModuleName[$sModuleName] ?? []; return $this->aIncludingExtensionsByModuleName[$sModuleName] ?? [];
} }
/**
* @return \iTopExtensionsMap
*/
public function GetExtensionMap(): iTopExtensionsMap
{
if (is_null($this->oMap)) {
$this->oMap = new iTopExtensionsMap();
$this->oMap->LoadInstalledExtensionsFromDatabase(MetaModel::GetConfig());
}
return $this->oMap;
}
/** /**
* @return iTopExtension[] * @return iTopExtension[]
*/ */
public function ReadItopExtensions(): array public function ReadItopExtensions(): array
{ {
if (count($this->aItopExtensions) === 0) { if (count($this->aItopExtensions) === 0) {
$oExtensionsMap = new iTopExtensionsMap(); $this->aItopExtensions = $this->GetExtensionMap()->GetAllExtensionsToDisplayInSetup(true);
$oExtensionsMap->LoadInstalledExtensionsFromDatabase(MetaModel::GetConfig());
$this->aItopExtensions = $oExtensionsMap->GetAllExtensionsToDisplayInSetup(true);
uasort($this->aItopExtensions, function (iTopExtension $oiTopExtension1, iTopExtension $oiTopExtension2) { uasort($this->aItopExtensions, function (iTopExtension $oiTopExtension1, iTopExtension $oiTopExtension2) {
return strcmp($oiTopExtension1->sLabel, $oiTopExtension2->sLabel); return strcmp($oiTopExtension1->sLabel, $oiTopExtension2->sLabel);

View File

@@ -174,6 +174,7 @@ class iTopExtension
return match ($this->sSource) { return match ($this->sSource) {
self::SOURCE_MANUAL => 'Local extensions folder', self::SOURCE_MANUAL => 'Local extensions folder',
self::SOURCE_REMOTE => (ITOP_APPLICATION == 'iTop') ? 'iTop Hub' : 'ITSM Designer', self::SOURCE_REMOTE => (ITOP_APPLICATION == 'iTop') ? 'iTop Hub' : 'ITSM Designer',
self::SOURCE_WIZARD => 'iTop package',
default => '', default => '',
}; };
} }

View File

@@ -33,7 +33,7 @@ class ExtensionDetails extends UIContentBlock
$this->sCode = $sCode; $this->sCode = $sCode;
$this->sLabel = $sLabel; $this->sLabel = $sLabel;
$this->sDescription = $sDescription; $this->sDescription = $sDescription;
$this->aMetaData = $aMetaData; $this->aMetaData = array_filter($aMetaData);
$this->aBadges = $aBadges; $this->aBadges = $aBadges;
$this->sAbout = $sAbout; $this->sAbout = $sAbout;
$this->InitializeToggler(); $this->InitializeToggler();
@@ -105,7 +105,7 @@ class ExtensionDetails extends UIContentBlock
*/ */
public function SetMetaData(array $aMetaData): static public function SetMetaData(array $aMetaData): static
{ {
$this->aMetaData = $aMetaData; $this->aMetaData = array_filter($aMetaData);
return $this; return $this;
} }