mirror of
https://github.com/Combodo/iTop.git
synced 2026-05-22 00:32:16 +02:00
N°9167 Use ExtensionDetails UIBlocks instead of table (#910)
This commit is contained in:
@@ -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"] {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -31,20 +31,23 @@ use utils;
|
||||
class DataFeatureRemovalController extends Controller
|
||||
{
|
||||
private array $aRemovedExtensionsForCheck = [];
|
||||
private ?array $aExtensionsToCheck = null;
|
||||
private bool $bForcedUninstallation = false;
|
||||
private array $aCountClassesToCleanup = [];
|
||||
private array $aAnalysisDataTable = [];
|
||||
private array $aDeletionExecutionSummary = [];
|
||||
|
||||
private int $iCount = 0;
|
||||
private int $iColumnCount = 2;
|
||||
|
||||
public function OperationMain($sErrorMessage = null): void
|
||||
{
|
||||
$aParams = [];
|
||||
|
||||
$this->ReadRemovedExtensions();
|
||||
$this->AddAnalyzeParams();
|
||||
$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['aClasses'] = array_keys($this->aCountClassesToCleanup);
|
||||
$aParams['DataFeatureRemovalErrorMessage'] = $sErrorMessage;
|
||||
@@ -76,12 +79,11 @@ class DataFeatureRemovalController extends Controller
|
||||
|
||||
public function OperationAnalyze(): void
|
||||
{
|
||||
$this->ReadRemovedExtensions();
|
||||
$iCount = $this->ReadExtensionsDiff();
|
||||
|
||||
$this->m_sOperation = 'Main';
|
||||
|
||||
try {
|
||||
if (count($this->aRemovedExtensionsForCheck) > 0) {
|
||||
if ($iCount > 0) {
|
||||
$this->Analyze();
|
||||
}
|
||||
$this->OperationMain();
|
||||
@@ -93,7 +95,8 @@ class DataFeatureRemovalController extends Controller
|
||||
|
||||
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();
|
||||
$oSetupAudit = new SetupAudit($sSourceEnv);
|
||||
$aGetRemovedClasses = $oSetupAudit->RunDataAudit();
|
||||
@@ -148,7 +151,8 @@ class DataFeatureRemovalController extends Controller
|
||||
|
||||
$aParams['sTransactionId'] = utils::GetNewTransactionId();
|
||||
$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);
|
||||
$aParams['sLaunchSetupUrl'] = utils::GetAbsoluteUrlAppRoot().'setup/wizard.php';
|
||||
@@ -261,72 +265,51 @@ class DataFeatureRemovalController extends Controller
|
||||
$this->OperationAnalysisResult();
|
||||
}
|
||||
|
||||
private function GetExtensionsTableDiff(array $aAddedExtensions, array $aRemovedExtensions): array
|
||||
private function GetAvailableExtensions(bool $bIncludePackageExtensions = false): array
|
||||
{
|
||||
$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'),
|
||||
];
|
||||
$aExtensionsData = [];
|
||||
if ($bIncludePackageExtensions) {
|
||||
$aExtensionsRef = DataFeatureRemoverExtensionService::GetInstance()->GetExtensionMap()->GetAllExtensionsWithPreviouslyInstalled();
|
||||
} else {
|
||||
$aExtensionsRef = DataFeatureRemoverExtensionService::GetInstance()->ReadItopExtensions();
|
||||
}
|
||||
|
||||
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 ($aExtensionsRef as $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
|
||||
@@ -370,27 +353,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) {
|
||||
return;
|
||||
if (!is_null($this->aExtensionsToCheck)) {
|
||||
return count($this->aExtensionsToCheck['to_be_installed']) + count($this->aExtensionsToCheck['to_be_removed']);
|
||||
}
|
||||
|
||||
$aSelectedExtensionsFromUI = utils::ReadPostedParam('aExtensions', []);
|
||||
foreach ($aSelectedExtensionsFromUI as $sCode => $aData) {
|
||||
$sValue = $aData['enable'] ?? 'off';
|
||||
if (($sValue) === 'on') {
|
||||
$this->aRemovedExtensionsForCheck[] = $sCode;
|
||||
}
|
||||
$aAvailableExtensions = $this->GetAvailableExtensions();
|
||||
$aSelectedExtensionsFromUI = utils::ReadPostedParam('aSelectedExtensions', []);
|
||||
$this->aExtensionsToCheck = [
|
||||
'to_be_installed' => [],
|
||||
'to_be_removed' => [],
|
||||
];
|
||||
foreach ($aAvailableExtensions as $sCode => &$aExtensionData) {
|
||||
if (!isset($aSelectedExtensionsFromUI[$sCode])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add source removed to check
|
||||
foreach (DataFeatureRemoverExtensionService::GetInstance()->ReadItopExtensions() as $sCode => $oExtension) {
|
||||
if ($oExtension->bRemovedFromDisk) {
|
||||
$this->aRemovedExtensionsForCheck[] = $sCode;
|
||||
if ($aExtensionData['installed'] && $aSelectedExtensionsFromUI[$sCode] !== 'on') {
|
||||
$aExtensionData['extra_flags']['selected'] = false;
|
||||
$this->aExtensionsToCheck['to_be_removed'][] = $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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ use MetaModel;
|
||||
class DataFeatureRemoverExtensionService
|
||||
{
|
||||
private static DataFeatureRemoverExtensionService $oInstance;
|
||||
|
||||
private ?iTopExtensionsMap $oMap = null;
|
||||
private array $aItopExtensions = [];
|
||||
private array $aIncludingExtensionsByModuleName = [];
|
||||
|
||||
@@ -60,15 +60,25 @@ class DataFeatureRemoverExtensionService
|
||||
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[]
|
||||
*/
|
||||
public function ReadItopExtensions(): array
|
||||
{
|
||||
if (count($this->aItopExtensions) === 0) {
|
||||
$oExtensionsMap = new iTopExtensionsMap();
|
||||
$oExtensionsMap->LoadInstalledExtensionsFromDatabase(MetaModel::GetConfig());
|
||||
$this->aItopExtensions = $oExtensionsMap->GetAllExtensionsToDisplayInSetup(true);
|
||||
$this->aItopExtensions = $this->GetExtensionMap()->GetAllExtensionsToDisplayInSetup(true);
|
||||
|
||||
uasort($this->aItopExtensions, function (iTopExtension $oiTopExtension1, iTopExtension $oiTopExtension2) {
|
||||
return strcmp($oiTopExtension1->sLabel, $oiTopExtension2->sLabel);
|
||||
|
||||
@@ -4,10 +4,21 @@
|
||||
|
||||
|
||||
{% UIPanel ForInformation { sTitle:'DataFeatureRemoval:Analysis:Title'|dict_s} %}
|
||||
|
||||
{% UIFieldSet Standard {sLegend:'DataFeatureRemoval:Features:Title'|dict_s} %}
|
||||
{% UIDataTable ForForm { sRef:'aExtensions', aColumns:aExtensions.Columns, aData:aExtensions.Data} %}{% EndUIDataTable %}
|
||||
{% EndUIFieldSet %}
|
||||
{% 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 bDeletionNeeded %}
|
||||
{% UIFieldSet Standard {sLegend:'DataFeatureRemoval:DeletionPlan:Title'|dict_s} %}
|
||||
|
||||
@@ -6,9 +6,21 @@
|
||||
{% UIInput ForHidden {sName:'operation', sValue:'Analyze'} %}
|
||||
{% UIInput ForHidden {sName:'transaction_id', sValue:sTransactionId} %}
|
||||
|
||||
{% UIFieldSet Standard {sLegend:'DataFeatureRemoval:Features:Title'|dict_s} %}
|
||||
{% UIDataTable ForForm { sRef:'aExtensions', aColumns:aExtensions.Columns, aData:aExtensions.Data} %}{% EndUIDataTable %}
|
||||
{% EndUIFieldSet %}
|
||||
{% 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 %}
|
||||
|
||||
{% UIToolbar ForButton {} %}
|
||||
{% UIButton ForPrimaryAction {sLabel:'UI:Button:Analyze'|dict_s, sName:'btn_apply', sId:'btn_apply', bIsSubmit:true} %}
|
||||
|
||||
@@ -20,4 +20,5 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', [
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~',
|
||||
'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions~~',
|
||||
]);
|
||||
|
||||
@@ -20,4 +20,5 @@ Dict::Add('DA DA', 'Danish', 'Dansk', [
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~',
|
||||
'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions~~',
|
||||
]);
|
||||
|
||||
@@ -20,4 +20,5 @@ Dict::Add('DE DE', 'German', 'Deutsch', [
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~',
|
||||
'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions~~',
|
||||
]);
|
||||
|
||||
@@ -18,4 +18,5 @@ Dict::Add('EN US', 'English', 'English', [
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall',
|
||||
'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions',
|
||||
]);
|
||||
|
||||
@@ -20,4 +20,5 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', [
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~',
|
||||
'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions~~',
|
||||
]);
|
||||
|
||||
@@ -20,4 +20,5 @@ Dict::Add('FR FR', 'French', 'Français', [
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'À propos de %1$s',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'Plus d\'informations',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Forcer la désinstallation',
|
||||
'UI:Layout:ExtensionsDetails:MoreActions' => 'Plus d\'actions',
|
||||
]);
|
||||
|
||||
@@ -20,4 +20,5 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', [
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~',
|
||||
'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions~~',
|
||||
]);
|
||||
|
||||
@@ -20,4 +20,5 @@ Dict::Add('IT IT', 'Italian', 'Italiano', [
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~',
|
||||
'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions~~',
|
||||
]);
|
||||
|
||||
@@ -20,4 +20,5 @@ Dict::Add('JA JP', 'Japanese', '日本語', [
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~',
|
||||
'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions~~',
|
||||
]);
|
||||
|
||||
@@ -20,4 +20,5 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', [
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~',
|
||||
'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions~~',
|
||||
]);
|
||||
|
||||
@@ -20,4 +20,5 @@ Dict::Add('PL PL', 'Polish', 'Polski', [
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~',
|
||||
'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions~~',
|
||||
]);
|
||||
|
||||
@@ -20,4 +20,5 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', [
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~',
|
||||
'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions~~',
|
||||
]);
|
||||
|
||||
@@ -20,4 +20,5 @@ Dict::Add('RU RU', 'Russian', 'Русский', [
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~',
|
||||
'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions~~',
|
||||
]);
|
||||
|
||||
@@ -20,4 +20,5 @@ Dict::Add('SK SK', 'Slovak', 'Slovenčina', [
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~',
|
||||
'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions~~',
|
||||
]);
|
||||
|
||||
@@ -20,4 +20,5 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', [
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~',
|
||||
'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions~~',
|
||||
]);
|
||||
|
||||
@@ -20,4 +20,5 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', [
|
||||
'UI:Layout:ExtensionsDetails:MenuAboutTitle' => 'About %1$s~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuAbout' => 'More informations~~',
|
||||
'UI:Layout:ExtensionsDetails:MenuForce' => 'Force uninstall~~',
|
||||
'UI:Layout:ExtensionsDetails:MoreActions' => 'Show more actions~~',
|
||||
]);
|
||||
|
||||
@@ -486,7 +486,7 @@ class iTopExtensionsMap
|
||||
'default' => true, // by default offer to install all modules
|
||||
'modules' => $oExtension->aModules,
|
||||
'mandatory' => $oExtension->bMandatory,
|
||||
'source_label' => $this->GetExtensionSourceLabel($oExtension->sSource),
|
||||
'source_label' => $oExtension->GetExtensionSourceLabel(),
|
||||
'uninstallable' => $oExtension->CanBeUninstalled(),
|
||||
'missing' => $oExtension->bRemovedFromDisk,
|
||||
'version' => $oExtension->sVersion,
|
||||
@@ -496,22 +496,6 @@ class iTopExtensionsMap
|
||||
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
|
||||
* @param string $sExtensionCode The code of the extension (code without version number)
|
||||
|
||||
@@ -8,7 +8,7 @@ use SetupUtils;
|
||||
|
||||
class DryRemovalRuntimeEnvironment extends RunTimeEnvironment
|
||||
{
|
||||
protected array $aExtensionsByCode;
|
||||
protected array $aExtensionsToRemoveByCode;
|
||||
|
||||
/**
|
||||
* Toolset for building a run-time environment
|
||||
@@ -18,7 +18,7 @@ class DryRemovalRuntimeEnvironment extends RunTimeEnvironment
|
||||
public function __construct($sSourceEnv = 'production', array $aExtensionCodesToRemove = [])
|
||||
{
|
||||
parent::__construct($sSourceEnv, false);
|
||||
$this->aExtensionsByCode = $aExtensionCodesToRemove;
|
||||
$this->aExtensionsToRemoveByCode = $aExtensionCodesToRemove;
|
||||
$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."/conf/$sSourceEnv", APPROOT."/conf/$sBuildEnv");
|
||||
|
||||
$this->DeclareExtensionAsRemoved($this->aExtensionsByCode);
|
||||
$this->DeclareExtensionAsRemoved($this->aExtensionsToRemoveByCode);
|
||||
}
|
||||
|
||||
private function DeclareExtensionAsRemoved(array $aExtensionCodes): void
|
||||
|
||||
@@ -169,4 +169,18 @@ class iTopExtension
|
||||
return json_encode($this->__serialize(), JSON_PRETTY_PRINT);
|
||||
}
|
||||
|
||||
public function GetExtensionSourceLabel(): string
|
||||
{
|
||||
return match ($this->sSource) {
|
||||
self::SOURCE_MANUAL => 'Local extensions folder',
|
||||
self::SOURCE_REMOTE => (ITOP_APPLICATION == 'iTop') ? 'iTop Hub' : 'ITSM Designer',
|
||||
self::SOURCE_WIZARD => 'iTop package',
|
||||
default => '',
|
||||
};
|
||||
}
|
||||
|
||||
public function IsRemote(): string
|
||||
{
|
||||
return $this->sSource === self::SOURCE_REMOTE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ class ExtensionDetails extends UIContentBlock
|
||||
$this->sCode = $sCode;
|
||||
$this->sLabel = $sLabel;
|
||||
$this->sDescription = $sDescription;
|
||||
$this->aMetaData = $aMetaData;
|
||||
$this->aMetaData = array_filter($aMetaData);
|
||||
$this->aBadges = $aBadges;
|
||||
$this->sAbout = $sAbout;
|
||||
$this->InitializeToggler();
|
||||
@@ -105,7 +105,7 @@ class ExtensionDetails extends UIContentBlock
|
||||
*/
|
||||
public function SetMetaData(array $aMetaData): static
|
||||
{
|
||||
$this->aMetaData = $aMetaData;
|
||||
$this->aMetaData = array_filter($aMetaData);
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -179,13 +179,22 @@ class ExtensionDetails extends UIContentBlock
|
||||
|
||||
protected function InitializeToggler()
|
||||
{
|
||||
$sName = 'aSelectedExtensions['.$this->GetCode().']';
|
||||
$this->oToggler = new Toggler();
|
||||
$this->oToggler->SetName('ExtensionToggler');
|
||||
$this->oToggler->SetName($sName);
|
||||
$this->oToggler->AddCSSClass('toggler-install');
|
||||
}
|
||||
|
||||
protected function InitializePopoverMenu()
|
||||
{
|
||||
$this->oPopoverMenu = new PopoverMenu();
|
||||
$oPopoverOpenButton = ButtonUIBlockFactory::MakeIconAction('fas fa-ellipsis-v', Dict::S('UI:Layout:ExtensionsDetails:MoreActions'));
|
||||
$this->oPopoverMenu->SetTogglerFromBlock($oPopoverOpenButton);
|
||||
$this->oMoreActions = new UIContentBlock();
|
||||
$this->oMoreActions->AddSubBlock($this->oPopoverMenu);
|
||||
$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(
|
||||
@@ -198,13 +207,9 @@ class ExtensionDetails extends UIContentBlock
|
||||
});
|
||||
JS,
|
||||
);
|
||||
$this->oPopoverMenu = new PopoverMenu();
|
||||
$this->oPopoverMenu->AddItem('more-actions', PopoverMenuItemFactory::MakeFromApplicationPopupMenuItem($oModifyButton));
|
||||
$oPopoverOpenButton = ButtonUIBlockFactory::MakeIconAction('fas fa-ellipsis-v', 'Show more actions');
|
||||
$this->oPopoverMenu->SetTogglerFromBlock($oPopoverOpenButton);
|
||||
$this->oMoreActions = new UIContentBlock();
|
||||
$this->oMoreActions->AddSubBlock($this->oPopoverMenu);
|
||||
$this->oMoreActions->AddSubBlock($oPopoverOpenButton);
|
||||
$this->oPopoverMenu->AddItem('more-details', PopoverMenuItemFactory::MakeFromApplicationPopupMenuItem($oModifyButton));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function AllowForceUninstall()
|
||||
@@ -213,10 +218,11 @@ JS,
|
||||
'force_uninstall',
|
||||
Dict::S('UI:Layout:ExtensionsDetails:MenuForce'),
|
||||
<<<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,
|
||||
);
|
||||
$this->oPopoverMenu->AddItem('more-actions', PopoverMenuItemFactory::MakeFromApplicationPopupMenuItem($oForceUninstallButton));
|
||||
$this->oPopoverMenu->AddItem('force-uninstall', PopoverMenuItemFactory::MakeFromApplicationPopupMenuItem($oForceUninstallButton));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -18,6 +18,9 @@ class ExtensionDetailsUIBlockFactory extends AbstractUIBlockFactory
|
||||
$aBadges = [];
|
||||
$bUninstallable = $aExtraFlags['uninstallable'] ?? true;
|
||||
$bMissingFromDisk = $aExtraFlags['missing'] ?? false;
|
||||
$bSelected = $aExtraFlags['selected'] ?? true;
|
||||
$bDisabled = $aExtraFlags['disabled'] ?? false;
|
||||
$bRemote = $aExtraFlags['remote'] ?? false;
|
||||
self::AddExtraBadges($aBadges, $bUninstallable, $bMissingFromDisk);
|
||||
$oBadgeInstalled = BadgeUIBlockFactory::MakeGreen(Dict::S('UI:Layout:ExtensionsDetails:BadgeInstalled'));
|
||||
$oBadgeInstalled->AddCSSClass('checked');
|
||||
@@ -28,10 +31,22 @@ class ExtensionDetailsUIBlockFactory extends AbstractUIBlockFactory
|
||||
|
||||
$oExtensionDetails = new ExtensionDetails($sCode, $sLabel, $sDescription, $aMetaData, $aBadges, $sAbout);
|
||||
$oExtensionDetails->GetToggler()->SetIsToggled(true);
|
||||
if (!$bUninstallable) {
|
||||
if ($bMissingFromDisk) {
|
||||
$oExtensionDetails->GetToggler()->SetIsToggled(false);
|
||||
$oExtensionDetails->GetToggler()->SetIsDisabled(true);
|
||||
} elseif (!$bUninstallable || $bRemote) {
|
||||
$oExtensionDetails->AllowForceUninstall();
|
||||
$oExtensionDetails->GetToggler()->SetIsDisabled(true);
|
||||
}
|
||||
|
||||
if (!$bSelected) {
|
||||
$oExtensionDetails->GetToggler()->SetIsToggled(false);
|
||||
}
|
||||
if ($bDisabled) {
|
||||
$oExtensionDetails->GetToggler()->SetIsDisabled(true);
|
||||
$oExtensionDetails->GetToggler()->AddCSSClass('ibo-is-hidden');
|
||||
}
|
||||
|
||||
return $oExtensionDetails;
|
||||
}
|
||||
|
||||
@@ -39,6 +54,8 @@ class ExtensionDetailsUIBlockFactory extends AbstractUIBlockFactory
|
||||
{
|
||||
$aBadges = [];
|
||||
$bUninstallable = $aExtraFlags['uninstallable'] ?? true;
|
||||
$bSelected = $aExtraFlags['selected'] ?? false;
|
||||
$bDisabled = $aExtraFlags['disabled'] ?? false;
|
||||
self::AddExtraBadges($aBadges, $bUninstallable, false);
|
||||
$oBadgeInstalled = BadgeUIBlockFactory::MakeGrey(Dict::S('UI:Layout:ExtensionsDetails:BadgeNotInstalled'));
|
||||
$oBadgeInstalled->AddCSSClass('unchecked');
|
||||
@@ -46,8 +63,17 @@ class ExtensionDetailsUIBlockFactory extends AbstractUIBlockFactory
|
||||
$oBadgeToBeUninstalled = BadgeUIBlockFactory::MakeCyan(Dict::S('UI:Layout:ExtensionsDetails:BadgeToBeInstalled'));
|
||||
$oBadgeToBeUninstalled->AddCSSClass('checked');
|
||||
$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)
|
||||
|
||||
@@ -3,5 +3,6 @@
|
||||
<span class="ibo-toggler--wrapper">
|
||||
{{ parent() }}
|
||||
<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>
|
||||
{% endblock %}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
|
||||
$('#{{ oUIBlock.GetId() }}').parent().on('click', function() {
|
||||
let oInput = $(this).find('.ibo-toggler');
|
||||
let oHiddenInput = $(this).find('.ibo-toggler--hidden');
|
||||
if (!oInput.prop('disabled')) {
|
||||
oInput.prop('checked', !oInput.prop('checked'));
|
||||
oHiddenInput.val(oInput.prop('checked') ? 'on' : 'off');
|
||||
oInput.trigger('change');
|
||||
}
|
||||
});
|
||||
@@ -639,6 +639,9 @@ $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]);
|
||||
$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]);
|
||||
$oColumnRight->AddSubBlock($oExtensionDetailInstalledWithLongTitle);
|
||||
$oPage->add('<hr id="page_bottom"/>');
|
||||
|
||||
Reference in New Issue
Block a user