From a4345d03113f91cfba939c723b2c2ffcaa2d9ff2 Mon Sep 17 00:00:00 2001 From: odain Date: Wed, 20 May 2026 14:56:55 +0200 Subject: [PATCH 1/6] =?UTF-8?q?N=C2=B09567=20-=20fix=20back=20to=20setup?= =?UTF-8?q?=20from=20extension=20management=20-=20extension=20screen=20mis?= =?UTF-8?q?sing=20when=20back=20after=20audit?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit N°9567 - fix again --- setup/wizardsteps/WizStepModulesChoice.php | 3 ++- .../setup/WizStepModulesChoiceTest.php | 22 ++++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/setup/wizardsteps/WizStepModulesChoice.php b/setup/wizardsteps/WizStepModulesChoice.php index 08f0a2327d..fdc3d48d9a 100644 --- a/setup/wizardsteps/WizStepModulesChoice.php +++ b/setup/wizardsteps/WizStepModulesChoice.php @@ -175,7 +175,9 @@ class WizStepModulesChoice extends AbstractWizStepInstall ["class" => "WizStepUpgradeMiscParams","state" => ""], ]; $i = 0; + $this->aSteps = null; while (null != $this->GetStepInfo($i)) { + $this->aSteps = null; $aSteps [] = ["class" => "WizStepModulesChoice","state" => "$i"]; $i++; } @@ -709,7 +711,6 @@ EOF // Found an "installation.xml" file, let's use this definition for the wizard $aParams = new XMLParameters($this->GetSourceFilePath()); $this->aSteps = $aParams->Get('steps', []); - if ($index + 1 >= count($this->aSteps)) { //make sure we also cache next step as well $aOptions = $this->oExtensionsMap->GetAllExtensionsOptionInfo($bRemoteExtensionsShouldBeMandatory); diff --git a/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceTest.php b/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceTest.php index 51b8d0f3b5..45ef05f7a6 100644 --- a/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceTest.php +++ b/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceTest.php @@ -6,7 +6,6 @@ use Combodo\iTop\Test\UnitTest\ItopTestCase; use iTopExtensionsMap; use iTopExtensionsMapFake; use ModuleDiscovery; -use WepPageFake; use WizardController; use WizStepModulesChoiceFake; use XMLParameters; @@ -1431,4 +1430,25 @@ HTML, } $this->assertEquals($expected, $this->oWizStepModulesChoiceFake->GetWizardSteps()); } + + public function testGetWizardStepsWithoutAnyExtension() + { + $this->oWizard->SetParameter('source_dir', __DIR__.'/ressources'); + $oExtensionMap = $this->createMock(iTopExtensionsMap::class); + $oExtensionMap->expects(self::any())->method('GetAllExtensionsOptionInfo')->willReturn([]); + + $this->oWizStepModulesChoiceFake->setExtensionMap($oExtensionMap); + + $expected = [ + ["class" => "WizStepWelcome","state" => ""], + ["class" => "WizStepInstallOrUpgrade","state" => ""], + ["class" => "WizStepDetectedInfo","state" => ""], + ["class" => "WizStepUpgradeMiscParams","state" => ""], + ]; + + for ($i = 0;$i <= 4; $i++) { + $expected [] = ["class" => "WizStepModulesChoice","state" => "".$i]; + } + $this->assertEquals($expected, $this->oWizStepModulesChoiceFake->GetWizardSteps()); + } } From 00f1c7498d5d01106c3a0de64592e268ce5f9cbb Mon Sep 17 00:00:00 2001 From: odain Date: Wed, 20 May 2026 17:42:46 +0200 Subject: [PATCH 2/6] =?UTF-8?q?N=C2=B08760=20-=20raise=20module=20dependen?= =?UTF-8?q?cy=20errors=20in=20all=20setups=20ecept=20wizard/unattended?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- setup/runtimeenv.class.inc.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/setup/runtimeenv.class.inc.php b/setup/runtimeenv.class.inc.php index 25974efb9a..fa9e1b087d 100644 --- a/setup/runtimeenv.class.inc.php +++ b/setup/runtimeenv.class.inc.php @@ -477,7 +477,7 @@ class RunTimeEnvironment } $aModulesToLoad = $this->GetModulesToLoad($this->sFinalEnv, $aDirsToCompile); - $aAvailableModules = $this->AnalyzeInstallation($oSourceConfig, $aDirsToCompile, false, $aModulesToLoad); + $aAvailableModules = $this->AnalyzeInstallation($oSourceConfig, $aDirsToCompile, true, $aModulesToLoad); // Do load the required modules // @@ -1634,6 +1634,7 @@ class RunTimeEnvironment protected function GetModulesToLoad(string $sSourceEnv, array $aSearchDirs): ?array { if (is_null($this->GetExtensionMap())) { + SetupLog::Error(__METHOD__ . '================' . __LINE__); return null; } @@ -1641,6 +1642,7 @@ class RunTimeEnvironment $aChoices = $this->GetExtensionMap()->GetChoicesFromDatabase($oSourceConfig); if (false === $aChoices) { + SetupLog::Error(__METHOD__ . '================' . __LINE__); return null; } $sSourceDir = $oSourceConfig->Get('source_dir'); @@ -1666,6 +1668,7 @@ class RunTimeEnvironment $aModulesToLoad[] = $sModuleName; } + SetupLog::Error(__METHOD__ . '================' . __LINE__, null, [$aChoices, $aModuleIdsToLoad]); return $aModulesToLoad; } From 08a3044cd1479418cdd97566b7c77ea63d716b95 Mon Sep 17 00:00:00 2001 From: odain Date: Wed, 20 May 2026 17:44:55 +0200 Subject: [PATCH 3/6] =?UTF-8?q?N=C2=B09564=20-=20fix=20first=20screen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit log cleanup after merge adaptations --- .../DataFeatureRemovalController.php | 39 +++++- .../templates/AnalysisResult.html.twig | 129 +++++++++++------- .../templates/DeletionPlan.html.twig | 29 ---- .../templates/ExtensionRemovalData.html.twig | 19 --- .../templates/Features.html.twig | 2 +- .../templates/Main.html.twig | 16 --- setup/runtimeenv.class.inc.php | 3 - 7 files changed, 112 insertions(+), 125 deletions(-) delete mode 100644 datamodels/2.x/combodo-data-feature-removal/templates/DeletionPlan.html.twig delete mode 100644 datamodels/2.x/combodo-data-feature-removal/templates/ExtensionRemovalData.html.twig diff --git a/datamodels/2.x/combodo-data-feature-removal/src/Controller/DataFeatureRemovalController.php b/datamodels/2.x/combodo-data-feature-removal/src/Controller/DataFeatureRemovalController.php index 04b6c9c2a3..e87b496482 100644 --- a/datamodels/2.x/combodo-data-feature-removal/src/Controller/DataFeatureRemovalController.php +++ b/datamodels/2.x/combodo-data-feature-removal/src/Controller/DataFeatureRemovalController.php @@ -21,10 +21,12 @@ use Combodo\iTop\DataFeatureRemoval\Service\DataFeatureRemoverExtensionService; use Combodo\iTop\Setup\FeatureRemoval\DryRemovalRuntimeEnvironment; use Combodo\iTop\Setup\FeatureRemoval\SetupAudit; use ContextTag; +use CoreException; use Dict; use Exception; use IssueLog; use MetaModel; +use MissingDependencyException; use SetupUtils; use utils; @@ -55,6 +57,7 @@ class DataFeatureRemovalController extends Controller $aParams['sSetupUrl'] = utils::GetAbsoluteUrlAppRoot().'setup'; $aParams['iCount'] = $this->iCount; + Session::Set('bForceCompilation', true); $this->AddLinkedStylesheet(utils::GetAbsoluteUrlModulesRoot().DataFeatureRemovalHelper::MODULE_NAME.'/assets/css/DataFeatureRemoval.css'); $this->AddLinkedScript(utils::GetAbsoluteUrlModulesRoot().DataFeatureRemovalHelper::MODULE_NAME.'/assets/js/DataFeatureRemoval.js'); $this->DisplayPage($aParams); @@ -77,6 +80,7 @@ class DataFeatureRemovalController extends Controller $this->aAnalysisDataTable = $this->GetTableData('Analysis', $aColumns, $aData); } + /* public function OperationAnalyze(): void { $iCount = $this->ReadExtensionsDiff(); @@ -103,6 +107,7 @@ class DataFeatureRemovalController extends Controller IssueLog::Debug(__METHOD__, null, ['aGetRemovedClasses' => $aGetRemovedClasses]); $this->aCountClassesToCleanup = $aGetRemovedClasses; } + */ public function OperationAnalysisResult(): void { @@ -133,7 +138,14 @@ class DataFeatureRemovalController extends Controller $aParams['aHiddenInputs'] = $aHiddenInputs; $aAddedExtensions = json_decode($aHiddenInputs['added_extensions'], true); + $aRemovedExtensions = json_decode($aHiddenInputs['removed_extensions'], true); + if (count($aRemovedExtensions) == 0) { + $this->ReadExtensionsDiff(); + $aRemovedExtensions = $this->aRemovedExtensionsForCheck; + } + + $aRemoveExtensionCodes = array_keys($aRemovedExtensions); $aParams['aAddedExtensions'] = $aAddedExtensions; $aParams['aRemovedExtensions'] = $aRemovedExtensions; @@ -142,17 +154,29 @@ class DataFeatureRemovalController extends Controller 'added_extensions' => $aAddedExtensions, 'removed_extensions' => $aRemovedExtensions]); - $this->Compile(array_keys($aRemovedExtensions), false); + $aParams['sTransactionId'] = utils::GetNewTransactionId(); + $aParams['iColumnCount'] = $this->iColumnCount; + $aParams['aAvailableExtensions'] = $this->SplitArrayIntoColumns($this->GetExtensionsDiff($aAddedExtensions, $aRemovedExtensions), $this->iColumnCount); + + $bForceCompilation = Session::Get('bForceCompilation', false); + try { + $this->Compile($aRemoveExtensionCodes, $bForceCompilation); + } catch (CoreException $e) { + $aParams['DataFeatureRemovalErrorMessage'] = $e->getHtmlDesc(); + $this->DisplayPage($aParams, 'AnalysisResult'); + return; + } catch (Exception $e) { + $aParams['DataFeatureRemovalErrorMessage'] = $e->getMessage(); + $this->DisplayPage($aParams, 'AnalysisResult'); + return; + } $sSourceEnv = MetaModel::GetEnvironment(); $oSetupAudit = new SetupAudit($sSourceEnv); $aGetRemovedClasses = array_keys($oSetupAudit->RunDataAudit()); IssueLog::Debug(__METHOD__, null, ['aGetRemovedClasses' => $aGetRemovedClasses]); - $aParams['sTransactionId'] = utils::GetNewTransactionId(); $aParams['aClasses'] = $aGetRemovedClasses; - $aParams['iColumnCount'] = $this->iColumnCount; - $aParams['aAvailableExtensions'] = $this->SplitArrayIntoColumns($this->GetExtensionsDiff($aAddedExtensions, $aRemovedExtensions), $this->iColumnCount); new ContextTag(ContextTag::TAG_SETUP); $aParams['sLaunchSetupUrl'] = utils::GetAbsoluteUrlAppRoot().'setup/wizard.php'; @@ -170,6 +194,13 @@ class DataFeatureRemovalController extends Controller $this->DisplayPage($aParams, 'AnalysisResult'); } + /** +* @param array $aRemovedExtensions +* @param bool $bForceCompilation +* @return void +* @throws \ConfigException +* @throws \CoreException + */ private function Compile(array $aRemovedExtensions, bool $bForceCompilation = true): void { $sSourceEnv = MetaModel::GetEnvironment(); diff --git a/datamodels/2.x/combodo-data-feature-removal/templates/AnalysisResult.html.twig b/datamodels/2.x/combodo-data-feature-removal/templates/AnalysisResult.html.twig index 2ce1f409f1..8bebc67108 100644 --- a/datamodels/2.x/combodo-data-feature-removal/templates/AnalysisResult.html.twig +++ b/datamodels/2.x/combodo-data-feature-removal/templates/AnalysisResult.html.twig @@ -4,64 +4,87 @@ {% UIPanel ForInformation { sTitle:'DataFeatureRemoval:Analysis:Title'|dict_s} %} - {% UIPanel Neutral { sTitle:'DataFeatureRemoval:Features:Title'|dict_s, sSubTitle: '' } %} - {% UIMultiColumn Standard {} %} - {% 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 %} + {% if null != DataFeatureRemovalErrorMessage %} +
+ {% UIAlert ForFailure { sTitle:'DataFeatureRemoval:Failure:Title'|dict_s, sId: 'feature_removal_error_msg', sContent:DataFeatureRemovalErrorMessage } %} + {% EndUIAlert %} +
- {% if bDeletionNeeded %} - {% UIFieldSet Standard {sLegend:'DataFeatureRemoval:DeletionPlan:Title'|dict_s} %} - {% UIDataTable ForForm { sRef:'aDeletionPlanSummary', aColumns:aDeletionPlanSummary.Columns, aData:aDeletionPlanSummary.Data} %}{% EndUIDataTable %} - {% EndUIFieldSet %} - {% if bDeletionPossible %} - {% UIForm Standard {} %} - {% UIInput ForHidden { sName:'transaction_id', sValue:sTransactionId} %} - {% UIInput ForHidden { sName:'operation', sValue:'DoDeletion'} %} - {% for sKey, sClass in aClasses %} - {% UIInput ForHidden { sName:"classes[" ~ sKey ~ "]", sValue:sClass } %} + {% UIPanel Neutral { sTitle:'DataFeatureRemoval:Features:Title'|dict_s, sSubTitle: '' } %} + {% UIMultiColumn Standard {} %} + {% 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 %} - {% for sCode, sLabel in aAddedExtensions %} - {% UIInput ForHidden { sName:"aAddedExtensions[" ~ sCode ~ "]", sValue:sLabel } %} - {% endfor %} - {% for sCode, sLabel in aRemovedExtensions %} - {% UIInput ForHidden { sName:"aRemovedExtensions[" ~ sCode ~ "]", sValue:sLabel } %} - {% endfor %} - {% for sInputName, sValue in aHiddenInputs %} - {% UIInput ForHidden { sName:sInputName, sValue:sValue } %} - {% endfor %} - {% UIToolbar ForButton {} %} - {% UIButton ForPrimaryAction {sLabel:'UI:Button:DoDeletion'|dict_s, sName:'btn_deletion', sId:'btn_deletion', bIsSubmit:true} %} - {% EndUIToolbar %} - {% EndUIForm %} - {% else %} - {% UIAlert ForFailure { sContent: 'DataFeatureRemoval:DeletionPlan:Error:Issues'|dict_s } %}{% EndUIAlert %} - {% endif %} + {% EndUIMultiColumn %} + {% EndUIPanel %} {% else %} - {% UIAlert ForSuccess { sTitle:'DataFeatureRemoval:CleanupComplete:Title'|dict_s, sContent:'DataFeatureRemoval:CompilComplete'|dict_s, sId:value } %}{% EndUIAlert %} + {% UIPanel Neutral { sTitle:'DataFeatureRemoval:Features:Title'|dict_s, sSubTitle: '' } %} + {% UIMultiColumn Standard {} %} + {% 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 %} - {% UIForm Standard {'sId':'launch-setup-form', Action:sLaunchSetupUrl, 'EncType': 'application/x-www-form-urlencoded'} %} - {% for sKey, sValue in aSetupParams %} - {% UIInput ForHidden { sName:sKey, sValue:sValue } %} - {% endfor %} - {% UIButton ForPrimaryAction {sLabel:'UI:Button:Setup'|dict_s, sName:'btn_setup', sId:'btn_setup', bIsSubmit:true} %} - {% EndUIForm %} - {% endif %} + {% if bDeletionNeeded %} + {% UIFieldSet Standard {sLegend:'DataFeatureRemoval:DeletionPlan:Title'|dict_s} %} + {% UIDataTable ForForm { sRef:'aDeletionPlanSummary', aColumns:aDeletionPlanSummary.Columns, aData:aDeletionPlanSummary.Data} %}{% EndUIDataTable %} + {% EndUIFieldSet %} + {% if bDeletionPossible %} + {% UIForm Standard {} %} + {% UIInput ForHidden { sName:'transaction_id', sValue:sTransactionId} %} + {% UIInput ForHidden { sName:'operation', sValue:'DoDeletion'} %} + {% for sKey, sClass in aClasses %} + {% UIInput ForHidden { sName:"classes[" ~ sKey ~ "]", sValue:sClass } %} + {% endfor %} + {% for sCode, sLabel in aAddedExtensions %} + {% UIInput ForHidden { sName:"aAddedExtensions[" ~ sCode ~ "]", sValue:sLabel } %} + {% endfor %} + {% for sCode, sLabel in aRemovedExtensions %} + {% UIInput ForHidden { sName:"aRemovedExtensions[" ~ sCode ~ "]", sValue:sLabel } %} + {% endfor %} + {% for sInputName, sValue in aHiddenInputs %} + {% UIInput ForHidden { sName:sInputName, sValue:sValue } %} + {% endfor %} + {% UIToolbar ForButton {} %} + {% UIButton ForPrimaryAction {sLabel:'UI:Button:DoDeletion'|dict_s, sName:'btn_deletion', sId:'btn_deletion', bIsSubmit:true} %} + {% EndUIToolbar %} + {% EndUIForm %} + {% else %} + {% UIAlert ForFailure { sContent: 'DataFeatureRemoval:DeletionPlan:Error:Issues'|dict_s } %}{% EndUIAlert %} + {% endif %} + {% else %} + {% UIAlert ForSuccess { sTitle:'DataFeatureRemoval:CleanupComplete:Title'|dict_s, sContent:'DataFeatureRemoval:CompilComplete'|dict_s, sId:value } %}{% EndUIAlert %} - {% if bHasDeletionExecution %} - {% UIFieldSet Standard {sLegend:'DataFeatureRemoval:Execution:Title'|dict_s} %} - {% UIDataTable ForForm { sRef:'aDeletionExecutionSummary', aColumns:aDeletionExecutionSummary.Columns, aData:aDeletionExecutionSummary.Data} %}{% EndUIDataTable %} - {% EndUIFieldSet %} + {% UIForm Standard {'sId':'launch-setup-form', Action:sLaunchSetupUrl, 'EncType': 'application/x-www-form-urlencoded'} %} + {% for sKey, sValue in aSetupParams %} + {% UIInput ForHidden { sName:sKey, sValue:sValue } %} + {% endfor %} + {% UIButton ForPrimaryAction {sLabel:'UI:Button:Setup'|dict_s, sName:'btn_setup', sId:'btn_setup', bIsSubmit:true} %} + {% EndUIForm %} + {% endif %} + + {% if bHasDeletionExecution %} + {% UIFieldSet Standard {sLegend:'DataFeatureRemoval:Execution:Title'|dict_s} %} + {% UIDataTable ForForm { sRef:'aDeletionExecutionSummary', aColumns:aDeletionExecutionSummary.Columns, aData:aDeletionExecutionSummary.Data} %}{% EndUIDataTable %} + {% EndUIFieldSet %} + {% endif %} {% endif %} {% UIForm Standard {} %} diff --git a/datamodels/2.x/combodo-data-feature-removal/templates/DeletionPlan.html.twig b/datamodels/2.x/combodo-data-feature-removal/templates/DeletionPlan.html.twig deleted file mode 100644 index c37bff85a6..0000000000 --- a/datamodels/2.x/combodo-data-feature-removal/templates/DeletionPlan.html.twig +++ /dev/null @@ -1,29 +0,0 @@ -{# @copyright Copyright (C) 2010-2026 Combodo SARL #} -{# @license http://opensource.org/licenses/AGPL-3.0 #} - -{% UIPanel ForInformation { sTitle:'DataFeatureRemoval:DeletionPlan:Title'|dict_s, sSubTitle: 'DataFeatureRemoval:DeletionPlan:SubTitle'|dict_format(iQueryCount) } %} - {% UIDataTable ForForm { sRef:'aDeletionPlanSummary', aColumns:aDeletionPlanSummary.Columns, aData:aDeletionPlanSummary.Data} %}{% EndUIDataTable %} -{% EndUIPanel %} - -{% if bDeletionPossible %} - {% UIForm Standard {} %} - {% UIInput ForHidden { sName:'transaction_id', sValue:sTransactionId} %} - {% UIInput ForHidden { sName:'operation', sValue:'DoDeletion'} %} - {% for sKey, sClass in aClasses %} - {% UIInput ForHidden { sName:"classes[" ~ sKey ~ "]", sValue:sClass } %} - {% endfor %} - {% UIToolbar ForButton {} %} - {% UIButton ForPrimaryAction {sLabel:'UI:Button:DoDeletion'|dict_s, sName:'btn_deletion', sId:'btn_deletion', bIsSubmit:true} %} - {% EndUIToolbar %} - {% EndUIForm %} -{% else %} - {{ 'DataFeatureRemoval:DeletionPlan:Error:Issues'|dict_s }} -{% endif %} - -{% UIForm Standard {} %} - {% UIInput ForHidden { sName:'transaction_id', sValue:sTransactionId} %} - {% UIInput ForHidden { sName:'operation', sValue:'Main'} %} - {% UIToolbar ForButton {} %} - {% UIButton ForPrimaryAction {sLabel:'UI:Button:BackToMain'|dict_s, sName:'btn_back', sId:'btn_back', bIsSubmit:true} %} - {% EndUIToolbar %} -{% EndUIForm %} \ No newline at end of file diff --git a/datamodels/2.x/combodo-data-feature-removal/templates/ExtensionRemovalData.html.twig b/datamodels/2.x/combodo-data-feature-removal/templates/ExtensionRemovalData.html.twig deleted file mode 100644 index 2cce0e9ff4..0000000000 --- a/datamodels/2.x/combodo-data-feature-removal/templates/ExtensionRemovalData.html.twig +++ /dev/null @@ -1,19 +0,0 @@ -{# @copyright Copyright (C) 2010-2024 Combodo SAS #} -{# @license http://opensource.org/licenses/AGPL-3.0 #} - -{% if bHasData %} - {% UIPanel Neutral { sTitle:'DataFeatureRemoval:Analysis:Title'|dict_s, sSubTitle: 'DataFeatureRemoval:Analysis:SubTitle'|dict_format(iCount) } %} - {% UIDataTable ForForm { sRef:'aAnalysisDataTable', aColumns:aAnalysisDataTable.Columns, aData:aAnalysisDataTable.Data} %}{% EndUIDataTable %} - {% EndUIPanel %} - - {% UIForm Standard {} %} - {% UIInput ForHidden { sName:'transaction_id', sValue:sTransactionId} %} - {% UIInput ForHidden { sName:'operation', sValue:'DeletionPlan'} %} - {% for sKey, sClass in aClasses %} - {% UIInput ForHidden { sName:"classes[" ~ sKey ~ "]", sValue:sClass } %} - {% endfor %} - {% UIToolbar ForButton {} %} - {% UIButton ForPrimaryAction {sLabel:'UI:Button:PlanDeletion'|dict_s, sName:'btn_plandeletion', sId:'btn_plandeletion', bIsSubmit:true} %} - {% EndUIToolbar %} - {% EndUIForm %} -{% endif %} diff --git a/datamodels/2.x/combodo-data-feature-removal/templates/Features.html.twig b/datamodels/2.x/combodo-data-feature-removal/templates/Features.html.twig index 71b06b6b64..a2c2c84f18 100644 --- a/datamodels/2.x/combodo-data-feature-removal/templates/Features.html.twig +++ b/datamodels/2.x/combodo-data-feature-removal/templates/Features.html.twig @@ -3,7 +3,7 @@ {% UIForm Standard {} %} - {% UIInput ForHidden {sName:'operation', sValue:'Analyze'} %} + {% UIInput ForHidden {sName:'operation', sValue:'AnalysisResult'} %} {% UIInput ForHidden {sName:'transaction_id', sValue:sTransactionId} %} {% UIPanel Neutral { sTitle:'DataFeatureRemoval:Features:Title'|dict_s, sSubTitle: '' } %} diff --git a/datamodels/2.x/combodo-data-feature-removal/templates/Main.html.twig b/datamodels/2.x/combodo-data-feature-removal/templates/Main.html.twig index 89c6fa5798..04ae95101c 100644 --- a/datamodels/2.x/combodo-data-feature-removal/templates/Main.html.twig +++ b/datamodels/2.x/combodo-data-feature-removal/templates/Main.html.twig @@ -15,21 +15,5 @@ {{ 'DataFeatureRemoval:Helper:Desc2'|dict_s }} {% EndUIAlert %} - {% if null != DataFeatureRemovalErrorMessage %} -
- {% UIAlert ForFailure { sTitle:'DataFeatureRemoval:Failure:Title'|dict_s, sId: 'feature_removal_error_msg', sContent:DataFeatureRemovalErrorMessage } %} - {% EndUIAlert %} -
- {% endif %} - {% include 'Features.html.twig' %} - {% include 'ExtensionRemovalData.html.twig' %} - - {% if not bHasData %} - {% UIToolbar ForButton {} %} - - {% UIButton ForPrimaryAction {sLabel:'UI:Button:Setup'|dict_s, sName:'btn_setup', sId:'btn_setup', bIsSubmit:false} %} - - {% EndUIToolbar %} - {% endif %} {% EndUIPanel %} diff --git a/setup/runtimeenv.class.inc.php b/setup/runtimeenv.class.inc.php index fa9e1b087d..0b592eb81a 100644 --- a/setup/runtimeenv.class.inc.php +++ b/setup/runtimeenv.class.inc.php @@ -1634,7 +1634,6 @@ class RunTimeEnvironment protected function GetModulesToLoad(string $sSourceEnv, array $aSearchDirs): ?array { if (is_null($this->GetExtensionMap())) { - SetupLog::Error(__METHOD__ . '================' . __LINE__); return null; } @@ -1642,7 +1641,6 @@ class RunTimeEnvironment $aChoices = $this->GetExtensionMap()->GetChoicesFromDatabase($oSourceConfig); if (false === $aChoices) { - SetupLog::Error(__METHOD__ . '================' . __LINE__); return null; } $sSourceDir = $oSourceConfig->Get('source_dir'); @@ -1668,7 +1666,6 @@ class RunTimeEnvironment $aModulesToLoad[] = $sModuleName; } - SetupLog::Error(__METHOD__ . '================' . __LINE__, null, [$aChoices, $aModuleIdsToLoad]); return $aModulesToLoad; } From a5b5d22e2f827a8d33e8911ab0b91685c773469b Mon Sep 17 00:00:00 2001 From: odain Date: Thu, 21 May 2026 11:31:48 +0200 Subject: [PATCH 4/6] =?UTF-8?q?N=C2=B09564=20-=20enhance=20simulate=20test?= =?UTF-8?q?ing=20script=20to=20use=20local=20settings?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../simulate-audit-from-setup.php | 100 ++++++------------ 1 file changed, 32 insertions(+), 68 deletions(-) diff --git a/tests/php-unit-tests/unitary-tests/datamodels/2.x/combodo-data-feature-removal/simulate-audit-from-setup.php b/tests/php-unit-tests/unitary-tests/datamodels/2.x/combodo-data-feature-removal/simulate-audit-from-setup.php index 179bea189c..34d0c7e181 100644 --- a/tests/php-unit-tests/unitary-tests/datamodels/2.x/combodo-data-feature-removal/simulate-audit-from-setup.php +++ b/tests/php-unit-tests/unitary-tests/datamodels/2.x/combodo-data-feature-removal/simulate-audit-from-setup.php @@ -15,78 +15,42 @@ $aParams = [ new ContextTag(ContextTag::TAG_SETUP); $sToken = SetupUtils::CreateSetupToken(); -$aSelectedModules = [ - 'authent-cas', - 'authent-external', - 'authent-ldap', - 'authent-local', - 'combodo-backoffice-darkmoon-theme', - 'combodo-backoffice-fullmoon-high-contrast-theme', - 'combodo-backoffice-fullmoon-protanopia-deuteranopia-theme', - 'combodo-backoffice-fullmoon-tritanopia-theme', - 'combodo-data-feature-removal', - 'itop-backup', - 'itop-config', - 'itop-files-information', - 'itop-portal-base', - 'itop-profiles-itil', - 'itop-sla-computation', - 'itop-structure', - 'itop-welcome-itil', - 'itop-config-mgmt', - 'itop-attachments', - 'itop-tickets', - 'combodo-db-tools', - 'itop-core-update', - 'itop-hub-connector', - 'itop-oauth-client', - 'itop-themes-compat', - 'combodo-my-account', - 'combodo-my-account-user-info', - 'combodo-oauth2-client', - 'itop-attribute-class-set', - 'itop-attribute-encrypted-password', - 'itop-ui-copypaste', - 'itop-datacenter-mgmt', - 'itop-endusers-devices', - 'itop-storage-mgmt', - 'itop-virtualization-mgmt', - 'itop-bridge-cmdb-ticket', - 'itop-bridge-virtualization-storage', - 'itop-service-mgmt', - 'itop-bridge-cmdb-services', - 'itop-bridge-datacenter-mgmt-services', - 'itop-bridge-endusers-devices-services', - 'itop-bridge-storage-mgmt-services', - 'itop-bridge-virtualization-mgmt-services', - 'itop-request-mgmt', - 'itop-portal', - 'itop-change-mgmt', - 'itop-faq-light', - 'itop-knownerror-mgmt', - 'itop-problem-mgmt', - 'itop-system-information', - 'itop-log-mgmt', -]; +function GetLastestInstallFile(): ?string +{ + $aFiles = glob(APPROOT.'/log/install-*.xml'); + rsort($aFiles); + $iLatestCtime = 0; + $sLastFilePath = null; + foreach ($aFiles as $sFilePath) { + if (is_file($sFilePath)) { + $iCurrentCtime = filemtime($sFilePath); + if ($iCurrentCtime > $iLatestCtime) { + $iLatestCtime = $iCurrentCtime; + $sLastFilePath = $sFilePath; + } + } + } -$aSelectedExtensions = [ - 'itop-config-mgmt-core', - 'itop-config-mgmt-datacenter', - 'itop-config-mgmt-end-user', - 'itop-config-mgmt-storage', - 'itop-config-mgmt-virtualization', - 'itop-service-mgmt-enterprise', - 'itop-ticket-mgmt-simple-ticket', - 'itop-ticket-mgmt-simple-ticket-enhanced-portal', - 'itop-change-mgmt-simple', - 'itop-kown-error-mgmt', - 'itop-problem-mgmt', - 'itop-system-information', - 'itop-log-mgmt', -]; + return $sLastFilePath; +} $aRemovedExtensions = ['itop-container-mgmt' => 'Containerization']; +$sPath = GetLastestInstallFile(); +if (is_null($sPath)) { + throw new Exception("$sPath no installation XM. Launch a setup...."); +} +$aParams = new XMLParameters($sPath); +$aSelectedModules = array_filter($aParams->Get('selected_modules', []), static function ($element) { + global $aRemovedExtensions; + return ! array_key_exists($element, $aRemovedExtensions); +}); + +$aSelectedExtensions = array_filter($aParams->Get('selected_extensions', []), static function ($element) { + global $aRemovedExtensions; + return ! array_key_exists($element, $aRemovedExtensions); +}); + $aPostParams = [ "auth_user" => 'admin', "auth_pwd" => 'admin', From 3aa59ae0b792be5b2957749c1409da5d1a51e8ed Mon Sep 17 00:00:00 2001 From: odain Date: Thu, 21 May 2026 13:54:16 +0200 Subject: [PATCH 5/6] =?UTF-8?q?N=C2=B09564=20-=20fix=20extension=20mgt=20f?= =?UTF-8?q?low=20from=201st=20to=202nd=20screen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/.compilation-symlinks | 0 .../DataFeatureRemovalController.php | 46 ++++--------------- 2 files changed, 9 insertions(+), 37 deletions(-) delete mode 100644 data/.compilation-symlinks diff --git a/data/.compilation-symlinks b/data/.compilation-symlinks deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/datamodels/2.x/combodo-data-feature-removal/src/Controller/DataFeatureRemovalController.php b/datamodels/2.x/combodo-data-feature-removal/src/Controller/DataFeatureRemovalController.php index e87b496482..9be23183f1 100644 --- a/datamodels/2.x/combodo-data-feature-removal/src/Controller/DataFeatureRemovalController.php +++ b/datamodels/2.x/combodo-data-feature-removal/src/Controller/DataFeatureRemovalController.php @@ -24,7 +24,6 @@ use ContextTag; use CoreException; use Dict; use Exception; -use IssueLog; use MetaModel; use MissingDependencyException; use SetupUtils; @@ -32,7 +31,6 @@ use utils; class DataFeatureRemovalController extends Controller { - private array $aRemovedExtensionsForCheck = []; private ?array $aExtensionsToCheck = null; private bool $bForcedUninstallation = false; private array $aCountClassesToCleanup = []; @@ -80,35 +78,6 @@ class DataFeatureRemovalController extends Controller $this->aAnalysisDataTable = $this->GetTableData('Analysis', $aColumns, $aData); } - /* - public function OperationAnalyze(): void - { - $iCount = $this->ReadExtensionsDiff(); - - $this->m_sOperation = 'Main'; - try { - if ($iCount > 0) { - $this->Analyze(); - } - $this->OperationMain(); - } catch (Exception $e) { - IssueLog::Error(__METHOD__, null, ['stack' => $e->getTraceAsString(), 'exception' => $e->getMessage()]); - $this->OperationMain($e->getMessage()); - } - } - - private function Analyze(): void - { - //TODO : Run data audit with added extension too, not just removed ones - $this->Compile($this->aExtensionsToCheck['to_be_removed']); - $sSourceEnv = MetaModel::GetEnvironment(); - $oSetupAudit = new SetupAudit($sSourceEnv); - $aGetRemovedClasses = $oSetupAudit->RunDataAudit(); - IssueLog::Debug(__METHOD__, null, ['aGetRemovedClasses' => $aGetRemovedClasses]); - $this->aCountClassesToCleanup = $aGetRemovedClasses; - } - */ - public function OperationAnalysisResult(): void { $aParams = []; @@ -142,7 +111,10 @@ class DataFeatureRemovalController extends Controller $aRemovedExtensions = json_decode($aHiddenInputs['removed_extensions'], true); if (count($aRemovedExtensions) == 0) { $this->ReadExtensionsDiff(); - $aRemovedExtensions = $this->aRemovedExtensionsForCheck; + $aAddedExtensions = $this->aExtensionsToCheck['to_be_installed']; + $aHiddenInputs['added_extensions'] = utils::HtmlEntities(json_encode($aAddedExtensions)); + $aRemovedExtensions = $this->aExtensionsToCheck['to_be_removed']; + $aHiddenInputs['removed_extensions'] = utils::HtmlEntities(json_encode($aRemovedExtensions)); } $aRemoveExtensionCodes = array_keys($aRemovedExtensions); @@ -150,7 +122,7 @@ class DataFeatureRemovalController extends Controller $aParams['aAddedExtensions'] = $aAddedExtensions; $aParams['aRemovedExtensions'] = $aRemovedExtensions; - IssueLog::Debug(__METHOD__.' Extensions given in parameter', null, [ + DataFeatureRemovalLog::Debug(__METHOD__.' Extensions given in parameter', null, [ 'added_extensions' => $aAddedExtensions, 'removed_extensions' => $aRemovedExtensions]); @@ -174,7 +146,7 @@ class DataFeatureRemovalController extends Controller $sSourceEnv = MetaModel::GetEnvironment(); $oSetupAudit = new SetupAudit($sSourceEnv); $aGetRemovedClasses = array_keys($oSetupAudit->RunDataAudit()); - IssueLog::Debug(__METHOD__, null, ['aGetRemovedClasses' => $aGetRemovedClasses]); + DataFeatureRemovalLog::Debug(__METHOD__, null, ['aGetRemovedClasses' => $aGetRemovedClasses]); $aParams['aClasses'] = $aGetRemovedClasses; @@ -377,7 +349,7 @@ class DataFeatureRemovalController extends Controller } $sTransactionId = utils::ReadPostedParam('transaction_id', null, utils::ENUM_SANITIZATION_FILTER_TRANSACTION_ID); - IssueLog::Debug(__FUNCTION__.": Transaction [$sTransactionId]"); + DataFeatureRemovalLog::Debug(__FUNCTION__.": Transaction [$sTransactionId]"); if (empty($sTransactionId) || !utils::IsTransactionValid($sTransactionId, false)) { throw new DataFeatureRemovalException(Dict::S("iTopUpdate:Error:InvalidToken")); } @@ -406,13 +378,13 @@ class DataFeatureRemovalController extends Controller if ($aExtensionData['installed'] && $aSelectedExtensionsFromUI[$sCode] !== 'on') { $aExtensionData['extra_flags']['selected'] = false; - $this->aExtensionsToCheck['to_be_removed'][] = $sCode; + $this->aExtensionsToCheck['to_be_removed'][$sCode] = $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; + $this->aExtensionsToCheck['to_be_installed'][$sCode] = $sCode; } } return count($this->aExtensionsToCheck['to_be_installed']) + count($this->aExtensionsToCheck['to_be_removed']); From 0912cc21cf7e9ad72c40668c77fe9826a8deebe7 Mon Sep 17 00:00:00 2001 From: odain Date: Thu, 21 May 2026 13:56:24 +0200 Subject: [PATCH 6/6] =?UTF-8?q?N=C2=B09564=20-=20fix=20WizardChoice=20test?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- setup/wizardsteps/WizStepModulesChoice.php | 1 - 1 file changed, 1 deletion(-) diff --git a/setup/wizardsteps/WizStepModulesChoice.php b/setup/wizardsteps/WizStepModulesChoice.php index fdc3d48d9a..03bc4cddb3 100644 --- a/setup/wizardsteps/WizStepModulesChoice.php +++ b/setup/wizardsteps/WizStepModulesChoice.php @@ -181,7 +181,6 @@ class WizStepModulesChoice extends AbstractWizStepInstall $aSteps [] = ["class" => "WizStepModulesChoice","state" => "$i"]; $i++; } - $aSteps [] = ["class" => "WizStepModulesChoice","state" => "$i"]; return $aSteps; }