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 df0cbecf49..9c2b098d03 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
@@ -344,7 +344,7 @@ class DataFeatureRemovalController extends Controller
'uninstallable' => $oExtension->CanBeUninstalled(),
'remote' => $oExtension->IsRemote(),
'missing' => $oExtension->bRemovedFromDisk,
- 'cannot-be-installed' => count($oExtension->aMissingDependencies) > 0,
+ 'cannot-be-installed' => $oExtension->HasDependencyIssue(),
],
];
diff --git a/datamodels/2.x/itop-hub-connector/land.php b/datamodels/2.x/itop-hub-connector/land.php
index ed3cd0d0d1..f0921e33f4 100644
--- a/datamodels/2.x/itop-hub-connector/land.php
+++ b/datamodels/2.x/itop-hub-connector/land.php
@@ -159,7 +159,7 @@ function DoInstall(WebPage $oPage)
foreach ($oExtensionsMap->GetAllExtensions() as $oExtension) {
if ($oExtension->sSource == iTopExtension::SOURCE_REMOTE) {
- if (count($oExtension->aMissingDependencies) > 0) {
+ if ($oExtension->HasDependencyIssue()) {
$oPage->add('
');
$oPage->add('
');
$sTitle = Dict::Format('iTopHub:InstallationEffect:MissingDependencies_Details', implode(', ', $oExtension->aMissingDependencies));
diff --git a/setup/extensionsmap.class.inc.php b/setup/extensionsmap.class.inc.php
index 0f378d48f7..bee2fcce5b 100644
--- a/setup/extensionsmap.class.inc.php
+++ b/setup/extensionsmap.class.inc.php
@@ -545,7 +545,7 @@ class iTopExtensionsMap
continue;
}
- if (! $bKeepExtensionsHavingMissingDependencies && count($oExtension->aMissingDependencies) > 0) {
+ if (! $bKeepExtensionsHavingMissingDependencies && $oExtension->HasDependencyIssue()) {
//skip extensions with dependency issues
continue;
}
@@ -562,19 +562,20 @@ class iTopExtensionsMap
public function GetAllExtensionsOptionInfo(bool $bRemoteExtensionsShouldBeMandatory = true): array
{
$aRes = [];
- foreach ($this->GetAllExtensionsToDisplayInSetup(false, $bRemoteExtensionsShouldBeMandatory) as $sCode => $oExtension) {
+ foreach ($this->GetAllExtensionsToDisplayInSetup(true, $bRemoteExtensionsShouldBeMandatory) as $sCode => $oExtension) {
$aRes[] = [
- 'extension_code' => $oExtension->sCode,
- 'title' => $oExtension->sLabel,
- 'description' => $oExtension->sDescription,
- 'more_info' => $oExtension->sMoreInfoUrl,
- 'default' => true, // by default offer to install all modules
- 'modules' => $oExtension->aModules,
- 'mandatory' => $oExtension->bMandatory,
- 'source_label' => $oExtension->GetExtensionSourceLabel(),
- 'uninstallable' => $oExtension->CanBeUninstalled(),
- 'missing' => $oExtension->bRemovedFromDisk,
- 'version' => $oExtension->sVersion,
+ 'extension_code' => $oExtension->sCode,
+ 'title' => $oExtension->sLabel,
+ 'description' => $oExtension->sDescription,
+ 'more_info' => $oExtension->sMoreInfoUrl,
+ 'default' => true, // by default offer to install all modules
+ 'modules' => $oExtension->aModules,
+ 'mandatory' => $oExtension->bMandatory,
+ 'dependency_issue' => $oExtension->HasDependencyIssue(),
+ 'source_label' => $oExtension->GetExtensionSourceLabel(),
+ 'uninstallable' => $oExtension->CanBeUninstalled(),
+ 'missing' => $oExtension->bRemovedFromDisk,
+ 'version' => $oExtension->sVersion,
];
}
diff --git a/setup/itopextension.class.inc.php b/setup/itopextension.class.inc.php
index a84b69deb4..0e009680b6 100644
--- a/setup/itopextension.class.inc.php
+++ b/setup/itopextension.class.inc.php
@@ -200,4 +200,9 @@ class iTopExtension
{
return $this->sLabel !== '';
}
+
+ public function HasDependencyIssue(): bool
+ {
+ return count($this->aMissingDependencies) > 0;
+ }
}
diff --git a/setup/unattended-install/InstallationFileService.php b/setup/unattended-install/InstallationFileService.php
index 33de7dac52..8bf5660cbd 100644
--- a/setup/unattended-install/InstallationFileService.php
+++ b/setup/unattended-install/InstallationFileService.php
@@ -338,7 +338,7 @@ class InstallationFileService
continue;
}
if ($this->CanChooseUnpackageExtension($oExtension)) {
- if (($oExtension->bVisible) && (count($oExtension->aMissingDependencies) === 0)) {
+ if ($oExtension->bVisible && !$oExtension->HasDependencyIssue()) {
$aCurrentModules = [];
$aUnselectableModules = [];
$bIsExtensionSelectable = true;
diff --git a/setup/wizardsteps/WizStepModulesChoice.php b/setup/wizardsteps/WizStepModulesChoice.php
index 2d62c15707..7494d92b75 100644
--- a/setup/wizardsteps/WizStepModulesChoice.php
+++ b/setup/wizardsteps/WizStepModulesChoice.php
@@ -587,7 +587,7 @@ EOF
break;
}
}
- if ((isset($aChoice['mandatory']) && $aChoice['mandatory']) ||
+ if ((isset($aChoice['mandatory']) && $aChoice['mandatory'] && (!isset($aChoice['dependency_issue']) || !$aChoice['dependency_issue'])) ||
(isset($aSelectedChoices[$sChoiceId]) && ($aSelectedChoices[$sChoiceId] == $sChoiceId))) {
$sDisplayChoices .= '
'.$aChoice['title'].'';
if (isset($aChoice['modules'])) {
@@ -637,7 +637,7 @@ EOF
if ($sChoiceName == null) {
$sChoiceName = $sChoiceId;
}
- if ((isset($aChoice['mandatory']) && $aChoice['mandatory']) ||
+ if ((isset($aChoice['mandatory']) && $aChoice['mandatory'] && (!isset($aChoice['dependency_issue']) || !$aChoice['dependency_issue'])) ||
(isset($aSelectedChoices[$sChoiceName]) && ($aSelectedChoices[$sChoiceName] == $sChoiceId))) {
$sDisplayChoices .= '
'.$aChoice['title'].'';
if ($aSelectedExtensions !== null) {
@@ -751,12 +751,16 @@ EOF
$bMissingFromDisk = isset($aChoice['missing']) && $aChoice['missing'] === true;
$bMandatory = (isset($aChoice['mandatory']) && $aChoice['mandatory']);
$bInstalled = $bMissingFromDisk || $oITopExtension->bInstalled;
+ $bDependencyIssue = $oITopExtension->HasDependencyIssue();
$bChecked = $bSelected;
$bDisabled = false;
if ($bMissingFromDisk) {
$bDisabled = true;
$bChecked = false;
+ } elseif ($bDependencyIssue) {
+ $bDisabled = true;
+ $bChecked = false;
} elseif ($bMandatory) {
$bDisabled = true;
$bChecked = true;
@@ -787,6 +791,8 @@ EOF
return [
'uninstallable' => $bCanBeUninstalled,
+ 'dependency_issue' => $bDependencyIssue,
+ 'mandatory' => $bMandatory,
'missing' => $bMissingFromDisk,
'installed' => $bInstalled,
'disabled' => $bDisabled,
@@ -805,7 +811,7 @@ EOF
$sChoiceId = $sParentId.self::$SEP.$index;
$aFlags = $this->ComputeChoiceFlags($aChoice, $sChoiceId, $aSelectedComponents, $bAllDisabled, $bDisableUninstallCheck, $this->bUpgrade);
- if ($aFlags['disabled'] && !$aFlags['checked'] && !$aFlags['uninstallable'] && !$bDisableUninstallCheck) {
+ if ($aFlags['disabled'] && !$aFlags['checked'] && !$bDisableUninstallCheck && (!$aFlags['uninstallable'] || $aFlags['mandatory'])) {
$this->bCanMoveForward = false;//Disable "Next"
}
@@ -882,6 +888,9 @@ EOF
if (!$aFlags['uninstallable']) {
$sTooltip .= '
cannot be uninstalled
';
}
+ if ($aFlags['dependency_issue']) {
+ $sTooltip .= '
cannot be installed
';
+ }
$sMetadata = '';
if (isset($aChoice['version']) && isset($aChoice['source_label'])) {
@@ -939,10 +948,6 @@ EOF
public function GetNextButtonLabel()
{
- if (!$this->bCanMoveForward) {
- return 'Non-uninstallable extension missing';
- }
-
if ($this->GetStepInfo(1 + $this->GetStepIndex()) === null) {
return 'Check compatibility';
}
diff --git a/sources/Application/UI/Base/Layout/Extension/ExtensionDetailsUIBlockFactory.php b/sources/Application/UI/Base/Layout/Extension/ExtensionDetailsUIBlockFactory.php
index 1bbe6278c1..c77163f490 100644
--- a/sources/Application/UI/Base/Layout/Extension/ExtensionDetailsUIBlockFactory.php
+++ b/sources/Application/UI/Base/Layout/Extension/ExtensionDetailsUIBlockFactory.php
@@ -26,11 +26,11 @@ class ExtensionDetailsUIBlockFactory extends AbstractUIBlockFactory
$aBadges = [];
$bUninstallable = $aExtraFlags['uninstallable'] ?? true;
$bMissingFromDisk = $aExtraFlags['missing'] ?? false;
- $bCannotBeInstalled = $aExtraFlags['cannot-be-installed'] ?? false;
+ $bDependencyIssue = $aExtraFlags['dependency_issue'] ?? false;
$bSelected = $aExtraFlags['selected'] ?? true;
$bDisabled = $aExtraFlags['disabled'] ?? false;
$bRemote = $aExtraFlags['remote'] ?? false;
- self::AddExtraBadges($aBadges, $bUninstallable, $bMissingFromDisk, $bCannotBeInstalled, $sCode);
+ self::AddExtraBadges($aBadges, $bUninstallable, $bMissingFromDisk, $bDependencyIssue, $sCode);
$oBadgeInstalled = BadgeUIBlockFactory::MakeGreen(
Dict::S('UI:Layout:ExtensionsDetails:BadgeInstalled'),
Dict::S('UI:Layout:ExtensionsDetails:BadgeInstalled+'),
@@ -48,7 +48,7 @@ class ExtensionDetailsUIBlockFactory extends AbstractUIBlockFactory
$oExtensionDetails = new ExtensionDetails($sCode, $sLabel, $sDescription, $aMetaData, $aBadges, $sAbout);
$oExtensionDetails->GetToggler()->SetIsToggled(true);
- if ($bMissingFromDisk || $bCannotBeInstalled) {
+ if ($bMissingFromDisk || $bDependencyIssue) {
$oExtensionDetails->GetToggler()->SetIsToggled(false);
$oExtensionDetails->GetToggler()->SetIsDisabled(true);
} elseif ((!$bUninstallable || $bRemote) && !$bDisabled) {
@@ -71,10 +71,10 @@ class ExtensionDetailsUIBlockFactory extends AbstractUIBlockFactory
{
$aBadges = [];
$bUninstallable = $aExtraFlags['uninstallable'] ?? true;
- $bCannotBeInstalled = $aExtraFlags['cannot-be-installed'] ?? false;
+ $bDependencyIssue = $aExtraFlags['dependency_issue'] ?? false;
$bSelected = $aExtraFlags['selected'] ?? false;
$bDisabled = $aExtraFlags['disabled'] ?? false;
- self::AddExtraBadges($aBadges, $bUninstallable, false, $bCannotBeInstalled, $sCode);
+ self::AddExtraBadges($aBadges, $bUninstallable, false, $bDependencyIssue, $sCode);
$oBadgeInstalled = BadgeUIBlockFactory::MakeGrey(
Dict::S('UI:Layout:ExtensionsDetails:BadgeNotInstalled'),
Dict::S('UI:Layout:ExtensionsDetails:BadgeNotInstalled+'),
@@ -91,7 +91,7 @@ class ExtensionDetailsUIBlockFactory extends AbstractUIBlockFactory
$aBadges[] = $oBadgeToBeUninstalled;
$oExtensionDetails = new ExtensionDetails($sCode, $sLabel, $sDescription, $aMetaData, $aBadges, $sAbout);
- if ($bCannotBeInstalled) {
+ if ($bDependencyIssue) {
$oExtensionDetails->GetToggler()->SetIsToggled(false);
$oExtensionDetails->GetToggler()->SetIsDisabled(true);
}
@@ -107,7 +107,7 @@ class ExtensionDetailsUIBlockFactory extends AbstractUIBlockFactory
return $oExtensionDetails;
}
- private static function AddExtraBadges(array &$aBadges, bool $bUninstallable, bool $bMissingFromDisk, bool $bCannotBeInstalled, string $sCode)
+ private static function AddExtraBadges(array &$aBadges, bool $bUninstallable, bool $bMissingFromDisk, bool $bDependencyIssue, string $sCode)
{
if (!$bUninstallable) {
$aBadges[] = BadgeUIBlockFactory::MakeYellow(
@@ -123,7 +123,7 @@ class ExtensionDetailsUIBlockFactory extends AbstractUIBlockFactory
self::GetBadgeId($sCode, self::BADGE_ID_MISSING_FROM_DISK)
);
}
- if ($bCannotBeInstalled) {
+ if ($bDependencyIssue) {
$aBadges[] = BadgeUIBlockFactory::MakeOrange(
Dict::S('UI:Layout:ExtensionsDetails:BadgeCannotBeInstalled'),
Dict::S('UI:Layout:ExtensionsDetails:BadgeCannotBeInstalled+'),
diff --git a/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceTest.php b/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceTest.php
index 717ee8bd85..2f538a0fd9 100644
--- a/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceTest.php
+++ b/tests/php-unit-tests/unitary-tests/setup/WizStepModulesChoiceTest.php
@@ -49,6 +49,8 @@ class WizStepModulesChoiceTest extends ItopTestCase
'installed' => false,
'disabled' => false,
'checked' => false,
+ 'dependency_issue' => false,
+ 'mandatory' => false,
],
],
'A selected but not installed extension should be checked and enabled' => [
@@ -70,6 +72,8 @@ class WizStepModulesChoiceTest extends ItopTestCase
'installed' => false,
'disabled' => false,
'checked' => true,
+ 'dependency_issue' => false,
+ 'mandatory' => false,
],
],
'A missing extension should be disabled and unchecked' => [
@@ -89,6 +93,8 @@ class WizStepModulesChoiceTest extends ItopTestCase
'installed' => true,
'disabled' => true,
'checked' => false,
+ 'dependency_issue' => true,
+ 'mandatory' => false,
],
],
'A missing extension should always be disabled and unchecked, even when mandatory' => [
@@ -108,6 +114,8 @@ class WizStepModulesChoiceTest extends ItopTestCase
'installed' => true,
'disabled' => true,
'checked' => false,
+ 'dependency_issue' => true,
+ 'mandatory' => true,
],
],
'A missing extension should always be disabled and unchecked, even when non-uninstallable' => [
@@ -127,6 +135,8 @@ class WizStepModulesChoiceTest extends ItopTestCase
'installed' => true,
'disabled' => true,
'checked' => false,
+ 'dependency_issue' => true,
+ 'mandatory' => true,
],
],
'An installed but not selected extension should not be checked and be enabled' => [
@@ -148,6 +158,8 @@ class WizStepModulesChoiceTest extends ItopTestCase
'installed' => true,
'disabled' => false,
'checked' => false,
+ 'dependency_issue' => false,
+ 'mandatory' => false,
],
],
'An installed non uninstallable extension should be checked and disabled' => [
@@ -169,6 +181,8 @@ class WizStepModulesChoiceTest extends ItopTestCase
'installed' => true,
'disabled' => true,
'checked' => true,
+ 'dependency_issue' => false,
+ 'mandatory' => false,
],
],
'An installed non uninstallable extension should be enabled if the "disable uninstallation check" flag is set' => [
@@ -190,6 +204,8 @@ class WizStepModulesChoiceTest extends ItopTestCase
'installed' => true,
'disabled' => false,
'checked' => true,
+ 'dependency_issue' => false,
+ 'mandatory' => false,
],
],
'A mandatory extension should be checked and disabled' => [
@@ -211,6 +227,8 @@ class WizStepModulesChoiceTest extends ItopTestCase
'installed' => false,
'disabled' => true,
'checked' => true,
+ 'dependency_issue' => false,
+ 'mandatory' => true,
],
],
'A mandatory extension should be checked and disabled even if the "disable uninstallation check" flag is set' => [
@@ -232,6 +250,8 @@ class WizStepModulesChoiceTest extends ItopTestCase
'installed' => false,
'disabled' => true,
'checked' => true,
+ 'dependency_issue' => false,
+ 'mandatory' => true,
],
],
'An optional sub extension should not force its parent flags' => [
@@ -265,6 +285,8 @@ class WizStepModulesChoiceTest extends ItopTestCase
'installed' => false,
'disabled' => false,
'checked' => false,
+ 'dependency_issue' => false,
+ 'mandatory' => false,
],
],
'A mandatory sub extension should force its parent to be checked and disabled' => [
@@ -298,6 +320,8 @@ class WizStepModulesChoiceTest extends ItopTestCase
'installed' => false,
'disabled' => true,
'checked' => true,
+ 'dependency_issue' => false,
+ 'mandatory' => false,
],
],
'An installed non uninstallable sub extension should force its parent to be checked and disabled' => [
@@ -331,6 +355,8 @@ class WizStepModulesChoiceTest extends ItopTestCase
'installed' => true,
'disabled' => true,
'checked' => true,
+ 'dependency_issue' => false,
+ 'mandatory' => false,
],
],
'A non installed non uninstallable sub extension should not force its parent flags' => [
@@ -364,6 +390,62 @@ class WizStepModulesChoiceTest extends ItopTestCase
'installed' => true,
'disabled' => false,
'checked' => false,
+ 'dependency_issue' => false,
+ 'mandatory' => false,
+ ],
+ ],
+ 'A non installed extension with missing dependencies should be not checked and disabled' => [
+ 'aExtensionsOnDiskOrDb' => [
+ 'itop-ext1' => [
+ 'installed' => false,
+ 'missing_dependencies' => [
+ 'itop-ext1-1',
+ ],
+ ],
+ ],
+ 'aWizardStepDefinition' => [
+ 'extension_code' => 'itop-ext1',
+ 'mandatory' => false,
+ 'uninstallable' => true,
+ 'missing_dependencies' => true,
+ ],
+ 'bCurrentSelected' => false,
+ 'bDisableUninstallChecks' => false,
+ 'aExpectedFlags' => [
+ 'uninstallable' => true,
+ 'missing' => false,
+ 'installed' => false,
+ 'disabled' => true,
+ 'checked' => false,
+ 'dependency_issue' => true,
+ 'mandatory' => false,
+ ],
+ ],
+ 'An installed extension with missing dependencies should be not checked and disabled' => [
+ 'aExtensionsOnDiskOrDb' => [
+ 'itop-ext1' => [
+ 'installed' => true,
+ 'missing_dependencies' => [
+ 'itop-ext1-1',
+ ],
+ ],
+ ],
+ 'aWizardStepDefinition' => [
+ 'extension_code' => 'itop-ext1',
+ 'mandatory' => false,
+ 'uninstallable' => true,
+ 'missing_dependencies' => true,
+ ],
+ 'bCurrentSelected' => false,
+ 'bDisableUninstallChecks' => false,
+ 'aExpectedFlags' => [
+ 'uninstallable' => true,
+ 'missing' => false,
+ 'installed' => true,
+ 'disabled' => true,
+ 'checked' => false,
+ 'dependency_issue' => true,
+ 'mandatory' => false,
],
],
];
diff --git a/tests/php-unit-tests/unitary-tests/setup/iTopExtensionsMapFake.php b/tests/php-unit-tests/unitary-tests/setup/iTopExtensionsMapFake.php
index 8dbf59085c..ecc68c5ab5 100644
--- a/tests/php-unit-tests/unitary-tests/setup/iTopExtensionsMapFake.php
+++ b/tests/php-unit-tests/unitary-tests/setup/iTopExtensionsMapFake.php
@@ -23,6 +23,7 @@ class iTopExtensionsMapFake extends iTopExtensionsMap
$oExtension->sVersion = $aExtension['version'] ?? '1.0.0';
$oExtension->sSource = $aExtension['source'] ?? iTopExtension::SOURCE_MANUAL;
$oExtension->aModuleInfo = $aExtension['module_info'] ?? [];
+ $oExtension->aMissingDependencies = $aExtension['missing_dependencies'] ?? [];
$oMap->AddExtension($oExtension);
}
return $oMap;