mirror of
https://github.com/Combodo/iTop.git
synced 2026-06-01 21:52:17 +02:00
Compare commits
2 Commits
feature/95
...
feature/96
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38e8bacd07 | ||
|
|
2ecd2d7a96 |
@@ -14,8 +14,6 @@ class CoreException extends Exception
|
||||
/**
|
||||
* CoreException constructor.
|
||||
*
|
||||
* ATTENTION: Logging here will break the CI
|
||||
*
|
||||
* @param string $sIssue error message
|
||||
* @param array|null $aContextData key/value array, value MUST implements _toString
|
||||
* @param string $sImpact
|
||||
|
||||
@@ -20,6 +20,16 @@
|
||||
*
|
||||
*/
|
||||
|
||||
use Combodo\iTop\PhpParser\Evaluation\PhpExpressionEvaluator;
|
||||
use Combodo\iTop\Setup\ModuleDiscovery\ModuleFileReaderException;
|
||||
use PhpParser\Comment;
|
||||
use PhpParser\Error;
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr\Array_;
|
||||
use PhpParser\Node\Expr\Assign;
|
||||
use PhpParser\Node\Expr\Variable;
|
||||
use PhpParser\ParserFactory;
|
||||
|
||||
define('ITOP_APPLICATION', 'iTop');
|
||||
define('ITOP_APPLICATION_SHORT', 'iTop');
|
||||
|
||||
@@ -2124,6 +2134,29 @@ class Config
|
||||
eval('?'.'>'.trim($sConfigCode));
|
||||
$sNoise = trim(ob_get_contents());
|
||||
ob_end_clean();
|
||||
|
||||
try {
|
||||
$oParser = (new ParserFactory())->createForNewestSupportedVersion();
|
||||
foreach ($oParser->parse($sConfigCode) as $oNode) {
|
||||
if ($oNode instanceof \PhpParser\Node\Stmt\Expression) {
|
||||
/** @var \PhpParser\Node\Stmt\Expression $oNode */
|
||||
$oExpr = $oNode->expr;
|
||||
if ($oExpr instanceof Assign) {
|
||||
/** @var Assign $oExpr */
|
||||
$oVar = $oExpr->var;
|
||||
if ($oVar instanceof Variable && $oVar->name === "MyModuleSettings") {
|
||||
if ($oExpr->expr instanceof Array_) {
|
||||
$oPhpExpressionEvaluator = new PhpExpressionEvaluator();
|
||||
$aArrayWithComments = $oPhpExpressionEvaluator->GetArrayWithComments($oExpr->expr);
|
||||
$MyModuleSettings = array_replace_recursive($aArrayWithComments, $MyModuleSettings);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Error $e) {
|
||||
var_dump($e);
|
||||
}
|
||||
} catch (Error $e) {
|
||||
// PHP 7
|
||||
throw new ConfigException(
|
||||
@@ -2714,6 +2747,15 @@ class Config
|
||||
foreach ($this->m_aModuleSettings as $sModule => $aProperties) {
|
||||
fwrite($hFile, "\t'$sModule' => array (\n");
|
||||
foreach ($aProperties as $sProperty => $value) {
|
||||
if (is_string($value) && false !== strpos($value, 'PhpParserComment')) {
|
||||
$value = preg_replace(
|
||||
["/.*StartPhpParserComment/", "/EndPhpParserComment/"],
|
||||
['', ''],
|
||||
$value
|
||||
);
|
||||
fwrite($hFile, "\t\t$value\n");
|
||||
continue;
|
||||
}
|
||||
$sNiceExport = self::PrettyVarExport($this->oItopConfigParser->GetVarValue('MyModuleSettings', $sProperty), $value, "\t\t");
|
||||
fwrite($hFile, "\t\t'$sProperty' => $sNiceExport,\n");
|
||||
}
|
||||
@@ -2883,7 +2925,7 @@ class Config
|
||||
}
|
||||
|
||||
/**
|
||||
* Pretty format a var_export'ed value so that (if possible) the identation is preserved on every line
|
||||
* Pretty format a var_export'ed value so that (if possible) the indentation is preserved on every line
|
||||
*
|
||||
* @param array $aParserValue
|
||||
* @param mixed $value The value to export
|
||||
@@ -2900,12 +2942,19 @@ class Config
|
||||
}
|
||||
|
||||
$sExport = var_export($value, true);
|
||||
if (strpos($sExport, 'PhpParserComment')) {
|
||||
$sExport = preg_replace(
|
||||
["/.*StartPhpParserComment/", "/EndPhpParserComment',/"],
|
||||
['', ''],
|
||||
$sExport
|
||||
);
|
||||
}
|
||||
$sNiceExport = str_replace(["\r\n", "\n", "\r"], "\n".$sIndentation, trim($sExport));
|
||||
if (!$bForceIndentation) {
|
||||
/** @var array $aImported */
|
||||
$aImported = null;
|
||||
eval('$aImported='.$sNiceExport.';');
|
||||
// Check if adding the identations at the beginning of each line
|
||||
// Check if adding the indentations at the beginning of each line
|
||||
// did not modify the values (in case of a string containing a line break)
|
||||
if ($aImported != $value) {
|
||||
$sNiceExport = $sExport;
|
||||
@@ -2914,7 +2963,6 @@ class Config
|
||||
|
||||
return $sNiceExport;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class ConfigPlaceholdersResolver
|
||||
|
||||
@@ -62,15 +62,4 @@ $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;
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -699,10 +699,14 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
#progress_content *:not(.message) + .message {
|
||||
#progress_content {
|
||||
min-height: 200px;
|
||||
overflow: auto;
|
||||
text-align: center;
|
||||
*:not(.message) + .message {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
#fresh_content{
|
||||
border: 0;
|
||||
min-height: 300px;
|
||||
|
||||
@@ -10,42 +10,38 @@
|
||||
*/
|
||||
|
||||
Dict::Add('EN US', 'English', 'English', [
|
||||
'Menu:DataFeatureRemovalMenu' => 'Extension management',
|
||||
'combodo-data-feature-removal/Operation:Main/Title' => 'Extension management',
|
||||
'Menu:DataFeatureRemovalMenu' => 'Features Removal',
|
||||
'combodo-data-feature-removal/Operation:Main/Title' => 'Features Removal',
|
||||
|
||||
'DataFeatureRemoval:Main:Title' => 'Extension management',
|
||||
'DataFeatureRemoval:Main:SubTitle' => 'Toggle extensions installed on your iTop',
|
||||
'DataFeatureRemoval:Failure:Title' => 'Extensions dry removal errors',
|
||||
'DataFeatureRemoval:Helper:Title' => 'Analyze if there are any data or dependency preventing you from adding/removing an extension.',
|
||||
'DataFeatureRemoval:Main:Title' => 'Features Removal',
|
||||
'DataFeatureRemoval:Main:SubTitle' => 'Prepare features you want to enable/disable in a future setup',
|
||||
'DataFeatureRemoval:Failure:Title' => 'Feature dry removal errors',
|
||||
'DataFeatureRemoval:Helper:Title' => 'Enable or disable features that are installed in your iTop.',
|
||||
'DataFeatureRemoval:Helper:Desc1' => 'It will prepare the setup step that proceeds to feature enabling or disabling.',
|
||||
'DataFeatureRemoval:Helper:Desc2' => 'Analyze if there are any data or dependency preventing you from enabling/disabling a feature.',
|
||||
|
||||
'DataFeatureRemoval:Features:Title' => 'Extensions',
|
||||
'DataFeatureRemoval:Result:Title' => 'Modification requested',
|
||||
'DataFeatureRemoval:Execution:Title' => 'Deletion Executions',
|
||||
'DataFeatureRemoval:Features:Title' => 'Features',
|
||||
'DataFeatureRemoval:Analysis:Title' => 'Analysis result',
|
||||
'DataFeatureRemoval:Analysis:Subtitle' => 'Review all elements requiring attention',
|
||||
'DataFeatureRemoval:Analysis:SubTitle' => '%1$s element(s) to clean before continuing',
|
||||
|
||||
'DataFeatureRemoval:DeletionPlan:Title' => 'Data deletion plan',
|
||||
'DataFeatureRemoval:DeletionPlan:Title' => 'Deletion plan',
|
||||
'DataFeatureRemoval:DeletionPlan:SubTitle' => '%1$s rows to clean before continuing',
|
||||
'DataFeatureRemoval:DoDeletion:Title' => 'Do deletion',
|
||||
'DataFeatureRemoval:DoDeletion:SubTitle' => 'Remove all the entries from the database',
|
||||
'DataFeatureRemoval:DeletionPlan:Error:Issues' => 'Some objects must be deleted manually prior to cleanup',
|
||||
|
||||
'DataFeatureRemoval:Table:Analysis:ClassName' => 'Element to remove',
|
||||
'DataFeatureRemoval:Table:Analysis:FeatureName' => 'Extension name',
|
||||
'DataFeatureRemoval:Table:Analysis:FeatureName' => 'Feature name',
|
||||
'DataFeatureRemoval:Table:Analysis:Module' => 'Module name',
|
||||
'DataFeatureRemoval:Table:Analysis:Occurrence' => 'Occurrence',
|
||||
|
||||
'DataFeatureRemoval:CleanupComplete:Title' => 'All clear.',
|
||||
'DataFeatureRemoval:CompilComplete' => 'Compilation successful. No Cleanup needed. You can proceed to setup.',
|
||||
|
||||
'UI:Button:Analyze' => 'Analyze',
|
||||
'UI:Button:ModifyChoices' => 'Change my selection',
|
||||
'UI:Button:ModifyChoices' => 'Modify Choices',
|
||||
'UI:Button:AnalyzeAndSetup' => 'Analyze and go to setup',
|
||||
'UI:Button:PlanDeletion' => 'Proceed with deletion',
|
||||
'UI:Button:DoDeletion' => 'Proceed with deletion',
|
||||
'UI:Button:BackToMain' => 'Change my selection',
|
||||
'UI:Button:Setup' => 'Run setup',
|
||||
'UI:Button:PlanDeletion' => 'Prepare deletion plan',
|
||||
'UI:Button:DoDeletion' => 'Delete data',
|
||||
'UI:Button:BackToMain' => 'Back to Feature Removal',
|
||||
'UI:Button:Setup' => 'Back to setup',
|
||||
|
||||
'UI:Action:ForceUninstall' => 'Force uninstall',
|
||||
'UI:Action:MoreInfo' => 'More information',
|
||||
|
||||
@@ -10,42 +10,38 @@
|
||||
*/
|
||||
|
||||
Dict::Add('FR FR', 'French', 'Français', [
|
||||
'Menu:DataFeatureRemovalMenu' => 'Gestion des extensions',
|
||||
'combodo-data-feature-removal/Operation:Main/Title' => 'Gestion des extensions',
|
||||
'Menu:DataFeatureRemovalMenu' => 'Suppression de fonctionnalités',
|
||||
'combodo-data-feature-removal/Operation:Main/Title' => 'Suppression de fonctionnalités',
|
||||
|
||||
'DataFeatureRemoval:Main:Title' => 'Gestion des extensions',
|
||||
'DataFeatureRemoval:Main:SubTitle' => 'Sélectionner les extensions à installer sur votre iTop',
|
||||
'DataFeatureRemoval:Failure:Title' => 'Erreurs lors de la simulation de suppression d\'extensions',
|
||||
'DataFeatureRemoval:Helper:Title' => 'Activez ou désactivez les extensions installées dans votre iTop.',
|
||||
'DataFeatureRemoval:Main:Title' => 'Suppression de fonctionnalités',
|
||||
'DataFeatureRemoval:Main:SubTitle' => 'Préparez les fonctionnalités que vous souhaitez activer ou désactiver lors d’une prochaine configuration',
|
||||
'DataFeatureRemoval:Failure:Title' => 'Erreurs lors de la simulation de suppression de fonctionnalités',
|
||||
'DataFeatureRemoval:Helper:Title' => 'Activez ou désactivez les fonctionnalités installées dans votre iTop.',
|
||||
'DataFeatureRemoval:Helper:Desc1' => 'Cette étape prépare l’assistant de configuration à activer ou désactiver des fonctionnalités.',
|
||||
'DataFeatureRemoval:Helper:Desc2' => 'Analyse si des données ou des dépendances empêchent l’activation ou la désactivation d’une fonctionnalité.',
|
||||
|
||||
'DataFeatureRemoval:Features:Title' => 'Extensions',
|
||||
'DataFeatureRemoval:Result:Title' => 'Modification demandée',
|
||||
'DataFeatureRemoval:Execution:Title' => 'Suppressions',
|
||||
'DataFeatureRemoval:Features:Title' => 'Fonctionnalités',
|
||||
'DataFeatureRemoval:Analysis:Title' => 'Résultat de l’analyse',
|
||||
'DataFeatureRemoval:Analysis:Subtitle' => 'Vérifier les éléments à nettoyer',
|
||||
'DataFeatureRemoval:Analysis:SubTitle' => '%1$s élément(s) à nettoyer avant de poursuivre',
|
||||
|
||||
'DataFeatureRemoval:DeletionPlan:Title' => 'Plan de suppression des données',
|
||||
'DataFeatureRemoval:DeletionPlan:Title' => 'Plan de suppression',
|
||||
'DataFeatureRemoval:DeletionPlan:SubTitle' => '%1$s ligne(s) à nettoyer avant de poursuivre',
|
||||
'DataFeatureRemoval:DoDeletion:Title' => 'Exécuter la suppression',
|
||||
'DataFeatureRemoval:DoDeletion:SubTitle' => 'Supprime toutes les entrées de la base de données',
|
||||
'DataFeatureRemoval:DeletionPlan:Error:Issues' => 'Certains objets doivent être supprimés manuellement avant le nettoyage',
|
||||
|
||||
'DataFeatureRemoval:Table:Analysis:ClassName' => 'Élément à supprimer',
|
||||
'DataFeatureRemoval:Table:Analysis:FeatureName' => 'Extension',
|
||||
'DataFeatureRemoval:Table:Analysis:FeatureName' => 'Fonctionnalité',
|
||||
'DataFeatureRemoval:Table:Analysis:Module' => 'Module',
|
||||
'DataFeatureRemoval:Table:Analysis:Occurrence' => 'Occurrence',
|
||||
|
||||
'DataFeatureRemoval:CleanupComplete:Title' => 'All clear.',
|
||||
'DataFeatureRemoval:CompilComplete' => 'Compilation successful. No Cleanup needed. You can proceed to setup.',
|
||||
|
||||
'UI:Button:Analyze' => 'Analyser',
|
||||
'UI:Button:ModifyChoices' => 'Modifier la sélection',
|
||||
'UI:Button:ModifyChoices' => 'Modifier les choix',
|
||||
'UI:Button:AnalyzeAndSetup' => 'Analyser et ouvrir l’assistant de configuration',
|
||||
'UI:Button:PlanDeletion' => 'Supprimer les données',
|
||||
'UI:Button:PlanDeletion' => 'Préparer le plan de suppression',
|
||||
'UI:Button:DoDeletion' => 'Supprimer les données',
|
||||
'UI:Button:BackToMain' => 'Modifier la sélection',
|
||||
'UI:Button:Setup' => 'Lancer le setup',
|
||||
'UI:Button:BackToMain' => 'Retour à la suppression de fonctionnalités',
|
||||
'UI:Button:Setup' => 'Retour à l’assistant de configuration',
|
||||
|
||||
'UI:Action:ForceUninstall' => 'Forcer la désinstallation',
|
||||
'UI:Action:MoreInfo' => 'Plus d’informations',
|
||||
|
||||
@@ -10,45 +10,35 @@ namespace Combodo\iTop\DataFeatureRemoval\Controller;
|
||||
require_once APPROOT.'setup/feature_removal/SetupAudit.php';
|
||||
require_once APPROOT.'setup/feature_removal/DryRemovalRuntimeEnvironment.php';
|
||||
|
||||
use Combodo\iTop\Application\Helper\Session;
|
||||
use Combodo\iTop\Application\TwigBase\Controller\Controller;
|
||||
use Combodo\iTop\DataFeatureRemoval\Entity\DataCleanupSummaryEntity;
|
||||
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalException;
|
||||
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalHelper;
|
||||
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalLog;
|
||||
use Combodo\iTop\DataFeatureRemoval\Service\DataCleanupService;
|
||||
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 RunTimeEnvironment;
|
||||
use SetupUtils;
|
||||
use utils;
|
||||
|
||||
class DataFeatureRemovalController extends Controller
|
||||
{
|
||||
private ?array $aExtensionsToCheck = null;
|
||||
private bool $bForcedUninstallation = false;
|
||||
private array $aSelectedExtensionsForCheck = [];
|
||||
private array $aCountClassesToCleanup = [];
|
||||
private array $aAnalysisDataTable = [];
|
||||
private array $aDeletionExecutionSummary = [];
|
||||
private ?RuntimeEnvironment $oRuntimeEnvironment = null;
|
||||
|
||||
private int $iCount = 0;
|
||||
private int $iColumnCount = 2;
|
||||
|
||||
public function OperationMain($sErrorMessage = null): void
|
||||
{
|
||||
$aParams = [];
|
||||
|
||||
$this->ReadRemovedExtensions();
|
||||
$this->AddAnalyzeParams();
|
||||
$aParams['sTransactionId'] = utils::GetNewTransactionId();
|
||||
$aParams['iColumnCount'] = $this->iColumnCount;
|
||||
$aParams['aAvailableExtensions'] = $this->SplitArrayIntoColumns($this->GetAvailableExtensions(), $this->iColumnCount);
|
||||
$aParams['aExtensions'] = $this->GetExtensionsTableToSelect();
|
||||
$aParams['aAnalysisDataTable'] = $this->aAnalysisDataTable;
|
||||
$aParams['aClasses'] = array_keys($this->aCountClassesToCleanup);
|
||||
$aParams['DataFeatureRemovalErrorMessage'] = $sErrorMessage;
|
||||
@@ -56,7 +46,6 @@ 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);
|
||||
@@ -79,6 +68,35 @@ class DataFeatureRemovalController extends Controller
|
||||
$this->aAnalysisDataTable = $this->GetTableData('Analysis', $aColumns, $aData);
|
||||
}
|
||||
|
||||
public function OperationAnalyze(): void
|
||||
{
|
||||
$this->ReadRemovedExtensions();
|
||||
|
||||
$this->m_sOperation = 'Main';
|
||||
|
||||
try {
|
||||
if (count($this->aSelectedExtensionsForCheck) > 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
|
||||
{
|
||||
$sSourceEnv = MetaModel::GetEnvironment();
|
||||
$oDryRemovalRuntimeEnvironment = new DryRemovalRuntimeEnvironment($sSourceEnv, $this->aSelectedExtensionsForCheck);
|
||||
$oDryRemovalRuntimeEnvironment->CompileFrom($sSourceEnv);
|
||||
|
||||
$oSetupAudit = new SetupAudit($sSourceEnv);
|
||||
$aGetRemovedClasses = $oSetupAudit->RunDataAudit();
|
||||
IssueLog::Debug(__METHOD__, null, ['aGetRemovedClasses' => $aGetRemovedClasses]);
|
||||
$this->aCountClassesToCleanup = $aGetRemovedClasses;
|
||||
}
|
||||
|
||||
public function OperationAnalysisResult(): void
|
||||
{
|
||||
$aParams = [];
|
||||
@@ -92,176 +110,19 @@ class DataFeatureRemovalController extends Controller
|
||||
}
|
||||
|
||||
// Display changed extensions
|
||||
$aHiddenInputNames = [
|
||||
'selected_extensions' => '[]',
|
||||
'selected_modules' => '[]',
|
||||
'display_choices' => '[]',
|
||||
'added_extensions' => '[]',
|
||||
'removed_extensions' => '[]',
|
||||
'extensions_not_uninstallable' => '[]',
|
||||
'copy_setup_files' => 1,
|
||||
];
|
||||
$aAddedExtensions = utils::ReadPostedParam('aAddedExtensions', []);
|
||||
$aRemovedExtensions = utils::ReadPostedParam('aRemovedExtensions', []);
|
||||
|
||||
$aHiddenInputs = [];
|
||||
foreach ($aHiddenInputNames as $sInputName => $defaultValue) {
|
||||
$aHiddenInputs[$sInputName] = utils::ReadPostedParam($sInputName, $defaultValue, utils::ENUM_SANITIZATION_FILTER_RAW_DATA);
|
||||
}
|
||||
$aParams['aHiddenInputs'] = $aHiddenInputs;
|
||||
|
||||
$aAddedExtensions = json_decode($aHiddenInputs['added_extensions'], true);
|
||||
|
||||
$aRemovedExtensions = json_decode($aHiddenInputs['removed_extensions'], true);
|
||||
if ("[]" === $aHiddenInputs['selected_modules']) {
|
||||
//it does not come from setup
|
||||
// we get extensions from 1st screen uiblocks
|
||||
$this->ReadExtensionsDiff();
|
||||
$aAddedExtensions = $this->aExtensionsToCheck['to_be_installed'];
|
||||
$aHiddenInputs['added_extensions'] = $this->ConvertIntoSetupFormat($aAddedExtensions);
|
||||
|
||||
$aRemovedExtensions = $this->aExtensionsToCheck['to_be_removed'];
|
||||
$aHiddenInputs['removed_extensions'] = $this->ConvertIntoSetupFormat($aRemovedExtensions);
|
||||
}
|
||||
|
||||
$aRemoveExtensionCodes = array_keys($aRemovedExtensions);
|
||||
|
||||
$aParams['aAddedExtensions'] = $aAddedExtensions;
|
||||
$aParams['aRemovedExtensions'] = $aRemovedExtensions;
|
||||
|
||||
DataFeatureRemovalLog::Debug(__METHOD__.' Extensions given in parameter', null, [
|
||||
'added_extensions' => $aAddedExtensions,
|
||||
'removed_extensions' => $aRemovedExtensions]);
|
||||
|
||||
$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;
|
||||
}
|
||||
|
||||
if ("[]" === $aHiddenInputs['selected_modules']) {
|
||||
//to make setup redirection work, we need to pass complex data structures to setup wizards (ie extension/module lists)
|
||||
$oConfig = MetaModel::GetConfig();
|
||||
$aSelectedExtensions = DataFeatureRemoverExtensionService::GetInstance()->GetExtensionMap()->GetSelectedExtensions($oConfig, $aAddedExtensions, $aRemovedExtensions);
|
||||
$aHiddenInputs['selected_extensions'] = $this->ConvertIntoSetupFormat($aSelectedExtensions);
|
||||
|
||||
$oRunTimeEnvironment = $this->GetRuntimeEnvironment($aRemovedExtensions);
|
||||
$aSearchDirs = [$oRunTimeEnvironment->GetBuildDir()];
|
||||
$aSelectedModules = $oRunTimeEnvironment->GetModulesToLoadFromChoices($oConfig, $aSelectedExtensions, $aSearchDirs);
|
||||
$aHiddenInputs['selected_modules'] = $this->ConvertIntoSetupFormat($aSelectedModules);
|
||||
}
|
||||
IssueLog::Info(__METHOD__.' Extensions given in parameter', null, ['aAddedExtensions' => $aAddedExtensions, 'aRemovedExtensions' => $aRemovedExtensions]);
|
||||
|
||||
$sSourceEnv = MetaModel::GetEnvironment();
|
||||
$oSetupAudit = new SetupAudit($sSourceEnv);
|
||||
$aGetRemovedClasses = array_keys($oSetupAudit->RunDataAudit());
|
||||
DataFeatureRemovalLog::Debug(__METHOD__, null, ['aGetRemovedClasses' => $aGetRemovedClasses]);
|
||||
IssueLog::Debug(__METHOD__, null, ['aGetRemovedClasses' => $aGetRemovedClasses]);
|
||||
|
||||
$aParams['aClasses'] = $aGetRemovedClasses;
|
||||
|
||||
new ContextTag(ContextTag::TAG_SETUP);
|
||||
$aParams['sLaunchSetupUrl'] = utils::GetAbsoluteUrlAppRoot().'setup/wizard.php';
|
||||
$aParams['aSetupParams'] = [
|
||||
"_class" => "WizStepLandingBeforeAudit",
|
||||
"operation" => "next",
|
||||
"_params[authent]" => SetupUtils::CreateSetupToken(),
|
||||
];
|
||||
|
||||
foreach ($aHiddenInputs as $sInputName => $sInputValue) {
|
||||
$aParams['aSetupParams']["_params[$sInputName]"] = $sInputValue;
|
||||
}
|
||||
|
||||
[$aParams['aDeletionPlanSummary'], $aParams['iQueryCount'], $aParams['bDeletionPossible']] = $this->GetDeletionPlanSummaryTable($aGetRemovedClasses);
|
||||
[$aParams['aDeletionExecutionSummary'], $aParams['bHasDeletionExecution']] = $this->GetExecutionSummaryTable();
|
||||
$aParams['bDeletionNeeded'] = ($aParams['iQueryCount'] > 0);
|
||||
Session::Set('aDeletionExecutionSummary', serialize($this->aDeletionExecutionSummary));
|
||||
|
||||
$this->DisplayPage($aParams, 'AnalysisResult');
|
||||
}
|
||||
|
||||
private function ConvertIntoSetupFormat(array $aData): string
|
||||
{
|
||||
return json_encode($aData);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aRemovedExtensions
|
||||
* @param bool $bForceCompilation
|
||||
* @return void
|
||||
* @throws \ConfigException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
private function Compile(array $aRemovedExtensions, bool $bForceCompilation = true): void
|
||||
{
|
||||
$sSourceEnv = MetaModel::GetEnvironment();
|
||||
$sBuildDir = APPROOT."/env-$sSourceEnv-build";
|
||||
if (! is_dir($sBuildDir)) {
|
||||
SetupUtils::builddir($sBuildDir);
|
||||
}
|
||||
$bIsDirEmpty = count(scandir($sBuildDir)) === 2;
|
||||
|
||||
if ($bIsDirEmpty || $bForceCompilation) {
|
||||
DataFeatureRemovalLog::Debug(
|
||||
__METHOD__,
|
||||
null,
|
||||
['sSourceEnv' => $sSourceEnv, 'sBuildDir' => $sBuildDir, 'bIsDirEmpty' => $bIsDirEmpty, glob("$sBuildDir/*")]
|
||||
);
|
||||
$this->GetRuntimeEnvironment($aRemovedExtensions)->CompileFrom($sSourceEnv);
|
||||
}
|
||||
}
|
||||
|
||||
private function GetRuntimeEnvironment(array $aRemovedExtensions): RunTimeEnvironment
|
||||
{
|
||||
if (is_null($this->oRuntimeEnvironment)) {
|
||||
$sSourceEnv = MetaModel::GetEnvironment();
|
||||
$this->oRuntimeEnvironment = new DryRemovalRuntimeEnvironment($sSourceEnv, $aRemovedExtensions);
|
||||
}
|
||||
|
||||
return $this->oRuntimeEnvironment;
|
||||
}
|
||||
|
||||
private function GetExecutionSummaryTable(): array
|
||||
{
|
||||
$sName = 'ExcutionSummary';
|
||||
|
||||
$aTableData = [];
|
||||
if (count($this->aDeletionExecutionSummary) === 0) {
|
||||
return [$aTableData, false];
|
||||
}
|
||||
|
||||
$aColumns = ['Class', 'Total Deleted Count' , 'Total Updated Count', 'Deleted Count' , 'Updated Count'];
|
||||
$aRows = [];
|
||||
/** @var DataCleanupSummaryEntity $oSummary */
|
||||
foreach ($this->aDeletionExecutionSummary as $sClass => $oSummary) {
|
||||
$aRows[] = [
|
||||
$sClass,
|
||||
$oSummary->iTotalDeleteCount,
|
||||
$oSummary->iTotalUpdateCount,
|
||||
$oSummary->iDeleteCount,
|
||||
$oSummary->iUpdateCount,
|
||||
];
|
||||
}
|
||||
|
||||
$aTableData = $this->GetTableData($sName, $aColumns, $aRows);
|
||||
|
||||
return [$aTableData, true];
|
||||
|
||||
}
|
||||
|
||||
private function GetDeletionPlanSummaryTable(array $aRemovedClasses): array
|
||||
{
|
||||
$sName = 'DeletionPlanSummary';
|
||||
$oDataCleanupService = new DataCleanupService();
|
||||
$aDeletionPlanSummaryEntities = $oDataCleanupService->GetCleanupSummary($aRemovedClasses);
|
||||
$aColumns = ['Class', 'Delete Count' , 'Update Count', 'Issue Count'];
|
||||
$aDeletionPlanSummaryEntities = $oDataCleanupService->GetCleanupSummary($aGetRemovedClasses);
|
||||
$aColumns = ['Class', 'DeleteCount' , 'UpdateCount', 'IssueCount'];
|
||||
$aRows = [];
|
||||
$iQueryCount = 0;
|
||||
$bHasIssues = false;
|
||||
@@ -276,78 +137,144 @@ class DataFeatureRemovalController extends Controller
|
||||
$iQueryCount += $oDeletionPlanSummaryEntity->iDeleteCount;
|
||||
$iQueryCount += $oDeletionPlanSummaryEntity->iUpdateCount;
|
||||
}
|
||||
return [$this->GetTableData($sName, $aColumns, $aRows), $iQueryCount, !$bHasIssues];
|
||||
|
||||
$aParams['sTransactionId'] = utils::GetNewTransactionId();
|
||||
$aParams['aDeletionPlanSummary'] = $this->GetTableData('Extensions', $aColumns, $aRows);
|
||||
$aParams['aClasses'] = $aGetRemovedClasses;
|
||||
$aParams['iQueryCount'] = $iQueryCount;
|
||||
$aParams['bDeletionPossible'] = !$bHasIssues;
|
||||
$aParams['aAddedExtensions'] = $aAddedExtensions;
|
||||
$aParams['aRemovedExtensions'] = $aRemovedExtensions;
|
||||
$aParams['aExtensions'] = $this->GetExtensionsTableDiff($aAddedExtensions, $aRemovedExtensions);
|
||||
|
||||
$this->DisplayPage($aParams);
|
||||
}
|
||||
|
||||
public function OperationDeletionPlan(): void
|
||||
{
|
||||
$aParams = [];
|
||||
$this->ValidateTransactionId();
|
||||
|
||||
$aClasses = utils::ReadPostedParam('classes', null, utils::ENUM_SANITIZATION_FILTER_CLASS);
|
||||
|
||||
$oDataCleanupService = new DataCleanupService();
|
||||
$aDeletionPlanSummaryEntities = $oDataCleanupService->GetCleanupSummary($aClasses);
|
||||
$aColumns = ['Class', 'DeleteCount' , 'UpdateCount', 'IssueCount'];
|
||||
$aRows = [];
|
||||
$iQueryCount = 0;
|
||||
$bHasIssues = false;
|
||||
foreach ($aDeletionPlanSummaryEntities as $oDeletionPlanSummaryEntity) {
|
||||
$aRows[] = [
|
||||
$oDeletionPlanSummaryEntity->sClass,
|
||||
$oDeletionPlanSummaryEntity->iDeleteCount,
|
||||
$oDeletionPlanSummaryEntity->iUpdateCount,
|
||||
$oDeletionPlanSummaryEntity->iIssueCount,
|
||||
];
|
||||
$bHasIssues |= ($oDeletionPlanSummaryEntity->iIssueCount !== 0);
|
||||
$iQueryCount += $oDeletionPlanSummaryEntity->iDeleteCount;
|
||||
$iQueryCount += $oDeletionPlanSummaryEntity->iUpdateCount;
|
||||
}
|
||||
|
||||
$aParams['sTransactionId'] = utils::GetNewTransactionId();
|
||||
$aParams['aDeletionPlanSummary'] = $this->GetTableData('Extensions', $aColumns, $aRows);
|
||||
$aParams['aClasses'] = $aClasses;
|
||||
$aParams['iQueryCount'] = $iQueryCount;
|
||||
$aParams['bDeletionPossible'] = !$bHasIssues;
|
||||
|
||||
$this->DisplayPage($aParams);
|
||||
}
|
||||
|
||||
public function OperationDoDeletion(): void
|
||||
{
|
||||
$aParams = [];
|
||||
$this->ValidateTransactionId();
|
||||
|
||||
$this->aDeletionExecutionSummary = unserialize(Session::Get('aDeletionExecutionSummary'));
|
||||
Session::Unset('aDeletionExecutionSummary');
|
||||
$aClasses = utils::ReadPostedParam('classes', null, utils::ENUM_SANITIZATION_FILTER_CLASS);
|
||||
|
||||
$oDataCleanupService = new DataCleanupService();
|
||||
$aDeletionExecutionSummary = $oDataCleanupService->ExecuteCleanup($aClasses);
|
||||
foreach ($aDeletionExecutionSummary as $sClass => $oExecutionSummary) {
|
||||
if (!array_key_exists($sClass, $this->aDeletionExecutionSummary)) {
|
||||
$this->aDeletionExecutionSummary[$sClass] = new DataCleanupSummaryEntity($sClass);
|
||||
}
|
||||
$oSummary = $this->aDeletionExecutionSummary[$sClass];
|
||||
$oSummary->iDeleteCount = $oExecutionSummary->iDeleteCount;
|
||||
$oSummary->iUpdateCount = $oExecutionSummary->iUpdateCount;
|
||||
$oSummary->iTotalDeleteCount += $oExecutionSummary->iDeleteCount;
|
||||
$oSummary->iTotalUpdateCount += $oExecutionSummary->iUpdateCount;
|
||||
}
|
||||
|
||||
$this->OperationAnalysisResult();
|
||||
}
|
||||
|
||||
private function GetAvailableExtensions(bool $bIncludePackageExtensions = false): array
|
||||
{
|
||||
$aExtensionsData = [];
|
||||
if ($bIncludePackageExtensions) {
|
||||
$aExtensionsRef = DataFeatureRemoverExtensionService::GetInstance()->GetExtensionMap()->GetAllExtensionsWithPreviouslyInstalled();
|
||||
} else {
|
||||
$aExtensionsRef = DataFeatureRemoverExtensionService::GetInstance()->ReadItopExtensions();
|
||||
}
|
||||
|
||||
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,
|
||||
],
|
||||
|
||||
$aColumns = ['Class', 'DeletedCount' , 'UpdatedCount'];
|
||||
$aRows = [];
|
||||
foreach ($aDeletionExecutionSummary as $oDeletionExecutionSummaryEntity) {
|
||||
$aRows[] = [
|
||||
$oDeletionExecutionSummaryEntity->sClass,
|
||||
$oDeletionExecutionSummaryEntity->iDeleteCount,
|
||||
$oDeletionExecutionSummaryEntity->iUpdateCount,
|
||||
];
|
||||
}
|
||||
|
||||
return $aExtensionsData;
|
||||
$aParams['sTransactionId'] = utils::GetNewTransactionId();
|
||||
$aParams['aDeletionExecutionSummary'] = $this->GetTableData('Extensions', $aColumns, $aRows);
|
||||
|
||||
$this->DisplayPage($aParams);
|
||||
}
|
||||
|
||||
private function GetExtensionsDiff(array $aAddedExtensions, array $aRemovedExtensions): array
|
||||
private function GetExtensionsTableDiff(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;
|
||||
}
|
||||
$aColumns = ['', 'Name', 'code', 'Badge' ];
|
||||
|
||||
foreach ($aAddedExtensions as $sAddedExtensionCode => $sAddedExtensionLabel) {
|
||||
$aExtensions[] = [
|
||||
<<<HTML
|
||||
<input type="checkbox" disabled class="extension_check" checked/>
|
||||
HTML,
|
||||
$sAddedExtensionLabel,
|
||||
$sAddedExtensionCode,
|
||||
Dict::S('UI:Layout:ExtensionsDetails:BadgeToBeInstalled'),
|
||||
];
|
||||
}
|
||||
foreach ($aRemovedExtensions as $sAddedExtensionCode => $sAddedExtensionLabel) {
|
||||
$aExtensions[] = [
|
||||
<<<HTML
|
||||
<input type="checkbox" disabled class="extension_check"/>
|
||||
HTML,
|
||||
$sAddedExtensionLabel,
|
||||
$sAddedExtensionCode,
|
||||
Dict::S('UI:Layout:ExtensionsDetails:BadgeToBeUninstalled'),
|
||||
];
|
||||
}
|
||||
|
||||
return $aExtensions;
|
||||
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) {
|
||||
/** @var \iTopExtension $oExtension */
|
||||
|
||||
$sChecked = '';
|
||||
$sDisabledHtml = '';
|
||||
if ($oExtension->bRemovedFromDisk) {
|
||||
$sDisabledHtml = 'disabled=""';
|
||||
$sChecked = 'checked';
|
||||
} elseif (in_array($sCode, $this->aSelectedExtensionsForCheck)) {
|
||||
$sChecked = 'checked';
|
||||
}
|
||||
|
||||
$sLabel = $oExtension->sLabel;
|
||||
$sVersion = $oExtension->sVersion;
|
||||
$sIdEnable = "aExtensions[$sCode][enable]";
|
||||
|
||||
$aExtensions[] = [
|
||||
<<<HTML
|
||||
<input type="checkbox" $sDisabledHtml class="extension_check" $sChecked id="$sIdEnable" name="$sIdEnable"/>
|
||||
HTML,
|
||||
$sVersion,
|
||||
$sLabel,
|
||||
$sCode,
|
||||
];
|
||||
}
|
||||
|
||||
return $this->GetTableData('Extensions', $aColumns, $aExtensions);
|
||||
}
|
||||
|
||||
private function GetTableData(string $sTableName, array $aColumns, array $aData): array
|
||||
@@ -384,65 +311,34 @@ class DataFeatureRemovalController extends Controller
|
||||
}
|
||||
|
||||
$sTransactionId = utils::ReadPostedParam('transaction_id', null, utils::ENUM_SANITIZATION_FILTER_TRANSACTION_ID);
|
||||
DataFeatureRemovalLog::Debug(__FUNCTION__.": Transaction [$sTransactionId]");
|
||||
IssueLog::Debug(__FUNCTION__.": Transaction [$sTransactionId]");
|
||||
if (empty($sTransactionId) || !utils::IsTransactionValid($sTransactionId, false)) {
|
||||
throw new DataFeatureRemovalException(Dict::S("iTopUpdate:Error:InvalidToken"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read extensions selected from posted parameters
|
||||
* @return int Number of extensions to be added or removed
|
||||
* @return void
|
||||
*/
|
||||
public function ReadExtensionsDiff(): int
|
||||
public function ReadRemovedExtensions(): void
|
||||
{
|
||||
if (!is_null($this->aExtensionsToCheck)) {
|
||||
return count($this->aExtensionsToCheck['to_be_installed']) + count($this->aExtensionsToCheck['to_be_removed']);
|
||||
if (count($this->aSelectedExtensionsForCheck) > 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
$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;
|
||||
}
|
||||
|
||||
if ($aExtensionData['installed'] && $aSelectedExtensionsFromUI[$sCode] !== 'on') {
|
||||
$aExtensionData['extra_flags']['selected'] = false;
|
||||
$sLabel = $aAvailableExtensions[$sCode]['label'];
|
||||
$this->aExtensionsToCheck['to_be_removed'][$sCode] = $sLabel;
|
||||
if (!$aExtensionData['extra_flags']['uninstallable'] || $aExtensionData['extra_flags']['remote']) {
|
||||
$this->bForcedUninstallation = true;
|
||||
}
|
||||
} elseif (!$aExtensionData['installed'] && $aSelectedExtensionsFromUI[$sCode] === 'on') {
|
||||
$aExtensionData['extra_flags']['selected'] = true;
|
||||
$sLabel = $aAvailableExtensions[$sCode]['label'];
|
||||
$this->aExtensionsToCheck['to_be_installed'][$sCode] = $sLabel;
|
||||
$aSelectedExtensionsFromUI = utils::ReadPostedParam('aExtensions', []);
|
||||
foreach ($aSelectedExtensionsFromUI as $sCode => $aData) {
|
||||
$sValue = $aData['enable'] ?? 'off';
|
||||
if (($sValue) === 'on') {
|
||||
$this->aSelectedExtensionsForCheck[] = $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++;
|
||||
// Add source removed to check
|
||||
foreach (DataFeatureRemoverExtensionService::GetInstance()->ReadItopExtensions() as $sCode => $oExtension) {
|
||||
if ($oExtension->bRemovedFromDisk) {
|
||||
$this->aSelectedExtensionsForCheck[] = $sCode;
|
||||
}
|
||||
}
|
||||
return $aOutput;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,6 @@ class DataCleanupSummaryEntity
|
||||
public int $iIssueCount = 0;
|
||||
public int $iUpdateCount = 0;
|
||||
public int $iDeleteCount = 0;
|
||||
public int $iTotalUpdateCount = 0;
|
||||
public int $iTotalDeleteCount = 0;
|
||||
|
||||
/**
|
||||
* @param string $sClass
|
||||
|
||||
@@ -14,7 +14,7 @@ use MetaModel;
|
||||
class DataFeatureRemoverExtensionService
|
||||
{
|
||||
private static DataFeatureRemoverExtensionService $oInstance;
|
||||
private ?iTopExtensionsMap $oMap = null;
|
||||
|
||||
private array $aItopExtensions = [];
|
||||
private array $aIncludingExtensionsByModuleName = [];
|
||||
|
||||
@@ -60,25 +60,15 @@ 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) {
|
||||
$this->aItopExtensions = $this->GetExtensionMap()->GetAllExtensionsToDisplayInSetup(true);
|
||||
$oExtensionsMap = new iTopExtensionsMap();
|
||||
$oExtensionsMap->LoadInstalledExtensionsFromDatabase(MetaModel::GetConfig());
|
||||
$this->aItopExtensions = $oExtensionsMap->GetAllExtensionsToDisplayInSetup(true);
|
||||
|
||||
uasort($this->aItopExtensions, function (iTopExtension $oiTopExtension1, iTopExtension $oiTopExtension2) {
|
||||
return strcmp($oiTopExtension1->sLabel, $oiTopExtension2->sLabel);
|
||||
|
||||
@@ -23,29 +23,27 @@ class ObjectServiceSummary implements iObjectService
|
||||
public function Update(DBObject $oToUpdate, string $sAttCode, $value): void
|
||||
{
|
||||
$sClass = get_class($oToUpdate);
|
||||
DataFeatureRemovalLog::Debug('Object to update', null, ['class' => $sClass, 'id' => $oToUpdate->GetKey(), 'code' => $sAttCode, 'value' => "$value"]);
|
||||
DataFeatureRemovalLog::Info('Object to update', null, ['class' => $sClass, 'id' => $oToUpdate->GetKey(), 'code' => $sAttCode, 'value' => "$value"]);
|
||||
if (! array_key_exists($sClass, $this->aSummary)) {
|
||||
$this->aSummary[$sClass] = new DataCleanupSummaryEntity($sClass);
|
||||
}
|
||||
$oDeletionPlanSummaryEntity = $this->aSummary[$sClass];
|
||||
$oDeletionPlanSummaryEntity->iUpdateCount++;
|
||||
$oDeletionPlanSummaryEntity->iTotalUpdateCount++;
|
||||
}
|
||||
|
||||
public function Delete(string $sClass, string $sId): void
|
||||
{
|
||||
DataFeatureRemovalLog::Debug('Object to delete', null, ['class' => $sClass, 'id' => $sId]);
|
||||
DataFeatureRemovalLog::Info('Object to delete', null, ['class' => $sClass, 'id' => $sId]);
|
||||
if (!array_key_exists($sClass, $this->aSummary)) {
|
||||
$this->aSummary[$sClass] = new DataCleanupSummaryEntity($sClass);
|
||||
}
|
||||
$oDeletionPlanSummaryEntity = $this->aSummary[$sClass];
|
||||
$oDeletionPlanSummaryEntity->iDeleteCount++;
|
||||
$oDeletionPlanSummaryEntity->iTotalDeleteCount++;
|
||||
}
|
||||
|
||||
public function SetIssue(string $sClass): void
|
||||
{
|
||||
DataFeatureRemovalLog::Debug('Issue on object', null, ['class' => $sClass]);
|
||||
DataFeatureRemovalLog::Info('Issue on object', null, ['class' => $sClass]);
|
||||
if (!array_key_exists($sClass, $this->aSummary)) {
|
||||
$this->aSummary[$sClass] = new DataCleanupSummaryEntity($sClass);
|
||||
}
|
||||
@@ -57,15 +55,4 @@ class ObjectServiceSummary implements iObjectService
|
||||
{
|
||||
return $this->aSummary;
|
||||
}
|
||||
|
||||
public function SetSummary(array $aSummary): void
|
||||
{
|
||||
foreach ($aSummary as $sClass => $oPreviousSummaryEntity) {
|
||||
$oSummaryEntity = new DataCleanupSummaryEntity($sClass);
|
||||
$oSummaryEntity->iTotalUpdateCount = $oPreviousSummaryEntity->iTotalUpdateCount;
|
||||
$oSummaryEntity->iTotalDeleteCount = $oPreviousSummaryEntity->iTotalDeleteCount;
|
||||
|
||||
$this->aSummary[$sClass] = $oSummaryEntity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,88 +3,29 @@
|
||||
|
||||
|
||||
|
||||
{% UIPanel ForInformation { sTitle:'DataFeatureRemoval:Analysis:Title'|dict_s, sSubTitle: 'DataFeatureRemoval:Analysis:Subtitle'|dict_s} %}
|
||||
{% if null != DataFeatureRemovalErrorMessage %}
|
||||
<div id="feature_removal_error_msg_div" style="display:block">
|
||||
{% UIAlert ForFailure { sTitle:'DataFeatureRemoval:Failure:Title'|dict_s, sId: 'feature_removal_error_msg', sContent:DataFeatureRemovalErrorMessage } %}
|
||||
{% EndUIAlert %}
|
||||
</div>
|
||||
{% UIPanel ForInformation { sTitle:'DataFeatureRemoval:Analysis:Title'|dict_s} %}
|
||||
|
||||
{% UIPanel Neutral { sTitle:'DataFeatureRemoval:Result: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 %}
|
||||
{% UIFieldSet Standard {sLegend:'DataFeatureRemoval:Features:Title'|dict_s} %}
|
||||
{% UIDataTable ForForm { sRef:'aExtensions', aColumns:aExtensions.Columns, aData:aExtensions.Data} %}{% EndUIDataTable %}
|
||||
{% EndUIFieldSet %}
|
||||
|
||||
{% 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 %}
|
||||
{% UIToolbar ForButton {} %}
|
||||
{% UIButton ForPrimaryAction {sLabel:'UI:Button:DoDeletion'|dict_s, sName:'btn_deletion', sId:'btn_deletion', bIsSubmit:true} %}
|
||||
{% EndUIToolbar %}
|
||||
{% EndUIForm %}
|
||||
{% else %}
|
||||
{% UIPanel Neutral { sTitle:'DataFeatureRemoval:Result: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} %}
|
||||
{% 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 %}
|
||||
|
||||
{% 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 %}
|
||||
{{ 'DataFeatureRemoval:DeletionPlan:Error:Issues'|dict_s }}
|
||||
{% endif %}
|
||||
|
||||
{% UIForm Standard {} %}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
{# @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 %}
|
||||
@@ -0,0 +1,19 @@
|
||||
{# @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 %}
|
||||
@@ -3,24 +3,12 @@
|
||||
|
||||
|
||||
{% UIForm Standard {} %}
|
||||
{% UIInput ForHidden {sName:'operation', sValue:'AnalysisResult'} %}
|
||||
{% UIInput ForHidden {sName:'operation', sValue:'Analyze'} %}
|
||||
{% UIInput ForHidden {sName:'transaction_id', sValue:sTransactionId} %}
|
||||
|
||||
{% 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 %}
|
||||
{% UIFieldSet Standard {sLegend:'DataFeatureRemoval:Features:Title'|dict_s} %}
|
||||
{% UIDataTable ForForm { sRef:'aExtensions', aColumns:aExtensions.Columns, aData:aExtensions.Data} %}{% EndUIDataTable %}
|
||||
{% EndUIFieldSet %}
|
||||
|
||||
{% UIToolbar ForButton {} %}
|
||||
{% UIButton ForPrimaryAction {sLabel:'UI:Button:Analyze'|dict_s, sName:'btn_apply', sId:'btn_apply', bIsSubmit:true} %}
|
||||
|
||||
@@ -11,7 +11,25 @@
|
||||
{% UIPanel ForInformation { sTitle:'DataFeatureRemoval:Main:Title'|dict_s, sSubTitle: 'DataFeatureRemoval:Main:SubTitle'|dict_s } %}
|
||||
|
||||
{% UIAlert ForInformation { sTitle:'DataFeatureRemoval:Helper:Title'|dict_s } %}
|
||||
{{ 'DataFeatureRemoval:Helper:Desc1'|dict_s }}<BR>
|
||||
{{ 'DataFeatureRemoval:Helper:Desc2'|dict_s }}
|
||||
{% EndUIAlert %}
|
||||
|
||||
{% if null != DataFeatureRemovalErrorMessage %}
|
||||
<div id="feature_removal_error_msg_div" style="display:block">
|
||||
{% UIAlert ForFailure { sTitle:'DataFeatureRemoval:Failure:Title'|dict_s, sId: 'feature_removal_error_msg', sContent:DataFeatureRemovalErrorMessage } %}
|
||||
{% EndUIAlert %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% include 'Features.html.twig' %}
|
||||
{% include 'ExtensionRemovalData.html.twig' %}
|
||||
|
||||
{% if not bHasData %}
|
||||
{% UIToolbar ForButton {} %}
|
||||
<a href="{{ sSetupUrl }}">
|
||||
{% UIButton ForPrimaryAction {sLabel:'UI:Button:Setup'|dict_s, sName:'btn_setup', sId:'btn_setup', bIsSubmit:false} %}
|
||||
</a>
|
||||
{% EndUIToolbar %}
|
||||
{% endif %}
|
||||
{% EndUIPanel %}
|
||||
|
||||
@@ -27,6 +27,12 @@
|
||||
<module>combodo-backoffice-fullmoon-protanopia-deuteranopia-theme</module>
|
||||
<module>combodo-backoffice-fullmoon-tritanopia-theme</module>
|
||||
<module>itop-themes-compat</module>
|
||||
<module>combodo-my-account</module>
|
||||
<module>combodo-my-account-user-info</module>
|
||||
<module>combodo-oauth2-client</module>
|
||||
<module>itop-attribute-class-set</module>
|
||||
<module>itop-attribute-encrypted-password</module>
|
||||
<module>itop-ui-copypaste</module>
|
||||
</modules>
|
||||
<mandatory>true</mandatory>
|
||||
</choice>
|
||||
@@ -88,6 +94,15 @@
|
||||
</options>
|
||||
</sub_options>
|
||||
</choice>
|
||||
<choice>
|
||||
<extension_code>itop-flow-map</extension_code>
|
||||
<title>Data flow</title>
|
||||
<description>Map data flows between applications</description>
|
||||
<modules type="array">
|
||||
<module>itop-flow-map</module>
|
||||
</modules>
|
||||
<default>false</default>
|
||||
</choice>
|
||||
</options>
|
||||
</step>
|
||||
<step>
|
||||
|
||||
@@ -85,13 +85,11 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', [
|
||||
Dict::Add('CS CZ', 'Czech', 'Čeština', [
|
||||
'Class:TriggerOnAttachmentDownload' => 'Trigger (on object\'s attachment download)~~',
|
||||
'Class:TriggerOnAttachmentDownload+' => 'Trigger on object\'s attachment download of [a child class of] the given class~~',
|
||||
'Class:TriggerOnAttachmentCreate' => 'Trigger (on object\'s attachment creation)~~',
|
||||
'Class:TriggerOnAttachmentCreate+' => 'Trigger on object\'s attachment creation~~',
|
||||
'Class:TriggerOnAttachmentCreate' => 'Trigger (on object\'s attachment create)~~',
|
||||
'Class:TriggerOnAttachmentCreate+' => 'Trigger on object\'s attachment create~~',
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email' => 'Add file in email~~',
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email+' => 'If checked, the file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (on object\'s attachment deletion)~~',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger on object\'s attachment deletion~~',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email' => 'Add deleted file in email~~',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email+' => 'If checked, the deleted file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (on object\'s attachment delete)~~',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger on object\'s attachment delete~~',
|
||||
'Class:TriggerOnObject:TriggerClassAttachment/ReadOnlyMessage' => 'Trigger on object is not allowed on class Attachment. Please use specific trigger~~',
|
||||
]);
|
||||
|
||||
@@ -84,13 +84,11 @@ Dict::Add('DA DA', 'Danish', 'Dansk', [
|
||||
Dict::Add('DA DA', 'Danish', 'Dansk', [
|
||||
'Class:TriggerOnAttachmentDownload' => 'Trigger (on object\'s attachment download)~~',
|
||||
'Class:TriggerOnAttachmentDownload+' => 'Trigger on object\'s attachment download of [a child class of] the given class~~',
|
||||
'Class:TriggerOnAttachmentCreate' => 'Trigger (on object\'s attachment creation)~~',
|
||||
'Class:TriggerOnAttachmentCreate+' => 'Trigger on object\'s attachment creation~~',
|
||||
'Class:TriggerOnAttachmentCreate' => 'Trigger (on object\'s attachment create)~~',
|
||||
'Class:TriggerOnAttachmentCreate+' => 'Trigger on object\'s attachment create~~',
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email' => 'Add file in email~~',
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email+' => 'If checked, the file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (on object\'s attachment deletion)~~',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger on object\'s attachment deletion~~',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email' => 'Add deleted file in email~~',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email+' => 'If checked, the deleted file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (on object\'s attachment delete)~~',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger on object\'s attachment delete~~',
|
||||
'Class:TriggerOnObject:TriggerClassAttachment/ReadOnlyMessage' => 'Trigger on object is not allowed on class Attachment. Please use specific trigger~~',
|
||||
]);
|
||||
|
||||
@@ -84,13 +84,11 @@ Dict::Add('DE DE', 'German', 'Deutsch', [
|
||||
Dict::Add('DE DE', 'German', 'Deutsch', [
|
||||
'Class:TriggerOnAttachmentDownload' => 'Trigger (beim Herunterladen eines Attachment eines Objekts)',
|
||||
'Class:TriggerOnAttachmentDownload+' => 'Trigger für das Herunterladen des Attachments der angegebenen Klasse oder einer Unterklasse',
|
||||
'Class:TriggerOnAttachmentCreate' => 'Trigger (on object\'s attachment creation)~~',
|
||||
'Class:TriggerOnAttachmentCreate+' => 'Trigger on object\'s attachment creation~~',
|
||||
'Class:TriggerOnAttachmentCreate' => 'Trigger (on object\'s attachment create)~~',
|
||||
'Class:TriggerOnAttachmentCreate+' => 'Trigger on object\'s attachment create~~',
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email' => 'Add file in email~~',
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email+' => 'If checked, the file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (on object\'s attachment deletion)~~',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger on object\'s attachment deletion~~',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email' => 'Add deleted file in email~~',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email+' => 'If checked, the deleted file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (on object\'s attachment delete)~~',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger on object\'s attachment delete~~',
|
||||
'Class:TriggerOnObject:TriggerClassAttachment/ReadOnlyMessage' => 'Trigger on object is not allowed on class Attachment. Please use specific trigger~~',
|
||||
]);
|
||||
|
||||
@@ -91,13 +91,11 @@ Dict::Add('EN US', 'English', 'English', [
|
||||
Dict::Add('EN US', 'English', 'English', [
|
||||
'Class:TriggerOnAttachmentDownload' => 'Trigger (on object\'s attachment download)',
|
||||
'Class:TriggerOnAttachmentDownload+' => 'Trigger on object\'s attachment download of [a child class of] the given class',
|
||||
'Class:TriggerOnAttachmentCreate' => 'Trigger (on object\'s attachment creation)',
|
||||
'Class:TriggerOnAttachmentCreate+' => 'Trigger on object\'s attachment creation',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (on object\'s attachment deletion)',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger on object\'s attachment deletion',
|
||||
'Class:TriggerOnAttachmentCreate' => 'Trigger (on object\'s attachment create)',
|
||||
'Class:TriggerOnAttachmentCreate+' => 'Trigger on object\'s attachment create',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (on object\'s attachment delete)',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger on object\'s attachment delete',
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email' => 'Add file in email',
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email+' => 'If checked, the file will be automatically attached to the email when an email action is triggered',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email' => 'Add deleted file in email',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email+' => 'If checked, the deleted file will be automatically attached to the email when an email action is triggered',
|
||||
'Class:TriggerOnObject:TriggerClassAttachment/ReadOnlyMessage' => 'Trigger on object is not allowed on class Attachment. Please use specific trigger',
|
||||
]);
|
||||
|
||||
@@ -81,13 +81,11 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', [
|
||||
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', [
|
||||
'Class:TriggerOnAttachmentDownload' => 'Disparador (al descargar el archivo adjunto del objeto)',
|
||||
'Class:TriggerOnAttachmentDownload+' => 'Disparador al descargar el archivo adjunto del objeto de [una clase secundaria de] la clase dada',
|
||||
'Class:TriggerOnAttachmentCreate' => 'Trigger (on object\'s attachment creation)~~',
|
||||
'Class:TriggerOnAttachmentCreate+' => 'Trigger on object\'s attachment creation~~',
|
||||
'Class:TriggerOnAttachmentCreate' => 'Trigger (on object\'s attachment create)~~',
|
||||
'Class:TriggerOnAttachmentCreate+' => 'Trigger on object\'s attachment create~~',
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email' => 'Add file in email~~',
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email+' => 'If checked, the file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (on object\'s attachment deletion)~~',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger on object\'s attachment deletion~~',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email' => 'Add deleted file in email~~',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email+' => 'If checked, the deleted file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (on object\'s attachment delete)~~',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger on object\'s attachment delete~~',
|
||||
'Class:TriggerOnObject:TriggerClassAttachment/ReadOnlyMessage' => 'Trigger on object is not allowed on class Attachment. Please use specific trigger~~',
|
||||
]);
|
||||
|
||||
@@ -89,7 +89,5 @@ Dict::Add('FR FR', 'French', 'Français', [
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email+' => 'Si coché, le fichier sera automatiquement attaché à l\'email quand l\'action email est lancée',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Déclencheur sur la suppression d\'une pièce jointe',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Déclencheur sur la suppression d\'une pièce jointe d\'un objet',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email' => 'Ajoute le fichier supprimé dans l\'email',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email+' => 'If checked, the deleted file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnObject:TriggerClassAttachment/ReadOnlyMessage' => 'Les Triggers sur les objets ne sont pas autorisés sur la classe Attachement. Veuillez utiliser les triggers spécifiques pour cette classe',
|
||||
]);
|
||||
|
||||
@@ -81,13 +81,11 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', [
|
||||
Dict::Add('HU HU', 'Hungarian', 'Magyar', [
|
||||
'Class:TriggerOnAttachmentDownload' => 'Trigger (on object\'s attachment download)~~',
|
||||
'Class:TriggerOnAttachmentDownload+' => 'Trigger on object\'s attachment download of [a child class of] the given class~~',
|
||||
'Class:TriggerOnAttachmentCreate' => 'Trigger (on object\'s attachment creation)~~',
|
||||
'Class:TriggerOnAttachmentCreate+' => 'Trigger on object\'s attachment creation~~',
|
||||
'Class:TriggerOnAttachmentCreate' => 'Trigger (on object\'s attachment create)~~',
|
||||
'Class:TriggerOnAttachmentCreate+' => 'Trigger on object\'s attachment create~~',
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email' => 'Add file in email~~',
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email+' => 'If checked, the file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (on object\'s attachment deletion)~~',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger on object\'s attachment deletion~~',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email' => 'Add deleted file in email~~',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email+' => 'If checked, the deleted file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (on object\'s attachment delete)~~',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger on object\'s attachment delete~~',
|
||||
'Class:TriggerOnObject:TriggerClassAttachment/ReadOnlyMessage' => 'Trigger on object is not allowed on class Attachment. Please use specific trigger~~',
|
||||
]);
|
||||
|
||||
@@ -83,13 +83,11 @@ Dict::Add('IT IT', 'Italian', 'Italiano', [
|
||||
Dict::Add('IT IT', 'Italian', 'Italiano', [
|
||||
'Class:TriggerOnAttachmentDownload' => 'Trigger (al download di un allegato dell\'oggetto)',
|
||||
'Class:TriggerOnAttachmentDownload+' => 'Trigger al download di un allegato di un oggetto di [una sottoclasse di] la classe data',
|
||||
'Class:TriggerOnAttachmentCreate' => 'Trigger (on object\'s attachment creation)~~',
|
||||
'Class:TriggerOnAttachmentCreate+' => 'Trigger on object\'s attachment creation~~',
|
||||
'Class:TriggerOnAttachmentCreate' => 'Trigger (on object\'s attachment create)~~',
|
||||
'Class:TriggerOnAttachmentCreate+' => 'Trigger on object\'s attachment create~~',
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email' => 'Add file in email~~',
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email+' => 'If checked, the file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (on object\'s attachment deletion)~~',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger on object\'s attachment deletion~~',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email' => 'Add deleted file in email~~',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email+' => 'If checked, the deleted file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (on object\'s attachment delete)~~',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger on object\'s attachment delete~~',
|
||||
'Class:TriggerOnObject:TriggerClassAttachment/ReadOnlyMessage' => 'Trigger on object is not allowed on class Attachment. Please use specific trigger~~',
|
||||
]);
|
||||
|
||||
@@ -83,13 +83,11 @@ Dict::Add('JA JP', 'Japanese', '日本語', [
|
||||
Dict::Add('JA JP', 'Japanese', '日本語', [
|
||||
'Class:TriggerOnAttachmentDownload' => 'Trigger (on object\'s attachment download)~~',
|
||||
'Class:TriggerOnAttachmentDownload+' => 'Trigger on object\'s attachment download of [a child class of] the given class~~',
|
||||
'Class:TriggerOnAttachmentCreate' => 'Trigger (on object\'s attachment creation)~~',
|
||||
'Class:TriggerOnAttachmentCreate+' => 'Trigger on object\'s attachment creation~~',
|
||||
'Class:TriggerOnAttachmentCreate' => 'Trigger (on object\'s attachment create)~~',
|
||||
'Class:TriggerOnAttachmentCreate+' => 'Trigger on object\'s attachment create~~',
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email' => 'Add file in email~~',
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email+' => 'If checked, the file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (on object\'s attachment deletion)~~',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger on object\'s attachment deletion~~',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email' => 'Add deleted file in email~~',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email+' => 'If checked, the deleted file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (on object\'s attachment delete)~~',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger on object\'s attachment delete~~',
|
||||
'Class:TriggerOnObject:TriggerClassAttachment/ReadOnlyMessage' => 'Trigger on object is not allowed on class Attachment. Please use specific trigger~~',
|
||||
]);
|
||||
|
||||
@@ -91,7 +91,5 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', [
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email+' => 'If checked, the file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (Bij het verwijderen van een bijlage)',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger bij het verwijderen van een bijlage van een object van de opgegeven klasse (of subklasse ervan)',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email' => 'Bestand toevoegen in e-mail',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email+' => 'If checked, the deleted file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnObject:TriggerClassAttachment/ReadOnlyMessage' => 'Trigger on object is not allowed on class Attachment. Please use specific trigger~~',
|
||||
]);
|
||||
|
||||
@@ -83,13 +83,11 @@ Dict::Add('PL PL', 'Polish', 'Polski', [
|
||||
Dict::Add('PL PL', 'Polish', 'Polski', [
|
||||
'Class:TriggerOnAttachmentDownload' => 'Wyzwalacz (po pobraniu załącznika obiektu)',
|
||||
'Class:TriggerOnAttachmentDownload+' => 'Wyzwalacz po pobraniu załącznika obiektu [klasy podrzędnej] danej klasy',
|
||||
'Class:TriggerOnAttachmentCreate' => 'Trigger (on object\'s attachment creation)~~',
|
||||
'Class:TriggerOnAttachmentCreate+' => 'Trigger on object\'s attachment creation~~',
|
||||
'Class:TriggerOnAttachmentCreate' => 'Trigger (on object\'s attachment create)~~',
|
||||
'Class:TriggerOnAttachmentCreate+' => 'Trigger on object\'s attachment create~~',
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email' => 'Add file in email~~',
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email+' => 'If checked, the file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (on object\'s attachment deletion)~~',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger on object\'s attachment deletion~~',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email' => 'Add deleted file in email~~',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email+' => 'If checked, the deleted file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (on object\'s attachment delete)~~',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger on object\'s attachment delete~~',
|
||||
'Class:TriggerOnObject:TriggerClassAttachment/ReadOnlyMessage' => 'Trigger on object is not allowed on class Attachment. Please use specific trigger~~',
|
||||
]);
|
||||
|
||||
@@ -83,13 +83,11 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', [
|
||||
Dict::Add('PT BR', 'Brazilian', 'Brazilian', [
|
||||
'Class:TriggerOnAttachmentDownload' => 'Trigger (on object\'s attachment download)~~',
|
||||
'Class:TriggerOnAttachmentDownload+' => 'Trigger on object\'s attachment download of [a child class of] the given class~~',
|
||||
'Class:TriggerOnAttachmentCreate' => 'Trigger (on object\'s attachment creation)~~',
|
||||
'Class:TriggerOnAttachmentCreate+' => 'Trigger on object\'s attachment creation~~',
|
||||
'Class:TriggerOnAttachmentCreate' => 'Trigger (on object\'s attachment create)~~',
|
||||
'Class:TriggerOnAttachmentCreate+' => 'Trigger on object\'s attachment create~~',
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email' => 'Add file in email~~',
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email+' => 'If checked, the file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (on object\'s attachment deletion)~~',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger on object\'s attachment deletion~~',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email' => 'Add deleted file in email~~',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email+' => 'If checked, the deleted file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (on object\'s attachment delete)~~',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger on object\'s attachment delete~~',
|
||||
'Class:TriggerOnObject:TriggerClassAttachment/ReadOnlyMessage' => 'Trigger on object is not allowed on class Attachment. Please use specific trigger~~',
|
||||
]);
|
||||
|
||||
@@ -84,13 +84,11 @@ Dict::Add('RU RU', 'Russian', 'Русский', [
|
||||
Dict::Add('RU RU', 'Russian', 'Русский', [
|
||||
'Class:TriggerOnAttachmentDownload' => 'Trigger (on object\'s attachment download)~~',
|
||||
'Class:TriggerOnAttachmentDownload+' => 'Trigger on object\'s attachment download of [a child class of] the given class~~',
|
||||
'Class:TriggerOnAttachmentCreate' => 'Trigger (on object\'s attachment creation)~~',
|
||||
'Class:TriggerOnAttachmentCreate+' => 'Trigger on object\'s attachment creation~~',
|
||||
'Class:TriggerOnAttachmentCreate' => 'Trigger (on object\'s attachment create)~~',
|
||||
'Class:TriggerOnAttachmentCreate+' => 'Trigger on object\'s attachment create~~',
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email' => 'Add file in email~~',
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email+' => 'If checked, the file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (on object\'s attachment deletion)~~',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger on object\'s attachment deletion~~',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email' => 'Add deleted file in email~~',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email+' => 'If checked, the deleted file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (on object\'s attachment delete)~~',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger on object\'s attachment delete~~',
|
||||
'Class:TriggerOnObject:TriggerClassAttachment/ReadOnlyMessage' => 'Trigger on object is not allowed on class Attachment. Please use specific trigger~~',
|
||||
]);
|
||||
|
||||
@@ -83,13 +83,11 @@ Dict::Add('SK SK', 'Slovak', 'Slovenčina', [
|
||||
Dict::Add('SK SK', 'Slovak', 'Slovenčina', [
|
||||
'Class:TriggerOnAttachmentDownload' => 'Trigger (on object\'s attachment download)~~',
|
||||
'Class:TriggerOnAttachmentDownload+' => 'Trigger on object\'s attachment download of [a child class of] the given class~~',
|
||||
'Class:TriggerOnAttachmentCreate' => 'Trigger (on object\'s attachment creation)~~',
|
||||
'Class:TriggerOnAttachmentCreate+' => 'Trigger on object\'s attachment creation~~',
|
||||
'Class:TriggerOnAttachmentCreate' => 'Trigger (on object\'s attachment create)~~',
|
||||
'Class:TriggerOnAttachmentCreate+' => 'Trigger on object\'s attachment create~~',
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email' => 'Add file in email~~',
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email+' => 'If checked, the file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (on object\'s attachment deletion)~~',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger on object\'s attachment deletion~~',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email' => 'Add deleted file in email~~',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email+' => 'If checked, the deleted file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (on object\'s attachment delete)~~',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger on object\'s attachment delete~~',
|
||||
'Class:TriggerOnObject:TriggerClassAttachment/ReadOnlyMessage' => 'Trigger on object is not allowed on class Attachment. Please use specific trigger~~',
|
||||
]);
|
||||
|
||||
@@ -83,13 +83,11 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', [
|
||||
Dict::Add('TR TR', 'Turkish', 'Türkçe', [
|
||||
'Class:TriggerOnAttachmentDownload' => 'Trigger (on object\'s attachment download)~~',
|
||||
'Class:TriggerOnAttachmentDownload+' => 'Trigger on object\'s attachment download of [a child class of] the given class~~',
|
||||
'Class:TriggerOnAttachmentCreate' => 'Trigger (on object\'s attachment creation)~~',
|
||||
'Class:TriggerOnAttachmentCreate+' => 'Trigger on object\'s attachment creation~~',
|
||||
'Class:TriggerOnAttachmentCreate' => 'Trigger (on object\'s attachment create)~~',
|
||||
'Class:TriggerOnAttachmentCreate+' => 'Trigger on object\'s attachment create~~',
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email' => 'Add file in email~~',
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email+' => 'If checked, the file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (on object\'s attachment deletion)~~',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger on object\'s attachment deletion~~',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email' => 'Add deleted file in email~~',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email+' => 'If checked, the deleted file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (on object\'s attachment delete)~~',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger on object\'s attachment delete~~',
|
||||
'Class:TriggerOnObject:TriggerClassAttachment/ReadOnlyMessage' => 'Trigger on object is not allowed on class Attachment. Please use specific trigger~~',
|
||||
]);
|
||||
|
||||
@@ -83,13 +83,11 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', [
|
||||
Dict::Add('ZH CN', 'Chinese', '简体中文', [
|
||||
'Class:TriggerOnAttachmentDownload' => '触发器 (于对象附件下载时)',
|
||||
'Class:TriggerOnAttachmentDownload+' => '触发器于指定类型 [子类型] 对象附件下载时',
|
||||
'Class:TriggerOnAttachmentCreate' => 'Trigger (on object\'s attachment creation)~~',
|
||||
'Class:TriggerOnAttachmentCreate+' => 'Trigger on object\'s attachment creation~~',
|
||||
'Class:TriggerOnAttachmentCreate' => 'Trigger (on object\'s attachment create)~~',
|
||||
'Class:TriggerOnAttachmentCreate+' => 'Trigger on object\'s attachment create~~',
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email' => 'Add file in email~~',
|
||||
'Class:TriggerOnAttachmentCreate/Attribute:file_in_email+' => 'If checked, the file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (on object\'s attachment deletion)~~',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger on object\'s attachment deletion~~',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email' => 'Add deleted file in email~~',
|
||||
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email+' => 'If checked, the deleted file will be automatically attached to the email when an email action is triggered~~',
|
||||
'Class:TriggerOnAttachmentDelete' => 'Trigger (on object\'s attachment delete)~~',
|
||||
'Class:TriggerOnAttachmentDelete+' => 'Trigger on object\'s attachment delete~~',
|
||||
'Class:TriggerOnObject:TriggerClassAttachment/ReadOnlyMessage' => 'Trigger on object is not allowed on class Attachment. Please use specific trigger~~',
|
||||
]);
|
||||
|
||||
@@ -34,10 +34,9 @@ class TriggerOnAttachmentDelete extends TriggerOnObject
|
||||
];
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
MetaModel::Init_AddAttribute(new AttributeBoolean("file_in_email", ["sql" => 'file_in_email', "is_null_allowed" => false, "default_value" => 'true', "allowed_values" => null, "depends_on" => [], "always_load_in_tables" => false]));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', ['description', 'context', 'filter', 'action_list', 'target_class','file_in_email']); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', ['description', 'context', 'filter', 'action_list', 'target_class']); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', ['finalclass', 'target_class']); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', ['description', 'target_class']); // Criteria of the std search form
|
||||
|
||||
@@ -14,12 +14,16 @@
|
||||
A2IDAuMDMsLTAuMDkgMC4wNSwtMC4xOSAwLjA2LC0wLjI4IGwgMC41OSwtMS45MSBjIDAuMSwtMC4zMyAtMC4wNSwtMC40OSAtMC40NSwtMC40OCBsIC0zLjEzLDAuMTUgYyAtMi4wOSwwLjEyIC0zLjcyLDAuMTggLTQuOSwwLjE3IC0xLjU0LDAuMDggLTMuMDgsLTAuMDcgLTQuNTgsLTAuNDYgLTEuMiwtMC40MSAtMS45NCwtMS42MSAtMS43NywtMi44NiBsIDkuOTEsLTEuMjcgYyA0LjQ0LC0wLjU3IDcuNDIsLTEuOTQgOC45MiwtNC4xMiBsIC0zLjM3LDExLjczIGMg
|
||||
LTAuMDcsMC4xOCAtMC4wNCwwLjM4IDAuMDcsMC41MyAwLjE4LDAuMTcgMC40MSwwLjI1IDAuNjUsMC4yMiBoIDQuMSBjIDAuNDcsMC4wNyAwLjkzLC0wLjIyIDEuMDYsLTAuNjggbCAzLjYyLC0xMi42NyBjIDAuNDgsLTEuNjcgMiwtMi40OCA0LjY3LC0yLjQ4IDIuNDEsMCA0LjIyLDAuMDIgNS4zOCwwLjA3IDAuMDMsMCAwLjA2LDAgMC4wOSwwIDAuMzksMCAwLjc0LC0wLjI2IDAuODQsLTAuNjMgbCAwLjYzLC0xLjc0IGMgMC4xNSwtMC4zIDAuMTIsLTAuNjMgLTAuMD
|
||||
UsLTAuODkgbSAtNjYuMTIsMTUuMjQgYyAtMS44MywwLjIzIC0zLjY4LDAuMzMgLTUuNTIsMC4zIC00LjE3LDAgLTUuOTksLTAuODQgLTUuNDYsLTIuNTMgMC4zOCwtMS4yMSAxLjQ3LC0xLjk0IDMuMjgsLTIuMTkgbCA5LjQ4LC0xLjI4IHogbSA0My44MywtMTAuMjcgYyAtMC40LDEuMyAtMi4yNSwyLjE5IC01LjU2LDIuNjcgbCAtNy45LDEuMTMgMC4yLC0wLjY1IGMgMC4zOSwtMS43NCAxLjM3LC0zLjI4IDIuNzksLTQuMzcgMS4yLC0wLjc3IDMuMTUsLTEuMTYgNS44NiwtMS4xNiAzLjU2LDAgNS4xLDAuOCA0LjYxLDIuMzgiLz4KPC9zdmc6c3ZnPgo=</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>Brand</finalclass>
|
||||
<friendlyname>Acer</friendlyname>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="2">
|
||||
<name>Apple</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>icons8-mac-os.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiMwODgzZDkiIGQ9Ik0zNi4yMzIsMjMuOTg1YzAtNS44NjUsNC43NjYtOC41MSw0Ljk2Ni04LjYzNmMtMi41OTYtMy45OTMtNi43OS00LjQ2Ny
|
||||
04LjM2Mi00LjQ2OCBjLTMuNjQzLDAtNi44NjMsMi4wMjItOC41ODUsMi4wMjJjLTEuNzk3LDAtNC40MTgtMi4xMjEtNy4zNjMtMi4wMjJjLTMuODQzLDAuMDc1LTcuMzYzLDIuMzQ2LTkuMzM0LDUuNjkxIGMtMS4zOTcsMi4zOTYtMS45NDcsNS4yMTctMS44OTYsOC4wODdjMC4wMDIsMC4xMTMsMC4wMTcsMC4yMjgsMC4wMiwwLjM0MUgzNi4zMkMzNi4yNzksMjQuNjcxLDM2LjI0MywyNC4zMzcsMzYuMjMyLDIzLjk4NXoiLz48cGF0aCBmaWxsPSIjMDg4M2Q5IiBkPSJN
|
||||
MzAuNTY1LDcuMDYzQzMyLjI2MSw1LjE5MSwzMy4yMSwyLjYyMSwzMy4wNiwwYy0yLjM0NiwwLTUuMDY2LDEuMzcyLTYuNzg4LDMuMzk0IGMtMS4zNDgsMS42NzItMi43OTUsNC4yOTMtMi4yNzEsNi45MTNDMjYuNDIyLDEwLjYwNywyOS4wNDMsOS4wODUsMzAuNTY1LDcuMDYzeiIvPjxwYXRoIGZpbGw9IiMwMzcwYzgiIGQ9Ik0xNy41MTEsNDVjMi43NzEsMCwzLjc5NC0xLjg0OCw3LjQxMy0xLjg0OGMzLjM3LDAsNC40MTgsMS44NDgsNy4zMzgsMS44NDggYzMuMDcsMCw1LjA5Mi0yLjc5NSw2LjkxMy01LjU2N2MyLjI5NS0zLjIxOCwzLjA3LTYuMjg4LDMuMTY5LTYuNDE0Yy0wLjA5NCwwLTUuMjg3LTIuMTEyLTYuMDI2LTguMDE5SDUuNjc4IGMwLjE1Nyw1LjMxMSwyLjIyOCwxMC43OSw0LjY3MSwxNC4zMDlDMTIuMjcsNDIuMDU1LDE0LjQ0MSw0NSwxNy41MTEsNDV6Ii8+PC9zdmc+Cg==</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>Brand</finalclass>
|
||||
<friendlyname>Apple</friendlyname>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="3">
|
||||
<name>Asus</name>
|
||||
@@ -38,6 +42,8 @@
|
||||
40ODQgMC4wMDEsLTUuNDg0ek0xMy4xMTEsMzkuOTE0aDE1LjczYzIuOTE0LC0wLjY0NyAzLjIxOCwtMy41NzcgMy4yMTgsLTMuNTc3YzAuMTM2LC0wLjg3MSAwLjA1NywtMS41NzQgMC4wNTcsLTEuNTc0Yy0wLjA4OCwtMC41ODggLTEuMDk0LC0zLjE3OCAtMy4yODEsLTMuNDA1Yy0xLjMwNCwtMC4xMzQgLTEyLjkxLC0xLjE1NSAtMTIuOTEsLTEuMTU1YzAuMjI1LDEuMjg4IDAuNzQ4LDEuOTM4IDEuMDk0LDIuMzExYzAuODA1LDAuODU3IDIuMDg3LDEuMDk5IDIuMDg3
|
||||
LDEuMDk5YzAuMzA5LDAuMDMzIDguOTQ1LDAuODI0IDguOTQ1LDAuODI0YzAuMjc0LDAuMDE3IDAuNzk3LDAuMDkzIDAuNzksMC44NDljMCwwLjA5MSAtMC4wNzUsMC43NTcgLTAuNzM4LDAuNzU3aC0xMi4wMTRjLTAuMjc2LDAgLTAuNSwtMC4yMjQgLTAuNSwtMC41di01LjM3M2wtMy40NzgsLTAuMjgxdjkuMDI3YzAsMC41NSAwLjQ0OCwwLjk5OCAxLDAuOTk4ek00Ny40NDQsMzcuMDE3YzAuMDAxLC0wLjU1MiAwLjQ0OCwtMC45OTggMSwtMC45OThoMTEuNDI5YzAuMj
|
||||
g2LDAgMC41OTUsLTAuMTg3IDAuNTk1LC0wLjE4N2MwLjEzLC0wLjEyOSAwLjIzNSwtMC4zNjQgMC4yMzUsLTAuNTkxYzAsLTAuNzUzIC0wLjU2MSwtMC43ODYgLTAuODQzLC0wLjgwM2MwLDAgLTguNzMyLC0wLjgwOCAtOS4wMzYsLTAuODM0YzAsMCAtMS4yMTEsLTAuMjA3IC0yLjAxNywtMS4wNjhjLTAuMzUxLC0wLjM2OSAtMC44MTUsLTAuNzcxIC0xLjE2MSwtMi4wOTljMCwwIDExLjY3MSwwLjc2MyAxMi45NjgsMC44OTdjMi4xODksMC4yMzIgMy4yMTUsMi42MzIgMy4zMDgsMy40M2MwLDAgMC4wOTMsMC43MjIgLTAuMDIsMS42MDdjMCwwIC0wLjQ1NCwzLjM3NCAtMy42NjQsMy41NzloLTExLjc5N2MtMC41NTMsMCAtMS4wMDEsLTAuNDQ5IC0xLC0xLjAwMnoiIGZpbGw9InVybCgjY29sb3ItMikiIGlkPSJwYXRoMTEiLz48L2c+PC9nPjwvc3ZnPgo=</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>Brand</finalclass>
|
||||
<friendlyname>Asus</friendlyname>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="10">
|
||||
<name>Cisco</name>
|
||||
@@ -57,18 +63,24 @@
|
||||
jEsMC40ODUgMC4wMDMsMC43MjMgYSAxLjUzNiwxLjUzNiAwIDAgMSAtMC43NDQsMC44OTIgMy42OTEsMy42OTEgMCAwIDEgLTEuMjM5LDAuMzg3IDksOSAwIDAgMSAtMS45MiwwLjA5NyAyMS45NzMsMjEuOTczIDAgMCAxIC0yLjUwNywtMC4zMzQgYyAtMC40MzMsLTAuMDkgLTAuODY0LC0wLjE5IC0xLjI5MSwtMC4zMDMgeiBtIC0xMS4xNDQsNC40ODIgaCA0LjczIFYgMzcuODQ2IGggLTQuNzMgeiBNIDg1LjMwNSw0My4zODYgYSA0LjkzNCw0LjkzNCAwIDEgMSA2LjE
|
||||
1Nyw3LjcxMSA0LjkzNCw0LjkzNCAwIDAgMSAtNi4xNTcsLTcuNzEgbSAtNi44NjcsMy44NDggYSA5Ljg3LDkuODcgMCAwIDAgMTIuMDAyLDkuNDg1IDkuNjI5LDkuNjI5IDAgMCAwIDMuMTU3LC0xNy43MjkgOS45MzQsOS45MzQgMCAwIDAgLTE1LjE2LDguMjQ0IiBpZD0icGF0aDIiLz48dXNlIGhyZWY9IiNiYXJfc2hvcnQiIHg9IjAiIGlkPSJ1c2UzIi8+PHVzZSBocmVmPSIjYmFyX3RhbGwiIHg9IjAiIGlkPSJ1c2U0Ii8+PHVzZSBocmVmPSIjYmFyX2dyYW5kZSIge
|
||||
D0iMCIgaWQ9InVzZTUiLz48dXNlIGhyZWY9IiNiYXJfdGFsbCIgeD0iMjUuODc1IiBpZD0idXNlNiIvPjx1c2UgaHJlZj0iI2Jhcl9zaG9ydCIgeD0iNTEuNzUiIGlkPSJ1c2U3Ii8+PHVzZSBocmVmPSIjYmFyX3RhbGwiIHg9IjUxLjc1IiBpZD0idXNlOCIvPjx1c2UgaHJlZj0iI2Jhcl9ncmFuZGUiIHg9IjUxLjc1IiBpZD0idXNlOSIvPjx1c2UgaHJlZj0iI2Jhcl90YWxsIiB4PSI3Ny42MjUiIGlkPSJ1c2UxMCIvPjx1c2UgaHJlZj0iI2Jhcl9zaG9ydCIgeD0iMTAzLjM3NSIgaWQ9InVzZTExIi8+PC9nPjxtZXRhZGF0YSBpZD0ibWV0YWRhdGExMSI+PHJkZjpSREY+PGNjOldvcmsgcmRmOmFib3V0PSIiPjxkYzp0aXRsZT5DaXNjby5jb20gRnJhbmNlPC9kYzp0aXRsZT48L2NjOldvcms+PC9yZGY6UkRGPjwvbWV0YWRhdGE+PC9zdmc+Cg==</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>Brand</finalclass>
|
||||
<friendlyname>Cisco</friendlyname>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="5">
|
||||
<name>Dell</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>icons8-dell.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiMwMjg4ZDEiIGQ9Ik0yNCw0QzEyLjk1Niw0LDQsMTIuOTU2LDQsMjRzOC45NTYsMjAsMjAsMjBzMjAtOC45NTYsMjAtMjBTMzUuMDQ0LDQsMjQs
|
||||
NHogTTI0LDQxYy05LjM5MSwwLTE3LTcuNjA5LTE3LTE3UzE0LjYwOSw3LDI0LDdzMTcsNy42MDksMTcsMTdTMzMuMzkxLDQxLDI0LDQxeiIvPjxwYXRoIGZpbGw9IiMwMjg4ZDEiIGQ9Ik0zNS42NDEsMjUuNTYzbDIuODQsMC4wMDRsLTAuMDA0LDIuMzk1bC01LjY5MS0wLjAxMmwwLjAxMi04LjE3MmwyLjg1NSwwLjAwNEwzNS42NDEsMjUuNTYzeiBNMjYuMzQsMjUuMTAybC00LjY5OSwzLjY4NGwtNC4yODUtMy4zNzljLTAuNjIxLDEuNDg0LTIuMTA5LDIuNTItMy44Mz
|
||||
YsMi41MTZsLTMuNjY0LTAuMDA0bDAuMDA4LTguMTcybDMuNjY4LDAuMDA0YzEuOTI2LDAuMDA0LDMuMzA5LDEuMjIzLDMuODI4LDIuNTMxbDQuMjk3LTMuMzY3bDEuNTg2LDEuMjVsLTMuOTM0LDMuMDg2bDAuNzU0LDAuNTk0bDMuOTM0LTMuMDg2bDEuNTksMS4yNTRsLTMuOTM0LDMuMDgybDAuNzUsMC41OTRsMy45NDEtMy4wODJsMC4wMDQtMi44MzZsMi44NTIsMC4wMDRsLTAuMDA4LDUuNzgxbDIuODQsMC4wMDRsLTAuMDA0LDIuMzkxbC01LjY5MS0wLjAwOEwyNi4zNCwyNS4xMDJ6IE0xNS4wMTIsMjMuODRjMC0xLjExMy0wLjczLTEuNzQyLTEuNzctMS43NDJoLTAuNjM3bC0wLjAwNCwzLjQ3N2gwLjYyMUMxNC4xODQsMjUuNTc0LDE1LjAxMiwyNS4wNTEsMTUuMDEyLDIzLjg0Ii8+PC9zdmc+Cg==</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>Brand</finalclass>
|
||||
<friendlyname>Dell</friendlyname>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="7">
|
||||
<name>HP Inc</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>icons8-hp.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiNmZmYiIGQ9Ik0yNCA0QTIwIDIwIDAgMSAwIDI0IDQ0QTIwIDIwIDAgMSAwIDI0IDRaIi8+PHBhdGggZmlsbD0iIzE5NzZkMiIgZD0iTTI0LDQzLj
|
||||
k5N2MtMC4xOTksMC0wLjY1MiwwLjAwNi0wLjg1LDBsNC0xMC45OTloNS42MjVjMC45ODcsMCwyLjA3MS0wLjc1OSwyLjQwOS0xLjY4Nmw0Ljc0OC0xMi42ODdjMC43MjUtMS45OTUtMC40MTctMy42MjYtMi41MzktMy42MjZoLTcuODA0bC02LjUxOCwxOC4yNTdoLTAuMDAybC0zLjcxMiwxMC4xOThDMTAuNTUsNDEuMzYxLDQsMzMuNDQ1LDQsMjMuOTk5YzAtOS4xNzQsNi4xNzgtMTYuOTA1LDE0LjYtMTkuMjYxbC0zLjgzLDEwLjUyNmgtMC4wMDFMOC4xNSwzMi45OTho
|
||||
NC4yMzlsNS41NzYtMTQuOTk5aDMuMTg1bC01LjU3NiwxNC45OTlsMy45MTksMC4wMDFsNS40MzgtMTQuMzc0YzAuNzI2LTEuOTk1LTAuNDE2LTMuNjI2LTIuNTM2LTMuNjI2SDE5LjE1bDMuOTUxLTEwLjk3OEMyMy4zOTksNC4wMDgsMjMuNjk5LDQsMjQsNGMxMS4wNDYsMCwyMCw4Ljk1MywyMCwxOS45OTlTMzUuMDQ2LDQzLjk5NywyNCw0My45OTd6IE0zNi4xNSwxNy45OTloLTMuMTg1bC00LjUwOSwxMS45OTloMy4xODVMMzYuMTUsMTcuOTk5eiIvPjwvc3ZnPgo=</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>Brand</finalclass>
|
||||
<friendlyname>HP Inc</friendlyname>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="1">
|
||||
<name>HPE</name>
|
||||
@@ -78,6 +90,8 @@
|
||||
hcGU6Y3g9Ii0yMTcuOTQxNzUiIGlua3NjYXBlOmN5PSIyNzUuMTQyNCIgaW5rc2NhcGU6d2luZG93LXdpZHRoPSIyNTYwIiBpbmtzY2FwZTp3aW5kb3ctaGVpZ2h0PSIxMzYwIiBpbmtzY2FwZTp3aW5kb3cteD0iMCIgaW5rc2NhcGU6d2luZG93LXk9IjAiIGlua3NjYXBlOndpbmRvdy1tYXhpbWl6ZWQ9IjEiIGlua3NjYXBlOmN1cnJlbnQtbGF5ZXI9ImthdG1hbl8xIj48c29kaXBvZGk6Z3VpZGUgcG9zaXRpb249IjE5Ny42NjI0NCwzMTQuNDg4NDgiIG9yaWVudGF0a
|
||||
W9uPSIwLC0xIiBpZD0iZ3VpZGUyIiBpbmtzY2FwZTpsb2NrZWQ9ImZhbHNlIi8+PC9zb2RpcG9kaTpuYW1lZHZpZXc+CjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyIgaWQ9InN0eWxlMSI+Cgkuc3Qwe2ZpbGw6bm9uZTtzdHJva2U6IzAwMDAwMDtzdHJva2Utd2lkdGg6MzY7fQoJLnN0MXtmaWxsOm5vbmU7c3Ryb2tlOiMwM0E4ODM7c3Ryb2tlLXdpZHRoOjM2O30KPC9zdHlsZT4KPHBhdGggY2xhc3M9InN0MCIgZD0ibSAxOC41MTE5ODcsNDA1LjkzMDEyIHYgLTE4MCBtIDE
|
||||
1NC4wMDAwMDMsMTgwIHYgLTE4MCBtIC0xNTQuMDAwMDAzLDg5IEggMTU1LjUxMTk5IG0gOTUsOTEgdiAtMTgwIG0gMCwxOCBoIDEwMiBjIDI3LjYsMCA1MCwyMi40IDUwLDUwIDAsMjcuNiAtMjIuNCw1MCAtNTAsNTAgaCAtMTAyIG0gMjIyLC02NyB2IC0zMyBoIDE1OCIgaWQ9InBhdGgxIi8+CjxwYXRoIGNsYXNzPSJzdDEiIGQ9Im0gNjMwLjUxMTk5LDM4Ny45MzAxMiBoIC0xNTggdiAtNzYgaCAxNTgiIGlkPSJwYXRoMiIvPgo8L3N2Zz4K</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>Brand</finalclass>
|
||||
<friendlyname>HPE</friendlyname>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="8">
|
||||
<name>IBM</name>
|
||||
@@ -86,6 +100,8 @@
|
||||
3IDE2ek0zNi43NzYgMzJMMzcuNTMxIDM0IDM4LjI3NiAzMnpNNDIgMzJINDhWMzRINDJ6TTM5LjQ3OSAxN0wzOC44MTkgMTkgNDYgMTkgNDggMTkgNDggMTd6TTM5LjM5MyAyOUwzNS42NDMgMjkgMzYuMzk4IDMxIDM4LjY0OCAzMXpNNDIgMjZINDZWMjhINDJ6TTM4LjQ5IDIwTDM3LjgzIDIyIDQ2IDIyIDQ2IDIwek0wIDE0SDhWMTZIMHpNMCAxN0g4VjE5SDB6TTIgMjBINlYyMkgyek0yIDIzSDZWMjVIMnpNMiAyNkg2VjI4SDJ6TTAgMjlIOFYzMUgwek0wIDMySDhWM
|
||||
zRIMHpNMTAgMTdIMThWMTlIMTB6TTI0Ljk3NyAxNmMtLjkxMy0xLjIwOC0yLjM0Ny0yLTMuOTc3LTJIMTB2Mmg3LjAyM0gyNC45Nzd6Ii8+PHBhdGggZmlsbD0iIzNmNTFiNSIgZD0iTTI1LjU3OCAxN2gtOS4xMzFDMTYuMTcxIDE3LjYxMyAxNiAxOC4yODMgMTYgMTloMTBDMjYgMTguMjg4IDI1Ljg0NiAxNy42MTMgMjUuNTc4IDE3ek0yMy45NzUgMjNIMTJ2MmgxMS45NzNjLS44MzMtLjYyLTEuODU0LTEtMi45NzMtMUMyMi4xMTkgMjQgMjMuMTQyIDIzLjYyMSAyMy4
|
||||
5NzUgMjN6TTE3LjAyMyAzMkgxMHYyaDExYzEuNjMgMCAzLjA2NS0uNzkyIDMuOTc3LTJIMTcuMDIzek0xOCAyOWgtMi02djJoNi40NDdIMThoNy41NzhDMjUuODQ2IDMwLjM4NyAyNiAyOS43MTIgMjYgMjlIMTh6TTIxIDIwYzAgMCAwIC4wODMgMCAxcy0xIDEtMSAxaDQuOTc5Yy40NDEtLjU4NC43Ny0xLjI1Ny45MjEtMkgyMXpNMTIgMjBIMTdWMjJIMTJ6Ii8+PGc+PHBhdGggZmlsbD0iIzNmNTFiNSIgZD0iTTIxIDI4aDQuODg1Yy0uMTU2LS43MzgtLjQ2Ny0xLjQxOC0uOTA3LTJIMjBjMCAwIDEgLjE2NyAxIDFTMjEgMjggMjEgMjh6TTEyIDI2SDE3VjI4SDEyeiIvPjwvZz48L3N2Zz4K</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>Brand</finalclass>
|
||||
<friendlyname>IBM</friendlyname>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="9">
|
||||
<name>Lenovo</name>
|
||||
@@ -98,6 +114,8 @@
|
||||
ZmlsbD0iI2ZmZiIgZD0iTTIxLjM3NywyNy45ODdjMC0wLjA5NSwwLjAwMS0yLjU4NywwLTMuNjYzYy0wLjAwMS0wLjc1OS0wLjYwNS0xLjMyNy0xLjQxNC0xLjMzMSBjLTAuNzk0LTAuMDA1LTEuMzgzLDAuNTYtMS4zODQsMS4zMzJjLTAuMDAxLDEuMDc2LDAsMy42NzksMCwzLjY3OWwtMS43NDEsMC4wMDJsMC4wMDctNi4zNzhjMCwwLDEuMTY4LTAuMDE4LDEuNzIyLTAuMDE4IGMwLDAuMjY0LTAuMDA2LDAuODMyLTAuMDA2LDAuODMyczAuMTM4LTAuMTI4LDAuMTgxLT
|
||||
AuMTcxYzEuMTU3LTEuMTc0LDMuMjI2LTAuOTczLDQuMDMxLDAuMzkxIGMwLjIyMywwLjM3OCwwLjMzOCwwLjc4OSwwLjM0LDEuMjIzYzAuMDA4LDEuMjY0LDAuMDAzLDQuMTA0LDAuMDAzLDQuMTA0UzIxLjk2NCwyNy45ODcsMjEuMzc3LDI3Ljk4N3oiLz48cGF0aCBmaWxsPSIjZmZmIiBkPSJNMzAuMTY0LDIxLjYwOGMwLjY0MiwwLDEuOTY0LDAuMDE1LDEuOTY0LDAuMDE1czEuNDc4LDQuMDI0LDEuNTI2LDQuMTQ5IGMwLjExNS0wLjMxMSwxLjIwOC0zLjI5LDEuNTIx
|
||||
LTQuMTc0YzAuNjQ2LDAuMDE4LDEuMjg4LDAuMDEsMS45NywwLjAxYy0wLjAyOSwwLjA4NC0yLjU2Miw2LjM5OC0yLjU2Miw2LjM5OGwtMS44NzYtMC4wMDMgQzMxLjkwNSwyNi4wNDIsMzAuMTkxLDIxLjY5MiwzMC4xNjQsMjEuNjA4eiIvPjxwYXRoIGZpbGw9IiNmZmYiIGQ9Ik01Ljc2NywyNi4zOTNjMC4xMDQsMCwzLjg2OCwwLjAxMSwzLjg2OCwwLjAxMWwtMC4wMDIsMS41ODFMNCwyNy45ODl2LTguMDczaDEuNzcgQzUuNzcsMTkuOTE2LDUuNzY3LDI2LjI4NCw1Ljc2NywyNi4zOTN6Ii8+PC9zdmc+Cg==</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>Brand</finalclass>
|
||||
<friendlyname>Lenovo</friendlyname>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="4">
|
||||
<name>Razer</name>
|
||||
@@ -128,6 +146,8 @@
|
||||
zIuNyA4Yy0uMSAwLS4zIDAtLjYuNEMzMiA4LjYgMzIgOC45IDMyIDkuMWMwIDEuMyAxLjggMi45IDMuNSA0LjQgMi43IDIuNCA1LjcgNS4yIDQgOC40LS41IDEtMS4zIDEuNi0yLjMgMS45LTEuMS4zLTIuMy4xLTMuNC0uNEMzMi42IDI0LjYgMzAuOCAyNSAyOS40IDI1ek0yOSAyMWMtLjIgMC0uNC4xLS42LjItLjIuMS0uNC40LS40LjYtLjEuNS4zIDEuMS44IDEuMi41LjEgMS45LjEgMi45LS41LS41LS4zLTEtLjYtMS41LS45LS40LS4zLS45LS42LTEuMS0uNkMyOS4
|
||||
xIDIxIDI5LjEgMjEgMjkgMjF6Ii8+PHBhdGggZD0iTTMyLjYgMjEuN2MuMi0uMi40LS42LjYtLjkuMi0uMy4zLS43LjMtMS4xIDAtLjQgMC0uNy0uMi0xLjEtLjEtLjQtLjQtLjctLjgtMSAuNC4yLjguMyAxLjIuNy4zLjMuNi44LjggMS4zLjEuNS4yIDEgLjIgMS41IDAgLjUtLjEgMS0uMyAxLjVsMCAuMWMtLjIuNS0uOC44LTEuMy42cy0uOC0uOC0uNi0xLjNDMzIuNCAyMS45IDMyLjUgMjEuOCAzMi42IDIxLjd6TTQwLjggNC4xYy0uMiAwLS40LS4yLS41LS40IDAtL
|
||||
jMuMS0uNS40LS42LjEgMCAuMi0uMi4yLS42QzQxIDIuMiA0MS4yIDIgNDEuNSAyUzQyIDIuMiA0MiAyLjVDNDIgMy4zIDQxLjUgNCA0MC44IDQuMSA0MC45IDQuMSA0MC45IDQuMSA0MC44IDQuMXoiLz48cGF0aCBkPSJNMzksNC41Yy0wLjIsMC0wLjQtMC4yLTAuNS0wLjRjLTAuMS0wLjMsMC4xLTAuNSwwLjQtMC42QzM5LDMuNSw0MSwzLDQyLjUsM0M0Mi44LDMsNDMsMy4yLDQzLDMuNVM0Mi44LDQsNDIuNSw0IGMtMS40LDAtMy40LDAuNS0zLjQsMC41QzM5LjEsNC41LDM5LDQuNSwzOSw0LjV6Ii8+PC9zdmc+Cg==</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>Brand</finalclass>
|
||||
<friendlyname>Razer</friendlyname>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="11">
|
||||
<name>Samsung</name>
|
||||
@@ -143,6 +163,8 @@
|
||||
y0wLjAxMy0wLjIzNS0wLjAxMS0wLjMyNXYtMy41NmgxLjI1NHYzLjY3MmMwLDAuMDY0LDAuMDAyLDAuMTM3LDAuMDEyLDAuMTkgQzI4LjkyMSwyNS40NzMsMjkuMDI1LDI1LjcxMywyOS4zNzIsMjUuNzEzeiIvPjxwYXRoIGZpbGw9IiNmYWZhZmEiIGQ9Ik0zOS43MjUsMjUuNjZjMC4zNTksMCwwLjQ4NS0wLjIyNywwLjUwOC0wLjM1OWMwLjAwOS0wLjA1NywwLjAxMi0wLjEyNiwwLjAxMS0wLjE4OXYtMC43MiBoLTAuNTA5di0wLjcyNGgxLjc2VjI1Yy0wLjAwMSwwLjA
|
||||
5My0wLjAwMywwLjE2Mi0wLjAxOCwwLjMyN2MtMC4wODIsMC45MDMtMC44NjYsMS4yMjUtMS43NDUsMS4yMjUgYy0wLjg4MSwwLTEuNjYzLTAuMzIyLTEuNzQ3LTEuMjI1Yy0wLjAxNC0wLjE2Ni0wLjAxNi0wLjIzNC0wLjAxOC0wLjMyN2wwLjAwMS0yLjA4OWMwLTAuMDg4LDAuMDExLTAuMjQ0LDAuMDIxLTAuMzI3IGMwLjExLTAuOTI4LDAuODYyLTEuMjI2LDEuNzQzLTEuMjI2YzAuODgsMCwxLjY1MSwwLjI5NywxLjc0MiwxLjIyNmMwLjAxNiwwLjE1OCwwLjAxMSwwL
|
||||
jMyNywwLjAxMSwwLjMyN3YwLjE2NmgtMS4yNTF2LTAuMjc4IGMwLjAwMSwwLjAwMS0wLjAwMi0wLjExOC0wLjAxNi0wLjE4OWMtMC4wMjEtMC4xMS0wLjExNi0wLjM2Mi0wLjQ5NS0wLjM2MmMtMC4zNjIsMC0wLjQ2NywwLjIzOC0wLjQ5NCwwLjM2MiBjLTAuMDE1LDAuMDY1LTAuMDIxLDAuMTU0LTAuMDIxLDAuMjM0djIuMjdjLTAuMDAxLDAuMDYzLDAuMDAzLDAuMTMyLDAuMDEzLDAuMTg5QzM5LjI0MSwyNS40MzMsMzkuMzY2LDI1LjY2LDM5LjcyNSwyNS42NnoiLz48L3N2Zz4K</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>Brand</finalclass>
|
||||
<friendlyname>Samsung</friendlyname>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="12">
|
||||
<name>Sony</name>
|
||||
@@ -165,6 +187,8 @@
|
||||
OTkyIC03Mi4wODk2LC04MS45MTk5OSAtNzUuMjg5NiwtODUuNTAzOTkgLTMuOTkzNiwtNC4zNTIgLTExLjAwOCwtMTEuMDg0NzkgLTIxLjY4MzIsLTExLjA4NDc5IGggLTI0LjQ0Nzk2IHYgLTI1LjAzNjggaCAxMzcuOTgzOTYgdiAyNC45ODU2IGggLTE2LjY0IGMgLTMuODQsMCAtNi40LDMuNjYwNzkgLTMuMTIzMiw3LjY3OTk5IDAsMCA0Ni40Mzg0LDU1LjU1MiA0Ni44NzM2LDU2LjE0MDggMC40MzUyLDAuNTg4OCAwLjgxOTIsMC43MTY4IDEuNDA4LDAuMTc5MiAwLj
|
||||
U4ODgsLTAuNTM3NiA0Ny41OTA0LC01NS44MDggNDcuOTQ4OCwtNTYuMzIgYSA0Ljc4NzE5OTQsNC43ODcxOTk0IDAgMCAwIC00LjA5NiwtNy42Nzk5OSBoIC0xNy4wNzUyIFYgNTM5LjA2MjEgSCAxMjgwIHYgMjUuMDM2OCBoIC0yNS4yNjcyIGMgLTkuMTY0OCwwIC0xMi44LDEuNjg5NTkgLTE5Ljc4ODgsOS40NzE5OSBsIC03Ni4xNiw4Ni44ODYzOSBhIDUuMzc1OTk5NCw1LjM3NTk5OTQgMCAwIDAgLTAuOTIxNiwzLjY4NjQgdiAzOS41MjY0IGEgMjguMTU5OTk3LDI4
|
||||
LjE1OTk5NyAwIDAgMCAwLjU2MzIsNS40MDE2IDguNTI0Nzk5LDguNTI0Nzk5IDAgMCAwIDUuNDAxNiw0LjgxMjggNTAuNjExMTk0LDUwLjYxMTE5NCAwIDAgMCA2LjkxMiwwLjQzNTIgaCAyNS44MzA0IHYgMjUuMDM2OCBoIC0xMzcuMjY3MiB2IC0yNS4wMzY4IHoiIGlkPSJwYXRoMSIgZmlsbD0iIzAwMDAwMCIgc3R5bGU9InN0cm9rZS13aWR0aDoyLjU2Ii8+PC9zdmc6Zz48L3N2ZzpnPjwvc3ZnOnN2Zz4K</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>Brand</finalclass>
|
||||
<friendlyname>Sony</friendlyname>
|
||||
</Brand>
|
||||
<Brand alias="Brand" id="13">
|
||||
<name>Toshiba</name>
|
||||
@@ -174,6 +198,8 @@
|
||||
uMDEzIiBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjI1NjAiIGlua3NjYXBlOndpbmRvdy1oZWlnaHQ9IjEzNjAiIGlua3NjYXBlOndpbmRvdy14PSIwIiBpbmtzY2FwZTp3aW5kb3cteT0iMCIgaW5rc2NhcGU6d2luZG93LW1heGltaXplZD0iMSIgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0ic3ZnMSI+PHNvZGlwb2RpOmd1aWRlIHBvc2l0aW9uPSIyMjcuMzE3MTYsMzk5LjM4NTQyIiBvcmllbnRhdGlvbj0iMCwtMSIgaWQ9Imd1aWRlMSIgaW5rc2NhcGU6bG9ja2VkPSJmY
|
||||
WxzZSIvPjwvc29kaXBvZGk6bmFtZWR2aWV3PgogIDxzdmc6cGF0aCBmaWxsPSIjZTYxZTFlIiBkPSJtIDc2Ni4xMDAxNiw0NTkuNzEzNiBoIDM0LjU1IGwgLTM1LjY1LC0xMTcuNjYgLTQ5LjEsLTAuMDAyIC0zNS42NSwxMTcuNjYgaCAzNC41NiBsIDYuMywtMjEuNzggaCAzOC42NiBsIDYuMzMsMjEuNzggbSAtMzcuNTEsLTQ3Ljk0MyAxMS43NiwtNDAuNjUxIGggMC4yIGwgMTEuNzYsNDAuNjUxIHogbSAtNTU1LjQ2LDUwLjA1NSBjIDM1LjQ4LDAgNTIuNjMsLTYuMjU
|
||||
gNTUuMDYsLTM4LjI2NSAwLjU4LC03LjYxOCAwLjY5LC0xNS40MzkgMC42OSwtMjIuNjg5IDAuMDEsLTcuMjI1IC0wLjExLC0xNS4wNTQgLTAuNjksLTIyLjY3MSAtMi40MywtMzIuMDI1IC0xOS41OCwtMzguMjY1IC01NS4wNiwtMzguMjY1IC0zNS40OCwwIC01Mi42Miw2LjI0IC01NS4wNCwzOC4yNjUgLTAuNTksNy42MTcgLTAuNzEsMTUuNDQ2IC0wLjcxLDIyLjY3MSAwLjAxLDcuMjUgMC4xMiwxNS4wNzEgMC43MSwyMi42ODkgMi40MiwzMi4wMTUgMTkuNTYsMzguMjY1IDU1LjA0LDM4LjI2NSBtIC0yMi4zMSwtNjAuOTU0IGMgMCwtNi40NjEgMC4xNiwtMTAuMjggMC4zLC0xMy4xMTQgMC45LC0xOC4xNjEgOC4wNywtMjAuMjc4IDIyLjAxLC0yMC4yNzggMTMuOTUsMCAyMS4xMiwyLjExNyAyMi4wMSwyMC4yNzggMC4xNCwyLjgzMyAwLjMxLDYuNjUyIDAuMzEsMTMuMTE0IDAsNi40ODIgLTAuMTcsMTAuMzA4IC0wLjMxLDEzLjEzNSAtMC44OSwxOC4xNjQgLTguMDYsMjAuMjg1IC0yMi4wMSwyMC4yODUgLTEzLjk0LDAgLTIxLjExLC0yLjEyMSAtMjIuMDEsLTIwLjI4NSAtMC4xNCwtMi44MjcgLTAuMywtNi42NTMgLTAuMywtMTMuMTM1IHogTSAwLjY1MDE1ODIyLDM0Mi4xMDU2IHYgMjkuMzMxIEggMzUuODIyMTU4IHYgODguMzI3IGggMzUuMTg1IHYgLTg4LjMyNyBoIDM1LjE3MzAwMiB2IC0yOS4zMzEgSCAwLjY1MDE1ODIyIE0gNTQwLjUwMDE2LDQ1OS43MTM2IHYgLTExNy42NjIgaCAtMzMuMzkgdiAxMTcuNjYyIGggMzMuMzkgbSAtMTM0LjM1LC03NC43MDMgdiAtNDIuOTU5IGggLTMzLjIgdiAxMTcuNjYyIGggMzMuMiB2IC00NS4zNzIgaCAzOC41OCB2IDQ1LjM3MiBoIDMzLjE5IHYgLTExNy42NjIgaCAtMzMuMTkgdiA0Mi45NTkgaCAtMzguNTggbSAyNDQuMTcsMTMuMjA2IGMgMTQuNzksLTMuNzgxIDE5LjEzLC0xMi42MTYgMTkuMTMsLTI1LjM4NiAwLC0yNS44NTkgLTE2LjI3LC0zMC43OCAtMzkuNCwtMzAuNzggaCAtNTkuOTUgdiAxMTcuNjYgaCA2Mi45MiBjIDI4Ljk3LDAgMzguNzEsLTEyLjQ4IDM4LjcxLC0zMS42NzUgMCwtMTMuMzgzIC0zLjA2LC0yNS4xOTEgLTIxLjQxLC0yOS44MjIgbSAtNDcuMDMsMTMuMTY5IGggMjMuMDIgYyA5LjMsMCAxMS4yNCw0LjA3NCAxMS4yNCwxMC43IDAsNi42MzIgLTMuNjQsMTAuNzE3IC0xMS4yNCwxMC43MTcgaCAtMjMuMDIgeiBtIDAsLTQyLjQyNSBoIDIzLjAyIGMgNi4wMSwwIDkuNzMsMi44NTEgOS43Myw5LjcwOCAwLDUuODc4IC0zLjY4LDkuNDk2IC05LjczLDkuNDk2IGggLTIzLjAyIHogbSAtMzU1LjA2LDUyLjE0MyBoIDMxLjY1IGMgMC4wMyw1LjcwOCAwLjc2LDkuNTIzIDMuNTMsMTEuNjMgMy4xNSwyLjM3NCA1Ljk3LDMuMTU4IDE1LjMyLDMuMTU4IDksMCAxOC44NiwwIDE4Ljg2LC0xMS4wODUgMCwtOC43NDIgLTUuNTEsLTEwLjczNyAtMTUuNjgsLTExLjI3OSAtMjUuMjIsLTEuMzM2IC0zNC4zNCwtMi4wNDkgLTQzLjczLC05LjAyNSAtNi40LC00Ljc1NyAtOS43MiwtMTQuMDE4IC05LjcyLC0yNi41NDIgMCwtMjEuMjk3IDcuNDMsLTI4Ljc2OCAxOC4xNSwtMzMuOTgxIDExLjA2LC01LjM4MSA1NC40NywtNS4zODEgNjYuMTUsMCAxNC42OSw2Ljc2OCAxNS4xMiwyMS40MiAxNS4xMiwzNS4wMTEgaCAtMzEuNTcgYyAtMC4wNiwtNi45MjkgLTEuNjIsLTguODg2IC0yLjg5LC0xMC4xNzUgLTMuMjgsLTIuOTA4IC03Ljk1LC0zLjUyMiAtMTQuNjksLTMuNTIyIC04LjE2LDAgLTE3LjYsMC4zNjggLTE3LjYsMTAuMjc3IDAsNy41NiAzLjI3LDEwLjcyIDExLjg1LDExLjI3NiAxMS43OSwwLjc1NCAzNS4wMiwxLjQ5NyA0My4zLDYuMzgzIDExLjYxLDYuODY3IDE0LjYyLDE2LjE1OSAxNC42MiwzMS4zMTkgMCwyMS45MDggLTcuODQsMjguMzM4IC0xOC43NSwzMy4xNTggLTEyLjU5LDUuNTYgLTU0LjY0LDUuNTYgLTY4LjMxLC0wLjQzIC0xNS4zLC02LjY3IC0xNS42MSwtMTkuOTY0IC0xNS42MSwtMzYuMTczIiBpZD0icGF0aDEiLz4KPC9zdmc6c3ZnPgo=</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>Brand</finalclass>
|
||||
<friendlyname>Toshiba</friendlyname>
|
||||
</Brand>
|
||||
</Set>
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
<OSFamily alias="OSFamily" id="1">
|
||||
<name>Arch</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>icons8-arch-linux.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmlld0JveD0iMCwwLDI1NiwyNTYiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiIGZpbGwtcnVsZT0ibm9uemVybyI+PGcgZmlsbD0iIzAwODhjYyIgZmlsbC1ydWxlPSJub256ZXJvIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgc3Ryb2tlLWxpbmVjYXA9ImJ1dHQiIHN0cm9rZS1saW5lam9pbj0ibWl0ZXIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLWRhc2hhcnJheT0iIiBzdHJva2UtZGFzaG9mZnNldD0iMCIgZm9udC1mYW1pbHk9Im5vbmUiIGZvbnQtd2VpZ2h0PSJub25lIiBmb250LXNpemU9Im5vbmUiIHRleHQtYW5jaG9yPSJub25lIiBzdHlsZT0ibWl4LWJsZW5kLW1vZGU6IG5vcm1hbCI+PGcgdHJhbnNmb3JtPSJzY2FsZSg1LjMzMzMzLDUuMzMzMzMpIj48cGF0aCBkPSJNMjguNDY1LDM4LjYxMWMwLjQxOSwtMS4xMDUgMC42NjQsLTIuMzY1IDAuNjY0LC0zLjcxNGMwLC00LjEzMyAtMi4yMTEsLTcuNDk0IC00LjkyOSwtNy40OTRjLTIuNzQxLDAgLTQuOTUxLDMuMzYxIC00Ljk1MSw3LjQ5NGMwLDEuMzI2IDAuMjIxLDIuNTg2IDAuNjQxLDMuNjY5Yy05LjA0MSwwLjk1MSAtMTUuNDA3LDQuNzMxIC0xNy45OTMsNi40MzJjNC4zNTUsLTYuMjc4IDguOTA5LC0xMy42MzggMTMuMjYyLC0yMi4xMDVjMS4wODMsLTIuMTAxIDIuMTAxLC00LjE3OCAzLjA1LC02LjIxMWMwLjM3NSwwLjI0MyAwLjc1MSwwLjUwOSAxLjE3MSwwLjc3NWMxLjk0NSwxLjIxNSAzLjc1OSwxLjg3OSA1LjA4NCwyLjIzM2MtMC45NzMsLTAuNzMgLTIuMDMzLC0xLjYxMyAtMy4xMTYsLTIuNjk3Yy0wLjgxNywtMC44MTcgLTEuNTQ3LC0xLjYzNyAtMi4xNjcsLTIuNDMzYzEuODM1LC00LjAyMiAzLjQyNywtNy44OTEgNC44MTksLTExLjU2YzIuMzIsNi4xNDQgNS4yMTcsMTIuODQyIDguODQxLDE5Ljg5M2MyLjM0Myw0LjUzMSA0LjczMSw4Ljc1NCA3LjExNywxMi42NDRjLTAuNjg1LC0wLjM3NSAtMS40MzcsLTAuNzMgLTIuMjMzLC0xLjAzOWMtMS4zNzEsLTAuNTMgLTIuNjUyLC0wLjg2MiAtMy43NTksLTEuMDZjMS41MDMsMC43NTEgMy4yNSwxLjc0NyA1LjA4NCwzLjA3M2MxLjE5NCwwLjg4NSAyLjI1NCwxLjc2OSAzLjE2MSwyLjYzMWMwLjAyMSwwLjAyMSAwLjAyMSwwLjAyMSAwLjA0NSwwLjA0NWMxLjI2LDIuMDU2IDIuNTY1LDMuOTU3IDMuODQ2LDUuODEzYy0yLjU0MSwtMS42ODEgLTguNzk2LC01LjM5NSAtMTcuNjM3LC02LjM4OXoiLz48L2c+PC9nPjwvc3ZnPgo=</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>OS Family</finalclass>
|
||||
<friendlyname>Arch</friendlyname>
|
||||
</OSFamily>
|
||||
<OSFamily alias="OSFamily" id="2">
|
||||
<name>Debian</name>
|
||||
@@ -22,6 +24,8 @@
|
||||
k5LTQuMjZjMC42NjktMC44NDEtMC4xMzItMC4wMDItMC4yNjMtMC4yMTVjMS40NjktMS41MiwxLjkzLTEuMDczLDIuOTItMS4zNDljMS4wNjgtMC42MzMtMC45MTcsMC4yNTEtMC40MS0wLjIzOWMxLjg0OC0wLjQ3MywxLjMxLTEuMDczLDMuNzE4LTEuMzExYzAuMjU0LDAuMTQ1LTAuNTksMC4yMjMtMC44LDAuNDFjMS41MzgtMC43NTMsNC44Ny0wLjU4NCw3LjAzNCwwLjQxN2MyLjUxMSwxLjE3Myw1LjMzLDQuNjQyLDUuNDQzLDcuOTA0bDAuMTI2LDAuMDM1Yy0wLjA2
|
||||
MywxLjI5OCwwLjE5OCwyLjc5OC0wLjI1Nyw0LjE3NUwzNS4yOTQsMjAuOTg2IE0yMC4wNzIsMjUuMzg5bC0wLjA4NiwwLjQzMWMwLjQwMywwLjU0NywwLjcyNCwxLjE0MiwxLjIzNywxLjU2N0MyMC44NTMsMjYuNjY0LDIwLjU3NywyNi4zNjQsMjAuMDcyLDI1LjM4OSBNMjEuMDIzLDI1LjM1M2MtMC4yMTMtMC4yMzctMC4zNC0wLjUxOC0wLjQ4LTAuODAyYzAuMTM1LDAuNDk1LDAuNDExLDAuOTIyLDAuNjY5LDEuMzU3TDIxLjAyMywyNS4zNTMgTTM3Ljg3NywyMS42OD
|
||||
hsLTAuMDg4LDAuMjI2Yy0wLjE2NiwxLjE3NC0wLjUyMywyLjMzMi0xLjA2OCwzLjQxMkMzNy4zMjQsMjQuMTg5LDM3LjcxNCwyMi45NDcsMzcuODc3LDIxLjY4OCBNMjQuNTYsNS4xODVDMjQuOTc0LDUuMDMxLDI1LjU3OSw1LjEwMSwyNi4wMTksNWMtMC41NzMsMC4wNDgtMS4xNDQsMC4wNzktMS43MDYsMC4xNTFMMjQuNTYsNS4xODUgTTEwLjAwNywxMi45MjNjMC4wOTUsMC44ODItMC42NjcsMS4yMjksMC4xNjcsMC42NDRDMTAuNjIzLDEyLjU2MiwxMCwxMy4yODYsMTAuMDA3LDEyLjkyMyBNOS4wMjgsMTcuMDE2YzAuMTkxLTAuNTkyLDAuMjI2LTAuOTQzLDAuMy0xLjI4NUM4Ljc5NywxNi40MSw5LjA4NCwxNi41NTMsOS4wMjgsMTcuMDE2Ii8+PC9zdmc+Cg==</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>OS Family</finalclass>
|
||||
<friendlyname>Debian</friendlyname>
|
||||
</OSFamily>
|
||||
<OSFamily alias="OSFamily" id="3">
|
||||
<name>Oracle Linux</name>
|
||||
@@ -37,6 +41,8 @@
|
||||
Jva2UtbGluZWNhcDpzcXVhcmU7cGFpbnQtb3JkZXI6c3Ryb2tlIGZpbGwgbWFya2VycyIgZD0ibSAyNS4zOTE1MTcsNDcuOTMwODcxIGggNC45ODA4NjMgdiAzLjgzMDAyNSBoIC00Ljk4MDg2MyB6IG0gNjEuNTAwOCwxOC41NTcwNjEgLTcuMjQsLTEwLjI0MDAwMiBoIDQuOTYgbCA0LjY0LDcuMDgwMDAyIGggMC4yNCBsIDQuNzYsLTcuMDgwMDAyIGggNC43MiBsIC03LjI4LDEwLjE2MDAwMiA3LjY0LDEwLjg4IGggLTQuOTYgbCAtNS4wOCwtNy43MiBoIC0wLjI0IGwg
|
||||
LTUuMTIsNy43MiBoIC00LjcyIHogbSAtMjEuNTk5OTk4LDExLjI4IHEgLTYuNjgsMCAtNi42OCwtNy4yNCBWIDU2LjI0NzkzIGggNC4xMiB2IDEzLjc2MDAwMiBxIDAsMi4zNiAxLjA0LDMuMzIgMS4wOCwwLjkyIDMuMTIsMC45MiAxLjQsMCAyLjYsLTAuNjggMS4yLC0wLjcyIDEuODgsLTIgMC43MiwtMS4yOCAwLjcyLC0yLjk2IFYgNTYuMjQ3OTMgaCA0LjEyIHYgMjEuMDQwMDAyIGggLTMuMzIgbCAtMC40LC0yLjggaCAtMC4yOCBxIC0xLjE2LDEuNiAtMi45MiwyLj
|
||||
Q0IC0xLjc2LDAuODQgLTQsMC44NCB6IE0gMzUuODEyMzIsNTYuMjQ3OTMgaCAzLjMyMDAwMSBsIDAuNCwyLjgwMDAwMiBoIDAuMjggcSAxLjEyLC0xLjYwMDAwMiAyLjg4LC0yLjQ0MDAwMiAxLjgsLTAuODQgNC4wNCwtMC44NCA2LjY4LDAgNi42OCw3LjI0MDAwMiB2IDE0LjI4IGggLTQuMTIgdiAtMTMuNzYgcSAwLC0yLjM2IC0xLjA4LC0zLjI4IC0xLjA0LC0wLjk2IC0zLjA4LC0wLjk2IC0xLjQsMCAtMi42LDAuNzIgLTEuMiwwLjY4IC0xLjkyLDEuOTYgLTAuNjgsMS4yOCAtMC42OCwyLjk2IHYgMTIuMzYgSCAzNS44MTIzMiBaIE0gMy42MTIzOSw0Ny45MzA4NzEgaCA0LjQ0IHYgMjUuNTE3MDYxIGggMTQuMjggdiAzLjg0IGggLTE4LjcyIHogTSAyNi4yNTY3NjgsNTkuNDYzOTUgViA3Ny4yODc5MzIgSCAzMC4zNzIzOCBWIDU2LjI3NTQ2NCBoIC02LjM4NzYxMiB2IDEuODI1NjgxIHoiLz48L2c+PC9zdmc+Cg==</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>OS Family</finalclass>
|
||||
<friendlyname>Oracle Linux</friendlyname>
|
||||
</OSFamily>
|
||||
<OSFamily alias="OSFamily" id="4">
|
||||
<name>Red Hat</name>
|
||||
@@ -62,6 +68,8 @@
|
||||
TggYy0wLjM0NC0wLjAyNy0wLjUyNi0wLjA4Ny0wLjU0My0wLjE2NGMtMC4wMTItMC4wNTIsMC4wNTUtMC4xMTEsMC4xOTctMC4xNzFjMC4wNy0wLjAzLDAuMTUzLTAuMDYxLDAuMjU2LTAuMDg5IGMwLjU4NC0wLjE2OSwwLjkxLTAuNjA4LDAuNTk0LTAuODA1Yy0wLjMzNy0wLjIxMi0xLjQ5Mi0wLjM0NS0yLjAwNC0wLjIzMWMtMC4yMTcsMC4wNDktMC4zNDIsMC4wNTEtMC4zNzQsMC4wMTMgYy0wLjAwMS0wLjAwMS0wLjAwNC0wLjAwMy0wLjAwNS0wLjAwNmMtMC4wMDk
|
||||
tMC4wMTUtMC4wMDQtMC4wMzUsMC4wMTEtMC4wNjJjMC4wMTItMC4wMTYsMC4wMjYtMC4wMzEsMC4wNDctMC4wNDggYzAsMCwwLjAwMSwwLDAuMDAyLDBjMC4wMTktMC4wMTgsMC4wNDUtMC4wMzIsMC4wNzItMC4wNDZjMC4wMDItMC4wMDMsMC4wMDYtMC4wMDMsMC4wMS0wLjAwNmMwLjAyNy0wLjAxNCwwLjA1Ny0wLjAyNywwLjA5Mi0wLjA0MSBjMC4wMDUtMC4wMDIsMC4wMDgtMC4wMDMsMC4wMTEtMC4wMDVjMC4wMzctMC4wMTQsMC4wNzctMC4wMjgsMC4xMjEtMC4wN
|
||||
DJjMC4wMDEsMCwwLjAwMy0wLjAwMiwwLjAwNS0wLjAwMiBjMC4yNzYtMC4wOSwwLjY4Mi0wLjE2NCwxLjEtMC4yMTNjMC4wMDgtMC4wMDMsMC4wMTQtMC4wMDMsMC4wMjEtMC4wMDNjMC4wNjEtMC4wMDksMC4xMjMtMC4wMTQsMC4xODYtMC4wMiBjMC4wMDktMC4wMDIsMC4wMTktMC4wMDIsMC4wMjctMC4wMDNjMC4wNjEtMC4wMDQsMC4xMTktMC4wMDksMC4xOC0wLjAxM2MwLjAwOSwwLDAuMDE5LTAuMDAyLDAuMDI3LTAuMDAyIGMwLjA2NS0wLjAwMywwLjEzMS0wLjAwNywwLjE5My0wLjAwOWMwLjAwNCwwLDAuMDA2LDAsMC4wMDYsMGMwLjIwNi0wLjAwOCwwLjQtMC4wMDIsMC41NzEsMC4wMTIgYzAuOTQ4LDAuMDg2LDEuNzE2LDAuNDIxLDEuODY4LDAuODEzYzAuMDE1LDAuMDQsMC4wMjQsMC4wOCwwLjAyNywwLjEyM0MyOS41MSwxMi45NzksMjkuMzIsMTMuMjAxLDI5LjAwMSwxMy4zOHoiLz48L3N2Zz4K</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>OS Family</finalclass>
|
||||
<friendlyname>Red Hat</friendlyname>
|
||||
</OSFamily>
|
||||
<OSFamily alias="OSFamily" id="5">
|
||||
<name>Ubuntu</name>
|
||||
@@ -71,6 +79,8 @@
|
||||
41LTEuMS0yLjUtMi41YzAtMC4yLDAtMC41LDAuMS0wLjdDMjYuNSwzMy44LDI1LjMsMzQsMjQsMzRjLTUuMSwwLTkuMi0zLjgtOS45LTguN2MtMC40LDAuNy0xLjIsMS4yLTIuMSwxLjIgYy0xLjQsMC0yLjUtMS4xLTIuNS0yLjVzMS4xLTIuNSwyLjUtMi41YzAuOSwwLDEuNywwLjUsMi4xLDEuMmMwLjctNC45LDQuOC04LjcsOS45LTguN2MxLjMsMCwyLjUsMC4yLDMuNiwwLjcgYy0wLjEtMC4yLTAuMS0wLjQtMC4xLTAuN2MwLTEuNCwxLjEtMi41LDIuNS0yLjVzMi41
|
||||
LDEuMSwyLjUsMi41YzAsMS4yLTAuOCwyLjItMiwyLjRDMzIuNywxOC4zLDM0LDIxLDM0LDI0cy0xLjMsNS43LTMuNSw3LjYgQzMxLjcsMzEuOCwzMi41LDMyLjgsMzIuNSwzNHoiLz48cGF0aCBmaWxsPSIjZTY0YTE5IiBkPSJNMzAgMTEuNWMxLjQgMCAyLjUgMS4xIDIuNSAyLjUgMCAxLjQtMS4xIDIuNS0yLjUgMi41cy0yLjUtMS4xLTIuNS0yLjVDMjcuNSAxMi42IDI4LjYgMTEuNSAzMCAxMS41TTMwIDEwLjVjLTEuOSAwLTMuNSAxLjYtMy41IDMuNXMxLjYgMy41ID
|
||||
MuNSAzLjUgMy41LTEuNiAzLjUtMy41UzMxLjkgMTAuNSAzMCAxMC41ek0yNCAyNGMtMi42LTQuMS01LjItOC4xLTcuOC0xMi4yIi8+PHBhdGggZmlsbD0iI2U2NGExOSIgZD0iTTE5LjEgMTAuN0gyMS4xVjI1LjFIMTkuMXoiIHRyYW5zZm9ybT0icm90YXRlKC0zMi40NjcgMjAuMTI3IDE3LjkxMSkiLz48cGF0aCBmaWxsPSIjZTY0YTE5IiBkPSJNMjQgMjNIMzguNFYyNUgyNHoiLz48Zz48cGF0aCBmaWxsPSIjZTY0YTE5IiBkPSJNMjQsMjRjLTIuNyw0LTUuMyw4LTgsMTIiLz48cGF0aCBmaWxsPSIjZTY0YTE5IiBkPSJNMTIuOCAyOUgyNy4yMDAwMDAwMDAwMDAwMDNWMzFIMTIuOHoiIHRyYW5zZm9ybT0icm90YXRlKC01Ni4zMTIgMTkuOTk4IDMwLjAwNikiLz48L2c+PC9zdmc+Cg==</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>OS Family</finalclass>
|
||||
<friendlyname>Ubuntu</friendlyname>
|
||||
</OSFamily>
|
||||
<OSFamily alias="OSFamily" id="6">
|
||||
<name>Ubuntu server</name>
|
||||
@@ -80,18 +90,26 @@
|
||||
41LTEuMS0yLjUtMi41YzAtMC4yLDAtMC41LDAuMS0wLjdDMjYuNSwzMy44LDI1LjMsMzQsMjQsMzRjLTUuMSwwLTkuMi0zLjgtOS45LTguN2MtMC40LDAuNy0xLjIsMS4yLTIuMSwxLjIgYy0xLjQsMC0yLjUtMS4xLTIuNS0yLjVzMS4xLTIuNSwyLjUtMi41YzAuOSwwLDEuNywwLjUsMi4xLDEuMmMwLjctNC45LDQuOC04LjcsOS45LTguN2MxLjMsMCwyLjUsMC4yLDMuNiwwLjcgYy0wLjEtMC4yLTAuMS0wLjQtMC4xLTAuN2MwLTEuNCwxLjEtMi41LDIuNS0yLjVzMi41
|
||||
LDEuMSwyLjUsMi41YzAsMS4yLTAuOCwyLjItMiwyLjRDMzIuNywxOC4zLDM0LDIxLDM0LDI0cy0xLjMsNS43LTMuNSw3LjYgQzMxLjcsMzEuOCwzMi41LDMyLjgsMzIuNSwzNHoiLz48cGF0aCBmaWxsPSIjZTY0YTE5IiBkPSJNMzAgMTEuNWMxLjQgMCAyLjUgMS4xIDIuNSAyLjUgMCAxLjQtMS4xIDIuNS0yLjUgMi41cy0yLjUtMS4xLTIuNS0yLjVDMjcuNSAxMi42IDI4LjYgMTEuNSAzMCAxMS41TTMwIDEwLjVjLTEuOSAwLTMuNSAxLjYtMy41IDMuNXMxLjYgMy41ID
|
||||
MuNSAzLjUgMy41LTEuNiAzLjUtMy41UzMxLjkgMTAuNSAzMCAxMC41ek0yNCAyNGMtMi42LTQuMS01LjItOC4xLTcuOC0xMi4yIi8+PHBhdGggZmlsbD0iI2U2NGExOSIgZD0iTTE5LjEgMTAuN0gyMS4xVjI1LjFIMTkuMXoiIHRyYW5zZm9ybT0icm90YXRlKC0zMi40NjcgMjAuMTI3IDE3LjkxMSkiLz48cGF0aCBmaWxsPSIjZTY0YTE5IiBkPSJNMjQgMjNIMzguNFYyNUgyNHoiLz48Zz48cGF0aCBmaWxsPSIjZTY0YTE5IiBkPSJNMjQsMjRjLTIuNyw0LTUuMyw4LTgsMTIiLz48cGF0aCBmaWxsPSIjZTY0YTE5IiBkPSJNMTIuOCAyOUgyNy4yMDAwMDAwMDAwMDAwMDNWMzFIMTIuOHoiIHRyYW5zZm9ybT0icm90YXRlKC01Ni4zMTIgMTkuOTk4IDMwLjAwNikiLz48L2c+PC9zdmc+Cg==</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>OS Family</finalclass>
|
||||
<friendlyname>Ubuntu server</friendlyname>
|
||||
</OSFamily>
|
||||
<OSFamily alias="OSFamily" id="7">
|
||||
<name>vCenter Server</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>icons8-vmware.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNTAgNTAiIHdpZHRoPSI1MHB4IiBoZWlnaHQ9IjUwcHgiPjxwYXRoIGQ9Ik0gNDIuNDE0MDYzIDE1IEMgMzguODI0MjE5IDE1IDM2LjU3NDIxOSAxNy41IDM2LjU3NDIxOSAxNy41IEMgMzUuMzc4OTA2IDE1Ljk0MTQwNiAzMy43MzA0NjkgMTUuMDAzOTA2IDMwLjk0MTQwNiAxNS4wMDM5MDYgQyAyNy45OTYwOTQgMTUuMDAzOTA2IDI2LjA0Mjk2OSAxNy41IDI2LjA0Mjk2OSAxNy41IEMgMjQuODQ3NjU2IDE1Ljk0MTQwNiAyMi42ODc1IDE1IDIxIDE1IEMgMTguMzkwNjI1IDE1IDE2LjMyMDMxMyAxNi4xNTIzNDQgMTUuMDU0Njg4IDE5LjA1ODU5NCBMIDEwLjgyMDMxMyAyOC4zMjAzMTMgTCA2LjAzMTI1IDE2LjU1ODU5NCBDIDUuNDI1NzgxIDE1LjIyNjU2MyAzLjkzMzU5NCAxNC42MjUgMi41NDI5NjkgMTUuMjQ2MDk0IEMgMS4xNDg0MzggMTUuODcxMDk0IDAuNjM2NzE5IDE3LjQyNTc4MSAxLjI2NTYyNSAxOC43NTc4MTMgTCA3LjExMzI4MSAzMS45NDUzMTMgQyA4LjAzMTI1IDMzLjk0OTIxOSA5LjAwMzkwNiAzNSAxMC44MjAzMTMgMzUgQyAxMi43NjU2MjUgMzUgMTMuNjA5Mzc1IDMzLjg1NTQ2OSAxNC41MzEyNSAzMS45NDUzMTMgQyAxNC41MzEyNSAzMS45NDUzMTMgMTguNTExNzE5IDIzLjA2MjUgMTkgMjIgQyAxOS40ODgyODEgMjAuOTM3NSAyMC4zMDA3ODEgMjAgMjEuNSAyMCBDIDIyLjg3NSAyMCAyNCAyMS4xMjUgMjQgMjIuNSBMIDI0IDMyLjM3NSBDIDI0IDMzLjgyMDMxMyAyNS4wODU5MzggMzUgMjYuNTIzNDM4IDM1IEMgMjcuOTU3MDMxIDM1IDI5IDMzLjgyMDMxMyAyOSAzMi4zNzUgTCAyOSAyMi41IEMgMjkgMjEuMTI1IDMwLjEyNSAyMCAzMS41IDIwIEMgMzIuODc1IDIwIDM0IDIxLjEyNSAzNCAyMi41IEwgMzQgMzIuNSBDIDM0IDMzLjg3NSAzNS4xMjUgMzUgMzYuNSAzNSBDIDM3Ljg3NSAzNSAzOSAzMy44NzUgMzkgMzIuNSBMIDM5IDIyLjUgQyAzOSAyMS4xMjUgNDAuMTI1IDIwIDQxLjUgMjAgQyA0Mi44NzUgMjAgNDQgMjEuMTI1IDQ0IDIyLjUgTCA0NCAzMi41IEMgNDQgMzMuODc1IDQ1LjEyNSAzNSA0Ni41IDM1IEMgNDcuODc1IDM1IDQ5IDMzLjg3NSA0OSAzMi41IEwgNDkgMjEuMzU1NDY5IEMgNDkgMTcuNjE3MTg4IDQ2LjAxMTcxOSAxNSA0Mi40MTQwNjMgMTUgWiIvPjwvc3ZnPgo=</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>OS Family</finalclass>
|
||||
<friendlyname>vCenter Server</friendlyname>
|
||||
</OSFamily>
|
||||
<OSFamily alias="OSFamily" id="8">
|
||||
<name>Windows</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>icons8-windows.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiMxOTc2ZDIiIGQ9Ik02LDZoMTd2MTdINlY2eiIvPjxwYXRoIGZpbGw9IiMxOTc2ZDIiIGQ9Ik0yNS4wNDIsMjIuOTU4VjZINDJ2MTYuOTU4SDI1LjA0MnoiLz48cGF0aCBmaWxsPSIjMTk3NmQyIiBkPSJNNiwyNWgxN3YxN0g2VjI1eiIvPjxwYXRoIGZpbGw9IiMxOTc2ZDIiIGQ9Ik0yNSw0MlYyNWgxN3YxN0gyNXoiLz48L3N2Zz4K</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>OS Family</finalclass>
|
||||
<friendlyname>Windows</friendlyname>
|
||||
</OSFamily>
|
||||
<OSFamily alias="OSFamily" id="9">
|
||||
<name>Windows server</name>
|
||||
<logo><mimetype>image/svg+xml</mimetype><filename>icons8-windows-server.svg</filename><data>PD94bWwgdmVyc2lvbj0iMS4wIj8+CjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB2aWV3Qm94PSIwIDAgNDggNDgiIHdpZHRoPSI0OHB4IiBoZWlnaHQ9IjQ4cHgiPjxwYXRoIGZpbGw9IiMwMGIwZmYiIGQ9Ik0yMCAyNS4wMjZMNS4wMTEgMjUgNS4wMTIgMzcuNzQ0IDIwIDM5LjgxOHpNMjIgMjUuMDNMMjIgNDAuMDk1IDQyLjk5NSA0MyA0MyAyNS4wNjZ6TTIwIDguMjU2TDUgMTAuMzggNS4wMTQgMjMgMjAgMjN6TTIyIDcuOTczTDIyIDIzIDQyLjk5NSAyMyA0Mi45OTUgNXoiLz48L3N2Zz4K</data><downloads_count>0</downloads_count></logo>
|
||||
<finalclass>OS Family</finalclass>
|
||||
<friendlyname>Windows server</friendlyname>
|
||||
</OSFamily>
|
||||
</Set>
|
||||
|
||||
|
||||
@@ -3,70 +3,112 @@
|
||||
<name>10</name>
|
||||
<osfamily_id>8</osfamily_id>
|
||||
<osfamily_id_friendlyname>Windows</osfamily_id_friendlyname>
|
||||
<osfamily_name>Windows</osfamily_name>
|
||||
<finalclass>OS Version</finalclass>
|
||||
<friendlyname>10</friendlyname>
|
||||
</OSVersion>
|
||||
<OSVersion alias="OSVersion" id="2">
|
||||
<name>11</name>
|
||||
<osfamily_id>8</osfamily_id>
|
||||
<osfamily_id_friendlyname>Windows</osfamily_id_friendlyname>
|
||||
<osfamily_name>Windows</osfamily_name>
|
||||
<finalclass>OS Version</finalclass>
|
||||
<friendlyname>11</friendlyname>
|
||||
</OSVersion>
|
||||
<OSVersion alias="OSVersion" id="3">
|
||||
<name>11.5</name>
|
||||
<osfamily_id>2</osfamily_id>
|
||||
<osfamily_id_friendlyname>Debian</osfamily_id_friendlyname>
|
||||
<osfamily_name>Debian</osfamily_name>
|
||||
<finalclass>OS Version</finalclass>
|
||||
<friendlyname>11.5</friendlyname>
|
||||
</OSVersion>
|
||||
<OSVersion alias="OSVersion" id="4">
|
||||
<name>18.04 LTS</name>
|
||||
<osfamily_id>6</osfamily_id>
|
||||
<osfamily_id_friendlyname>Ubuntu server</osfamily_id_friendlyname>
|
||||
<osfamily_name>Ubuntu server</osfamily_name>
|
||||
<finalclass>OS Version</finalclass>
|
||||
<friendlyname>18.04 LTS</friendlyname>
|
||||
</OSVersion>
|
||||
<OSVersion alias="OSVersion" id="5">
|
||||
<name>20.04 LTS</name>
|
||||
<osfamily_id>5</osfamily_id>
|
||||
<osfamily_id_friendlyname>Ubuntu</osfamily_id_friendlyname>
|
||||
<osfamily_name>Ubuntu</osfamily_name>
|
||||
<finalclass>OS Version</finalclass>
|
||||
<friendlyname>20.04 LTS</friendlyname>
|
||||
</OSVersion>
|
||||
<OSVersion alias="OSVersion" id="6">
|
||||
<name>20.04 LTS</name>
|
||||
<osfamily_id>6</osfamily_id>
|
||||
<osfamily_id_friendlyname>Ubuntu server</osfamily_id_friendlyname>
|
||||
<osfamily_name>Ubuntu server</osfamily_name>
|
||||
<finalclass>OS Version</finalclass>
|
||||
<friendlyname>20.04 LTS</friendlyname>
|
||||
</OSVersion>
|
||||
<OSVersion alias="OSVersion" id="7">
|
||||
<name>2019</name>
|
||||
<osfamily_id>9</osfamily_id>
|
||||
<osfamily_id_friendlyname>Windows server</osfamily_id_friendlyname>
|
||||
<osfamily_name>Windows server</osfamily_name>
|
||||
<finalclass>OS Version</finalclass>
|
||||
<friendlyname>2019</friendlyname>
|
||||
</OSVersion>
|
||||
<OSVersion alias="OSVersion" id="8">
|
||||
<name>2022</name>
|
||||
<osfamily_id>9</osfamily_id>
|
||||
<osfamily_id_friendlyname>Windows server</osfamily_id_friendlyname>
|
||||
<osfamily_name>Windows server</osfamily_name>
|
||||
<finalclass>OS Version</finalclass>
|
||||
<friendlyname>2022</friendlyname>
|
||||
</OSVersion>
|
||||
<OSVersion alias="OSVersion" id="9">
|
||||
<name>22.04 LTS</name>
|
||||
<osfamily_id>5</osfamily_id>
|
||||
<osfamily_id_friendlyname>Ubuntu</osfamily_id_friendlyname>
|
||||
<osfamily_name>Ubuntu</osfamily_name>
|
||||
<finalclass>OS Version</finalclass>
|
||||
<friendlyname>22.04 LTS</friendlyname>
|
||||
</OSVersion>
|
||||
<OSVersion alias="OSVersion" id="10">
|
||||
<name>22.04 LTS</name>
|
||||
<osfamily_id>6</osfamily_id>
|
||||
<osfamily_id_friendlyname>Ubuntu server</osfamily_id_friendlyname>
|
||||
<osfamily_name>Ubuntu server</osfamily_name>
|
||||
<finalclass>OS Version</finalclass>
|
||||
<friendlyname>22.04 LTS</friendlyname>
|
||||
</OSVersion>
|
||||
<OSVersion alias="OSVersion" id="11">
|
||||
<name>6.7</name>
|
||||
<osfamily_id>7</osfamily_id>
|
||||
<osfamily_id_friendlyname>vCenter Server</osfamily_id_friendlyname>
|
||||
<osfamily_name>vCenter Server</osfamily_name>
|
||||
<finalclass>OS Version</finalclass>
|
||||
<friendlyname>6.7</friendlyname>
|
||||
</OSVersion>
|
||||
<OSVersion alias="OSVersion" id="12">
|
||||
<name>9</name>
|
||||
<osfamily_id>4</osfamily_id>
|
||||
<osfamily_id_friendlyname>Red Hat</osfamily_id_friendlyname>
|
||||
<osfamily_name>Red Hat</osfamily_name>
|
||||
<finalclass>OS Version</finalclass>
|
||||
<friendlyname>9</friendlyname>
|
||||
</OSVersion>
|
||||
<OSVersion alias="OSVersion" id="13">
|
||||
<name>9.1</name>
|
||||
<osfamily_id>3</osfamily_id>
|
||||
<osfamily_id_friendlyname>Oracle Linux</osfamily_id_friendlyname>
|
||||
<osfamily_name>Oracle Linux</osfamily_name>
|
||||
<finalclass>OS Version</finalclass>
|
||||
<friendlyname>9.1</friendlyname>
|
||||
</OSVersion>
|
||||
<OSVersion alias="OSVersion" id="14">
|
||||
<name>Roling release</name>
|
||||
<osfamily_id>1</osfamily_id>
|
||||
<osfamily_id_friendlyname>Arch</osfamily_id_friendlyname>
|
||||
<osfamily_name>Arch</osfamily_name>
|
||||
<finalclass>OS Version</finalclass>
|
||||
<friendlyname>Roling release</friendlyname>
|
||||
</OSVersion>
|
||||
</Set>
|
||||
@@ -1480,19 +1480,19 @@
|
||||
<cell id="1" _delta="must_exist">
|
||||
<rank>1</rank>
|
||||
<dashlets>
|
||||
<dashlet id="ContainerApplication" xsi:type="DashletBadge" _delta="define">
|
||||
<dashlet id="container_43" xsi:type="DashletBadge" _delta="define">
|
||||
<rank>5</rank>
|
||||
<class>ContainerApplication</class>
|
||||
</dashlet>
|
||||
<dashlet id="ContainerHost" xsi:type="DashletBadge" _delta="define">
|
||||
<dashlet id="container_44" xsi:type="DashletBadge" _delta="define">
|
||||
<rank>6</rank>
|
||||
<class>ContainerHost</class>
|
||||
</dashlet>
|
||||
<dashlet id="ContainerCluster" xsi:type="DashletBadge" _delta="define">
|
||||
<dashlet id="container_45" xsi:type="DashletBadge" _delta="define">
|
||||
<rank>7</rank>
|
||||
<class>ContainerCluster</class>
|
||||
</dashlet>
|
||||
<dashlet id="ContainerImage" xsi:type="DashletBadge" _delta="define">
|
||||
<dashlet id="container_46" xsi:type="DashletBadge" _delta="define">
|
||||
<rank>8</rank>
|
||||
<class>ContainerImage</class>
|
||||
</dashlet>
|
||||
@@ -1507,11 +1507,11 @@
|
||||
<cell id="0">
|
||||
<rank>0</rank>
|
||||
<dashlets>
|
||||
<dashlet id="ContainerType" xsi:type="DashletBadge" _delta="define">
|
||||
<dashlet id="container_21" xsi:type="DashletBadge" _delta="define">
|
||||
<rank>21</rank>
|
||||
<class>ContainerType</class>
|
||||
</dashlet>
|
||||
<dashlet id="ContainerImageType" xsi:type="DashletBadge" _delta="define">
|
||||
<dashlet id="container_22" xsi:type="DashletBadge" _delta="define">
|
||||
<rank>22</rank>
|
||||
<class>ContainerImageType</class>
|
||||
</dashlet>
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Set>
|
||||
<DataFlowType alias="DataFlowType" id="1">
|
||||
<name>HTTP</name>
|
||||
<name>http</name>
|
||||
</DataFlowType>
|
||||
<DataFlowType alias="DataFlowType" id="2">
|
||||
<name>HTTPS</name>
|
||||
<name>https</name>
|
||||
</DataFlowType>
|
||||
<DataFlowType alias="DataFlowType" id="3">
|
||||
<name>FTP</name>
|
||||
<name>ftp</name>
|
||||
</DataFlowType>
|
||||
<DataFlowType alias="DataFlowType" id="4">
|
||||
<name>SFTP</name>
|
||||
<name>sftp</name>
|
||||
</DataFlowType>
|
||||
<DataFlowType alias="DataFlowType" id="5">
|
||||
<name>AS2</name>
|
||||
@@ -18,7 +18,4 @@
|
||||
<DataFlowType alias="DataFlowType" id="6">
|
||||
<name>X.400</name>
|
||||
</DataFlowType>
|
||||
<DataFlowType alias="DataFlowType" id="7">
|
||||
<name>FTPS</name>
|
||||
</DataFlowType>
|
||||
</Set>
|
||||
@@ -2,7 +2,7 @@
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.3">
|
||||
<classes>
|
||||
<class id="DataFlow" _delta="define">
|
||||
<parent>FunctionalCI</parent>
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
<properties>
|
||||
<category>bizmodel,searchable</category>
|
||||
<abstract>false</abstract>
|
||||
@@ -14,10 +14,6 @@
|
||||
<attributes>
|
||||
<attribute id="name"/>
|
||||
</attributes>
|
||||
<complementary_attributes>
|
||||
<attribute id="source_id"/>
|
||||
<attribute id="destination_id"/>
|
||||
</complementary_attributes>
|
||||
</naming>
|
||||
<reconciliation>
|
||||
<attributes>
|
||||
@@ -36,9 +32,23 @@
|
||||
</fields_semantic>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="name" xsi:type="AttributeString">
|
||||
<sql>name</sql>
|
||||
<default_value/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
<field id="org_id" xsi:type="AttributeExternalKey">
|
||||
<sql>org_id</sql>
|
||||
<filter/>
|
||||
<dependencies/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<target_class>Organization</target_class>
|
||||
<on_target_delete>DEL_MANUAL</on_target_delete>
|
||||
<tracking_level>all</tracking_level>
|
||||
</field>
|
||||
<field id="source_id" xsi:type="AttributeExternalKey">
|
||||
<sql>source_id</sql>
|
||||
<filter><![CDATA[SELECT FunctionalCI WHERE finalclass != 'DataFlow']]></filter>
|
||||
<filter/>
|
||||
<dependencies/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<target_class>FunctionalCI</target_class>
|
||||
@@ -64,7 +74,7 @@
|
||||
</field>
|
||||
<field id="destination_id" xsi:type="AttributeExternalKey">
|
||||
<sql>destination_id</sql>
|
||||
<filter><![CDATA[SELECT FunctionalCI WHERE finalclass != 'DataFlow']]></filter>
|
||||
<filter/>
|
||||
<dependencies/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<target_class>FunctionalCI</target_class>
|
||||
@@ -97,6 +107,12 @@
|
||||
<on_target_delete>DEL_MANUAL</on_target_delete>
|
||||
<tracking_level>all</tracking_level>
|
||||
</field>
|
||||
<field id="description" xsi:type="AttributeHTML">
|
||||
<sql>description</sql>
|
||||
<default_value/>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
<tracking_level>all</tracking_level>
|
||||
</field>
|
||||
<field id="status" xsi:type="AttributeEnum">
|
||||
<sql>status</sql>
|
||||
<values>
|
||||
@@ -125,6 +141,27 @@
|
||||
<display_style>list</display_style>
|
||||
<tracking_level>all</tracking_level>
|
||||
</field>
|
||||
<field id="business_criticity" xsi:type="AttributeEnum">
|
||||
<sort_type>rank</sort_type>
|
||||
<values>
|
||||
<value id="high">
|
||||
<code>high</code>
|
||||
<rank>10</rank>
|
||||
</value>
|
||||
<value id="medium">
|
||||
<code>medium</code>
|
||||
<rank>20</rank>
|
||||
</value>
|
||||
<value id="low">
|
||||
<code>low</code>
|
||||
<rank>30</rank>
|
||||
</value>
|
||||
</values>
|
||||
<sql>business_criticity</sql>
|
||||
<default_value>low</default_value>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<display_style>list</display_style>
|
||||
</field>
|
||||
<field id="execution_frequency" xsi:type="AttributeEnum">
|
||||
<sort_type>rank</sort_type>
|
||||
<values>
|
||||
@@ -162,36 +199,24 @@
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<display_style>list</display_style>
|
||||
</field>
|
||||
<field id="contacts_list" xsi:type="AttributeLinkedSetIndirect">
|
||||
<linked_class>lnkContactToDataFlow</linked_class>
|
||||
<ext_key_to_me>dataflow_id</ext_key_to_me>
|
||||
<count_min>0</count_min>
|
||||
<count_max>0</count_max>
|
||||
<ext_key_to_remote>contact_id</ext_key_to_remote>
|
||||
<duplicates/>
|
||||
</field>
|
||||
<field id="documents_list" xsi:type="AttributeLinkedSetIndirect">
|
||||
<linked_class>lnkDocumentToDataFlow</linked_class>
|
||||
<ext_key_to_me>dataflow_id</ext_key_to_me>
|
||||
<count_min>0</count_min>
|
||||
<count_max>0</count_max>
|
||||
<ext_key_to_remote>document_id</ext_key_to_remote>
|
||||
<duplicates/>
|
||||
</field>
|
||||
</fields>
|
||||
<event_listeners>
|
||||
<event_listener id="evtCheckSourceAndDestination">
|
||||
<event>EVENT_DB_CHECK_TO_WRITE</event>
|
||||
<rank>10</rank>
|
||||
<callback>evtCheckSourceAndDestination</callback>
|
||||
</event_listener>
|
||||
</event_listeners>
|
||||
<methods>
|
||||
<method id="evtCheckSourceAndDestination" _delta="define">
|
||||
<comment> /**
|
||||
* Ensure that the source and destination of a data flow are not DataFlow themselves
|
||||
*
|
||||
*/</comment>
|
||||
<static>false</static>
|
||||
<access>public</access>
|
||||
<type>EventListener</type>
|
||||
<code><![CDATA[ public function evtCheckSourceAndDestination(Combodo\iTop\Service\Events\EventData $oEventData)
|
||||
{
|
||||
$oSource = MetaModel::GetObject(FunctionalCI::class, $this->Get('source_id'), false, true);
|
||||
$oDestination = MetaModel::GetObject(FunctionalCI::class, $this->Get('destination_id'), false, true);
|
||||
if ($oSource instanceof DataFlow) {
|
||||
$this->AddCheckIssue(Dict::Format('Class:DataFlow/Error:CheckSource', $oSource->GetName()));
|
||||
}
|
||||
if ($oDestination instanceof DataFlow) {
|
||||
$this->AddCheckIssue(Dict::Format('Class:DataFlow/Error:CheckDestination', $oDestination->GetName()));
|
||||
}
|
||||
} ]]></code>
|
||||
</method>
|
||||
</methods>
|
||||
<methods/>
|
||||
<presentation>
|
||||
<list>
|
||||
<items>
|
||||
@@ -232,7 +257,7 @@
|
||||
<items>
|
||||
<item id="col:col1">
|
||||
<items>
|
||||
<item id="fieldset:ConfigMgmt:baseinfo">
|
||||
<item id="fieldset:DataFlow:baseinfo">
|
||||
<items>
|
||||
<item id="name">
|
||||
<rank>10</rank>
|
||||
@@ -277,24 +302,13 @@
|
||||
</item>
|
||||
<item id="col:col2">
|
||||
<items>
|
||||
<item id="fieldset:ConfigMgmt:dates">
|
||||
<items>
|
||||
<item id="move2production">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
</items>
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="fieldset:ConfigMgmt:otherinfo">
|
||||
<item id="fieldset:DataFlow:otherinfo">
|
||||
<items>
|
||||
<item id="description">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="groups_list">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
<rank>20</rank>
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
</items>
|
||||
<rank>20</rank>
|
||||
@@ -328,46 +342,201 @@
|
||||
</default_search>
|
||||
<summary>
|
||||
<items>
|
||||
<item id="business_criticity">
|
||||
<item id="org_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="source_id">
|
||||
<item id="description">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
<item id="destination_id">
|
||||
<rank>30</rank>
|
||||
</item>
|
||||
<item id="execution_frequency">
|
||||
<rank>40</rank>
|
||||
</item>
|
||||
</items>
|
||||
</summary>
|
||||
</presentation>
|
||||
<relations>
|
||||
<relation id="impacts">
|
||||
<neighbours>
|
||||
<neighbour id="functionalci">
|
||||
<neighbour id="functionalci ">
|
||||
<query_down><![CDATA[SELECT FunctionalCI WHERE :this->destination_impact = 'yes' AND id = :this->destination_id]]></query_down>
|
||||
<query_up><![CDATA[SELECT DataFlow AS f JOIN FunctionalCI AS ci ON f.destination_id = ci.id WHERE f.destination_impact = 'yes' AND ci.id=:this->id]]></query_up>
|
||||
<direction>both</direction>
|
||||
</neighbour>
|
||||
<neighbour id="contact">
|
||||
<neighbour id="contact ">
|
||||
<attribute>contacts_list</attribute>
|
||||
<direction>down</direction>
|
||||
</neighbour>
|
||||
</neighbours>
|
||||
</relation>
|
||||
<relation id="dataflows">
|
||||
<neighbours>
|
||||
<neighbour id="functionalci">
|
||||
<query_down><![CDATA[SELECT FunctionalCI WHERE id = :this->destination_id]]></query_down>
|
||||
<query_up><![CDATA[SELECT DataFlow AS f WHERE f.destination_id = :this->id]]></query_up>
|
||||
<direction>both</direction>
|
||||
</neighbour>
|
||||
</neighbours>
|
||||
</relation>
|
||||
</relations>
|
||||
</class>
|
||||
<class id="lnkDocumentToDataFlow" _delta="define">
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
<properties>
|
||||
<is_link>1</is_link>
|
||||
<category>bizmodel</category>
|
||||
<abstract>false</abstract>
|
||||
<key_type>autoincrement</key_type>
|
||||
<db_table>lnkdocumenttodataflow</db_table>
|
||||
<db_key_field>id</db_key_field>
|
||||
<db_final_class_field/>
|
||||
<naming>
|
||||
<attributes>
|
||||
<attribute id="document_id_friendlyname"/>
|
||||
<attribute id="dataflow_id_friendlyname"/>
|
||||
</attributes>
|
||||
</naming>
|
||||
<style>
|
||||
<icon/>
|
||||
</style>
|
||||
<reconciliation>
|
||||
<attributes>
|
||||
<attribute id="dataflow_id"/>
|
||||
<attribute id="document_id"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
<uniqueness_rules>
|
||||
<rule id="no_duplicate">
|
||||
<attributes>
|
||||
<attribute id="document_id"/>
|
||||
<attribute id="dataflow_id"/>
|
||||
</attributes>
|
||||
<filter><![CDATA[]]></filter>
|
||||
<disabled>false</disabled>
|
||||
<is_blocking>true</is_blocking>
|
||||
</rule>
|
||||
</uniqueness_rules>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="dataflow_id" xsi:type="AttributeExternalKey">
|
||||
<sql>dataflow_id</sql>
|
||||
<target_class>DataFlow</target_class>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<on_target_delete>DEL_AUTO</on_target_delete>
|
||||
</field>
|
||||
<field id="document_id" xsi:type="AttributeExternalKey">
|
||||
<sql>document_id</sql>
|
||||
<target_class>Document</target_class>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<on_target_delete>DEL_AUTO</on_target_delete>
|
||||
</field>
|
||||
</fields>
|
||||
<methods/>
|
||||
<presentation>
|
||||
<details>
|
||||
<items>
|
||||
<item id="document_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="dataflow_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
<search>
|
||||
<items>
|
||||
<item id="dataflow_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="document_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</search>
|
||||
<list>
|
||||
<items>
|
||||
<item id="dataflow_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="document_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</list>
|
||||
</presentation>
|
||||
</class>
|
||||
<class id="lnkContactToDataFlow" _delta="define">
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
<properties>
|
||||
<is_link>1</is_link>
|
||||
<category>bizmodel</category>
|
||||
<abstract>false</abstract>
|
||||
<key_type>autoincrement</key_type>
|
||||
<db_table>lnkcontacttodataflow</db_table>
|
||||
<db_key_field>id</db_key_field>
|
||||
<db_final_class_field/>
|
||||
<naming>
|
||||
<attributes>
|
||||
<attribute id="contact_id_friendlyname"/>
|
||||
<attribute id="dataflow_id_friendlyname"/>
|
||||
</attributes>
|
||||
</naming>
|
||||
<style>
|
||||
<icon/>
|
||||
</style>
|
||||
<reconciliation>
|
||||
<attributes>
|
||||
<attribute id="dataflow_id"/>
|
||||
<attribute id="contact_id"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
<uniqueness_rules>
|
||||
<rule id="no_duplicate">
|
||||
<attributes>
|
||||
<attribute id="contact_id"/>
|
||||
<attribute id="dataflow_id"/>
|
||||
</attributes>
|
||||
<filter><![CDATA[]]></filter>
|
||||
<disabled>false</disabled>
|
||||
<is_blocking>true</is_blocking>
|
||||
</rule>
|
||||
</uniqueness_rules>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="dataflow_id" xsi:type="AttributeExternalKey">
|
||||
<sql>dataflow_id</sql>
|
||||
<target_class>DataFlow</target_class>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<on_target_delete>DEL_AUTO</on_target_delete>
|
||||
</field>
|
||||
<field id="contact_id" xsi:type="AttributeExternalKey">
|
||||
<sql>contact_id</sql>
|
||||
<target_class>Contact</target_class>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<on_target_delete>DEL_AUTO</on_target_delete>
|
||||
</field>
|
||||
</fields>
|
||||
<methods/>
|
||||
<presentation>
|
||||
<details>
|
||||
<items>
|
||||
<item id="contact_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="dataflow_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
<search>
|
||||
<items>
|
||||
<item id="dataflow_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="contact_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</search>
|
||||
<list>
|
||||
<items>
|
||||
<item id="dataflow_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="contact_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</list>
|
||||
</presentation>
|
||||
</class>
|
||||
<class id="DataFlowType" _delta="define">
|
||||
<parent>Typology</parent>
|
||||
<properties>
|
||||
@@ -385,16 +554,6 @@
|
||||
<attribute id="finalclass"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
<uniqueness_rules>
|
||||
<rule id="name">
|
||||
<attributes>
|
||||
<attribute id="name"/>
|
||||
</attributes>
|
||||
<filter><![CDATA[]]></filter>
|
||||
<disabled>false</disabled>
|
||||
<is_blocking>true</is_blocking>
|
||||
</rule>
|
||||
</uniqueness_rules>
|
||||
</properties>
|
||||
<fields/>
|
||||
<methods/>
|
||||
@@ -470,15 +629,6 @@
|
||||
</neighbour>
|
||||
</neighbours>
|
||||
</relation>
|
||||
<relation id="dataflows" _delta="define">
|
||||
<neighbours>
|
||||
<neighbour id="flow">
|
||||
<query_down><![CDATA[SELECT DataFlow WHERE source_id = :this->id]]></query_down>
|
||||
<query_up><![CDATA[SELECT FunctionalCI AS ci JOIN DataFlow AS f ON f.source_id = ci.id WHERE f.id = :this->id]]></query_up>
|
||||
<direction>both</direction>
|
||||
</neighbour>
|
||||
</neighbours>
|
||||
</relation>
|
||||
</relations>
|
||||
</class>
|
||||
<class id="ApplicationSolution" _delta="must_exist">
|
||||
@@ -486,7 +636,7 @@
|
||||
<details>
|
||||
<items>
|
||||
<item id="dataflows" _delta="define">
|
||||
<rank>125</rank>
|
||||
<rank>25</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
@@ -497,7 +647,7 @@
|
||||
<details>
|
||||
<items>
|
||||
<item id="dataflows" _delta="define">
|
||||
<rank>115</rank>
|
||||
<rank>25</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
@@ -508,7 +658,7 @@
|
||||
<details>
|
||||
<items>
|
||||
<item id="dataflows" _delta="define">
|
||||
<rank>165</rank>
|
||||
<rank>25</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
@@ -519,7 +669,7 @@
|
||||
<details>
|
||||
<items>
|
||||
<item id="dataflows" _delta="define">
|
||||
<rank>165</rank>
|
||||
<rank>25</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
@@ -530,40 +680,7 @@
|
||||
<details>
|
||||
<items>
|
||||
<item id="dataflows" _delta="define">
|
||||
<rank>115</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
</presentation>
|
||||
</class>
|
||||
<class id="Server" _delta="must_exist">
|
||||
<presentation>
|
||||
<details>
|
||||
<items>
|
||||
<item id="dataflows" _delta="define">
|
||||
<rank>105</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
</presentation>
|
||||
</class>
|
||||
<class id="VirtualMachine" _delta="if_exists">
|
||||
<presentation>
|
||||
<details>
|
||||
<items>
|
||||
<item id="dataflows" _delta="define">
|
||||
<rank>165</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
</presentation>
|
||||
</class>
|
||||
<class id="ContainerApplication" _delta="if_exists">
|
||||
<presentation>
|
||||
<details>
|
||||
<items>
|
||||
<item id="dataflows" _delta="define">
|
||||
<rank>75</rank>
|
||||
<rank>25</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
@@ -574,7 +691,7 @@
|
||||
<details>
|
||||
<items>
|
||||
<item id="dataflows" _delta="define">
|
||||
<rank>125</rank>
|
||||
<rank>25</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
@@ -585,7 +702,7 @@
|
||||
<details>
|
||||
<items>
|
||||
<item id="dataflows" _delta="define">
|
||||
<rank>165</rank>
|
||||
<rank>25</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
@@ -596,7 +713,7 @@
|
||||
<details>
|
||||
<items>
|
||||
<item id="dataflows" _delta="define">
|
||||
<rank>155</rank>
|
||||
<rank>25</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
@@ -609,7 +726,7 @@
|
||||
<cells>
|
||||
<cell id="3" delta="if_exists">
|
||||
<dashlets>
|
||||
<dashlet id="DataFlow" xsi:type="DashletBadge" _delta="define">
|
||||
<dashlet id="DataFlow_20" xsi:type="DashletBadge" _delta="define">
|
||||
<rank>20</rank>
|
||||
<class>DataFlow</class>
|
||||
</dashlet>
|
||||
@@ -618,21 +735,6 @@
|
||||
</cells>
|
||||
</definition>
|
||||
</menu>
|
||||
<menu id="Typology" xsi:type="DashboardMenuNode" _delta="must_exist">
|
||||
<definition>
|
||||
<cells>
|
||||
<cell id="0">
|
||||
<rank>0</rank>
|
||||
<dashlets>
|
||||
<dashlet id="DataFlowType" xsi:type="DashletBadge" _delta="define">
|
||||
<rank>23</rank>
|
||||
<class>DataFlowType</class>
|
||||
</dashlet>
|
||||
</dashlets>
|
||||
</cell>
|
||||
</cells>
|
||||
</definition>
|
||||
</menu>
|
||||
</menus>
|
||||
<user_rights>
|
||||
<groups>
|
||||
|
||||
@@ -9,25 +9,21 @@
|
||||
|
||||
Dict::Add('EN US', 'English', 'English', [
|
||||
|
||||
'Relation:dataflows/Description' => 'DataFlows between CIs',
|
||||
'Relation:dataflows/DownStream' => 'Outbound flows...',
|
||||
'Relation:dataflows/DownStream+' => 'Outbound flows map from',
|
||||
'Relation:dataflows/UpStream' => 'Inbound flows...',
|
||||
'Relation:dataflows/UpStream+' => 'Inbound flows map to',
|
||||
|
||||
'Class:FunctionalCI/Attribute:dataflows' => 'Data flows',
|
||||
'Class:FunctionalCI/Attribute:dataflows+' => 'Data flows for which this object is the source or the destination',
|
||||
'FunctionalCI:DataFlow:Title' => 'Data flows',
|
||||
'FunctionalCI:DataFlow:Inbound' => 'Inbound flows',
|
||||
'FunctionalCI:DataFlow:Outbound' => 'Outbound flows',
|
||||
|
||||
'DataFlow:baseinfo' => 'General information',
|
||||
'DataFlow:otherinfo' => 'Other information',
|
||||
'DataFlow:moreinfo' => 'Flow specifics',
|
||||
|
||||
'Class:DataFlow' => 'Flow',
|
||||
'Class:DataFlow+' => 'For application flow for example',
|
||||
'Class:DataFlow/ComplementaryName' => '%1$s - %2$s',
|
||||
'Class:DataFlow/Name' => '%1$s',
|
||||
'Class:DataFlow/Attribute:name' => 'Name',
|
||||
'Class:DataFlow/Attribute:name+' => 'Identify the transferred data flow',
|
||||
'Class:DataFlow/Attribute:name_id+' => 'Data that are transferred',
|
||||
'Class:DataFlow/Attribute:source_id' => 'Source',
|
||||
'Class:DataFlow/Attribute:source_id+' => 'Source Ci of the flow',
|
||||
'Class:DataFlow/Attribute:source_impact' => 'Source impacts?',
|
||||
@@ -46,10 +42,22 @@ Dict::Add('EN US', 'English', 'English', [
|
||||
'Class:DataFlow/Attribute:destination_impact/Value:no+' => 'If the flow stops, the destination is not impacted',
|
||||
'Class:DataFlow/Attribute:dataflowtype_id' => 'Flow type',
|
||||
'Class:DataFlow/Attribute:dataflowtype_id+' => 'Typology of Flow.',
|
||||
'Class:DataFlow/Attribute:description' => 'Description',
|
||||
'Class:DataFlow/Attribute:description+' => '',
|
||||
'Class:DataFlow/Attribute:status' => 'Status',
|
||||
'Class:DataFlow/Attribute:status+' => '',
|
||||
'Class:DataFlow/Attribute:status/Value:active' => 'active',
|
||||
'Class:DataFlow/Attribute:status/Value:inactive' => 'inactive',
|
||||
'Class:DataFlow/Attribute:org_id' => 'Organization',
|
||||
'Class:DataFlow/Attribute:org_id+' => '',
|
||||
'Class:DataFlow/Attribute:business_criticity' => 'Business criticality',
|
||||
'Class:DataFlow/Attribute:business_criticity+' => '',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:high' => 'high',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:high+' => '',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:low' => 'low',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:low+' => '',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:medium' => 'medium',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:medium+' => '',
|
||||
'Class:DataFlow/Attribute:execution_frequency' => 'Execution frequency',
|
||||
'Class:DataFlow/Attribute:execution_frequency+' => 'How often the data flow is executed',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:realtime' => 'real-time',
|
||||
@@ -66,13 +74,10 @@ Dict::Add('EN US', 'English', 'English', [
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:monthly+' => '',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:yearly' => 'yearly',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:yearly+' => '',
|
||||
'Class:DataFlow/Attribute:documents_list' => 'Documents',
|
||||
'Class:DataFlow/Attribute:documents_list+' => 'Eg: technical specifications, runbooks, etc.',
|
||||
'Class:DataFlow/Attribute:contacts_list' => 'Contacts',
|
||||
'Class:DataFlow/Attribute:contacts_list+' => 'Eg: flow owner, technical support, etc.',
|
||||
'Class:DataFlow/Error:CheckSource' => 'The source of a data flow cannot be a data flow itself. Choose another source CI than %1$s',
|
||||
'Class:DataFlow/Error:CheckDestination' => 'The destination of a data flow cannot be a data flow itself. Choose another destination CI than %1$s',
|
||||
|
||||
'Class:DataFlowType' => 'Data Flow Type',
|
||||
'Class:DataFlowType+' => 'Typology of Data Flow',
|
||||
|
||||
/*
|
||||
'Class:DataFlow/Attribute:source_id_friendlyname' => 'source_id_friendlyname',
|
||||
|
||||
@@ -9,25 +9,21 @@
|
||||
|
||||
Dict::Add('FR FR', 'French', 'Français', [
|
||||
|
||||
'Relation:dataflows/Description' => 'Flux de données entre CIs',
|
||||
'Relation:dataflows/DownStream' => 'Flux sortants...',
|
||||
'Relation:dataflows/DownStream+' => 'Carte des flux sortants depuis',
|
||||
'Relation:dataflows/UpStream' => 'Flux entrants...',
|
||||
'Relation:dataflows/UpStream+' => 'Carte des flux entrants vers',
|
||||
|
||||
'Class:FunctionalCI/Attribute:dataflows' => 'Flux de données',
|
||||
'Class:FunctionalCI/Attribute:dataflows+' => 'Flux de données dont cet objet est la source ou la destination',
|
||||
'FunctionalCI:DataFlow:Title' => 'Flux de données',
|
||||
'FunctionalCI:DataFlow:Inbound' => 'Flux entrants',
|
||||
'FunctionalCI:DataFlow:Outbound' => 'Flux sortants',
|
||||
|
||||
'DataFlow:baseinfo' => 'Informations générales',
|
||||
'DataFlow:otherinfo' => 'Autres informations',
|
||||
'DataFlow:moreinfo' => 'Spécificités du flux',
|
||||
|
||||
'Class:DataFlow' => 'Flux de Données',
|
||||
'Class:DataFlow+' => 'Modélise les données transférées entre instances d\'application ou plus généralement entre CIs.',
|
||||
'Class:DataFlow/ComplementaryName' => '%1$s - %2$s',
|
||||
'Class:DataFlow+' => 'Modélise les données transférées entre instances d\'application',
|
||||
'Class:DataFlow/Name' => '%1$s',
|
||||
'Class:DataFlow/Attribute:name' => 'Nom',
|
||||
'Class:DataFlow/Attribute:name+' => 'Identifie le flux de données',
|
||||
'Class:DataFlow/Attribute:name_id+' => 'Type de données transferées',
|
||||
'Class:DataFlow/Attribute:source_id' => 'Source',
|
||||
'Class:DataFlow/Attribute:source_id+' => 'Instance d\application à la source du flux de données',
|
||||
'Class:DataFlow/Attribute:source_impact' => 'Source impactante ?',
|
||||
@@ -46,10 +42,22 @@ Dict::Add('FR FR', 'French', 'Français', [
|
||||
'Class:DataFlow/Attribute:destination_impact/Value:no+' => 'Si le flux s\'arrête, le destinataire n\'est pas impacté',
|
||||
'Class:DataFlow/Attribute:dataflowtype_id' => 'Type de flux',
|
||||
'Class:DataFlow/Attribute:dataflowtype_id+' => 'Typologie du flux',
|
||||
'Class:DataFlow/Attribute:description' => 'Description',
|
||||
'Class:DataFlow/Attribute:description+' => '',
|
||||
'Class:DataFlow/Attribute:status' => 'Etat',
|
||||
'Class:DataFlow/Attribute:status+' => '',
|
||||
'Class:DataFlow/Attribute:status/Value:active' => 'actif',
|
||||
'Class:DataFlow/Attribute:status/Value:inactive' => 'inactif',
|
||||
'Class:DataFlow/Attribute:org_id' => 'Organisation',
|
||||
'Class:DataFlow/Attribute:org_id+' => '',
|
||||
'Class:DataFlow/Attribute:business_criticity' => 'Criticité',
|
||||
'Class:DataFlow/Attribute:business_criticity+' => '',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:high' => 'haute',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:high+' => '',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:low' => 'basse',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:low+' => '',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:medium' => 'moyenne',
|
||||
'Class:DataFlow/Attribute:business_criticity/Value:medium+' => '',
|
||||
'Class:DataFlow/Attribute:execution_frequency' => 'Fréquence d\'exécution',
|
||||
'Class:DataFlow/Attribute:execution_frequency+' => 'À quelle fréquence le transfert de données est-il exécuté',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:realtime' => 'temps réel',
|
||||
@@ -66,13 +74,10 @@ Dict::Add('FR FR', 'French', 'Français', [
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:monthly+' => '',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:yearly' => 'annuelle',
|
||||
'Class:DataFlow/Attribute:execution_frequency/Value:yearly+' => '',
|
||||
'Class:DataFlow/Attribute:documents_list' => 'Documents',
|
||||
'Class:DataFlow/Attribute:documents_list+' => 'Eg: technical specifications, runbooks, etc.',
|
||||
'Class:DataFlow/Attribute:contacts_list' => 'Contacts',
|
||||
'Class:DataFlow/Attribute:contacts_list+' => 'Eg: flow owner, technical support, etc.',
|
||||
'Class:DataFlow/Error:CheckSource' => 'La source d\'un flux de données ne peut pas être un flux de données elle-même. Choisissez un autre CI source que %1$s',
|
||||
'Class:DataFlow/Error:CheckDestination' => 'La destination d\'un flux de données ne peut pas être un flux de données elle-même. Choisissez un autre CI destination que %1$s',
|
||||
|
||||
'Class:DataFlowType' => 'Type de flux',
|
||||
'Class:DataFlowType+' => 'Typologie des flux de données',
|
||||
|
||||
/*
|
||||
'Class:DataFlow/Attribute:source_id_friendlyname' => 'source_id_friendlyname',
|
||||
|
||||
@@ -17,7 +17,6 @@ SetupWebPage::AddModule(
|
||||
//
|
||||
'dependencies' => [
|
||||
'itop-config-mgmt/3.2.0',
|
||||
'itop-structure/3.2.0||itop-virtualization/3.2.0||itop-container-mgmt/3.2.0',
|
||||
],
|
||||
'mandatory' => false,
|
||||
'visible' => true,
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Set>
|
||||
<ContractType alias="ContractType" id="78">
|
||||
<name>Hosting</name>
|
||||
</ContractType>
|
||||
<ContractType alias="ContractType" id="79">
|
||||
<name>IT outsourcing</name>
|
||||
</ContractType>
|
||||
<ContractType alias="ContractType" id="77">
|
||||
<name>Maintenance</name>
|
||||
</ContractType>
|
||||
<ContractType alias="ContractType" id="76">
|
||||
<name>Support</name>
|
||||
</ContractType>
|
||||
</Set>
|
||||
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Set>
|
||||
<ContractType alias="ContractType" id="78">
|
||||
<name>Hébergement</name>
|
||||
</ContractType>
|
||||
<ContractType alias="ContractType" id="79">
|
||||
<name>Infogérance</name>
|
||||
</ContractType>
|
||||
<ContractType alias="ContractType" id="77">
|
||||
<name>Maintenance</name>
|
||||
</ContractType>
|
||||
<ContractType alias="ContractType" id="76">
|
||||
<name>Support</name>
|
||||
</ContractType>
|
||||
</Set>
|
||||
@@ -87,14 +87,6 @@ if (!class_exists('ServiceMgmtProviderInstaller')) {
|
||||
*/
|
||||
public static function AfterDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
// Load localized structural data: contract types
|
||||
static::LoadLocalizedData(
|
||||
$oConfiguration,
|
||||
$sPreviousVersion,
|
||||
$sCurrentVersion,
|
||||
'3.3.0',
|
||||
__DIR__."/data/{{language_code}}.data.itop-contracttype.xml"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Set>
|
||||
<ContractType alias="ContractType" id="78">
|
||||
<name>Hosting</name>
|
||||
</ContractType>
|
||||
<ContractType alias="ContractType" id="79">
|
||||
<name>IT outsourcing</name>
|
||||
</ContractType>
|
||||
<ContractType alias="ContractType" id="77">
|
||||
<name>Maintenance</name>
|
||||
</ContractType>
|
||||
<ContractType alias="ContractType" id="76">
|
||||
<name>Support</name>
|
||||
</ContractType>
|
||||
</Set>
|
||||
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Set>
|
||||
<ContractType alias="ContractType" id="78">
|
||||
<name>Hébergement</name>
|
||||
</ContractType>
|
||||
<ContractType alias="ContractType" id="79">
|
||||
<name>Infogérance</name>
|
||||
</ContractType>
|
||||
<ContractType alias="ContractType" id="77">
|
||||
<name>Maintenance</name>
|
||||
</ContractType>
|
||||
<ContractType alias="ContractType" id="76">
|
||||
<name>Support</name>
|
||||
</ContractType>
|
||||
</Set>
|
||||
@@ -84,14 +84,6 @@ if (!class_exists('ServiceMgmtInstaller')) {
|
||||
*/
|
||||
public static function AfterDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
// Load localized structural data: contact types and document types
|
||||
static::LoadLocalizedData(
|
||||
$oConfiguration,
|
||||
$sPreviousVersion,
|
||||
$sCurrentVersion,
|
||||
'3.3.0',
|
||||
__DIR__."/data/{{language_code}}.data.itop-contracttype.xml"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Set>
|
||||
<ContactType alias="ContactType" id="75">
|
||||
<name>Administrator</name>
|
||||
</ContactType>
|
||||
<ContactType alias="ContactType" id="73">
|
||||
<name>Buyer</name>
|
||||
</ContactType>
|
||||
<ContactType alias="ContactType" id="1">
|
||||
<name>Customer manager</name>
|
||||
</ContactType>
|
||||
<ContactType alias="ContactType" id="2">
|
||||
<name>Helpdesk</name>
|
||||
</ContactType>
|
||||
<ContactType alias="ContactType" id="3">
|
||||
<name>Manager</name>
|
||||
</ContactType>
|
||||
<ContactType alias="ContactType" id="74">
|
||||
<name>Sales</name>
|
||||
</ContactType>
|
||||
<ContactType alias="ContactType" id="4">
|
||||
<name>Support Agent</name>
|
||||
</ContactType>
|
||||
<ContactType alias="ContactType" id="5">
|
||||
<name>Support level1</name>
|
||||
</ContactType>
|
||||
<ContactType alias="ContactType" id="6">
|
||||
<name>Team leader</name>
|
||||
</ContactType>
|
||||
</Set>
|
||||
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Set>
|
||||
<DocumentType alias="DocumentType" id="72">
|
||||
<name>Architecture</name>
|
||||
</DocumentType>
|
||||
<DocumentType alias="DocumentType" id="69">
|
||||
<name>Contract</name>
|
||||
</DocumentType>
|
||||
<DocumentType alias="DocumentType" id="71">
|
||||
<name>Procedure</name>
|
||||
</DocumentType>
|
||||
<DocumentType alias="DocumentType" id="70">
|
||||
<name>Process</name>
|
||||
</DocumentType>
|
||||
</Set>
|
||||
@@ -1,30 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Set>
|
||||
<ContactType alias="ContactType" id="75">
|
||||
<name>Administrateur</name>
|
||||
</ContactType>
|
||||
<ContactType alias="ContactType" id="73">
|
||||
<name>Acheteur</name>
|
||||
</ContactType>
|
||||
<ContactType alias="ContactType" id="1">
|
||||
<name>Responsable de la relation client</name>
|
||||
</ContactType>
|
||||
<ContactType alias="ContactType" id="2">
|
||||
<name>Helpdesk</name>
|
||||
</ContactType>
|
||||
<ContactType alias="ContactType" id="3">
|
||||
<name>Manager</name>
|
||||
</ContactType>
|
||||
<ContactType alias="ContactType" id="74">
|
||||
<name>Commercial</name>
|
||||
</ContactType>
|
||||
<ContactType alias="ContactType" id="4">
|
||||
<name>Agent de support</name>
|
||||
</ContactType>
|
||||
<ContactType alias="ContactType" id="5">
|
||||
<name>Support niveau 1</name>
|
||||
</ContactType>
|
||||
<ContactType alias="ContactType" id="6">
|
||||
<name>Chef d'équipe</name>
|
||||
</ContactType>
|
||||
</Set>
|
||||
@@ -1,15 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Set>
|
||||
<DocumentType alias="DocumentType" id="72">
|
||||
<name>Architecture</name>
|
||||
</DocumentType>
|
||||
<DocumentType alias="DocumentType" id="69">
|
||||
<name>Contrat</name>
|
||||
</DocumentType>
|
||||
<DocumentType alias="DocumentType" id="71">
|
||||
<name>Procédure</name>
|
||||
</DocumentType>
|
||||
<DocumentType alias="DocumentType" id="70">
|
||||
<name>Processus</name>
|
||||
</DocumentType>
|
||||
</Set>
|
||||
@@ -99,22 +99,6 @@ if (!class_exists('StructureInstaller')) {
|
||||
*/
|
||||
public static function AfterDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
// Load localized structural data: contact types and document types
|
||||
static::LoadLocalizedData(
|
||||
$oConfiguration,
|
||||
$sPreviousVersion,
|
||||
$sCurrentVersion,
|
||||
'3.3.0',
|
||||
__DIR__."/data/{{language_code}}.data.itop-contacttype.xml"
|
||||
);
|
||||
static::LoadLocalizedData(
|
||||
$oConfiguration,
|
||||
$sPreviousVersion,
|
||||
$sCurrentVersion,
|
||||
'3.3.0',
|
||||
__DIR__."/data/{{language_code}}.data.itop-documenttype.xml"
|
||||
);
|
||||
|
||||
// Default language will be used for actions
|
||||
// Note: There is a issue when upgrading, default language cannot be retrieved from the passed configuration, we have to read it from the disk
|
||||
if (utils::IsNullOrEmptyString($sPreviousVersion)) {
|
||||
|
||||
@@ -60,7 +60,42 @@ class TicketsInstaller extends ModuleInstallerAPI
|
||||
utils::EnrichRaisedException($oTrigger, $e);
|
||||
}
|
||||
}
|
||||
// Load localized structural data: predefined query phrases for notifications
|
||||
static::LoadLocalizedData($oConfiguration, $sPreviousVersion, $sCurrentVersion, '3.0.0', __DIR__."/data/{{language_code}}.data.itop-tickets.xml");
|
||||
// It's not very clear if it make sense to test a particular version,
|
||||
// as the loading mechanism checks object existence using reconc_keys
|
||||
// and do not recreate them, nor update existing.
|
||||
// Without test, new entries added to the data files, would be automatically loaded
|
||||
if (($sPreviousVersion === '') ||
|
||||
(version_compare($sPreviousVersion, $sCurrentVersion, '<')
|
||||
&& version_compare($sPreviousVersion, '3.0.0', '<'))) {
|
||||
$oDataLoader = new XMLDataLoader();
|
||||
|
||||
CMDBObject::SetTrackInfo("Initialization TicketsInstaller");
|
||||
$oMyChange = CMDBObject::GetCurrentChange();
|
||||
|
||||
$sLang = null;
|
||||
// - Try to get app. language from configuration fil (app. upgrade)
|
||||
$sConfigFileName = APPCONF.'production/'.ITOP_CONFIG_FILE;
|
||||
if (file_exists($sConfigFileName)) {
|
||||
$oFileConfig = new Config($sConfigFileName);
|
||||
if (is_object($oFileConfig)) {
|
||||
$sLang = str_replace(' ', '_', strtolower($oFileConfig->GetDefaultLanguage()));
|
||||
}
|
||||
}
|
||||
|
||||
// - I still no language, get the default one
|
||||
if (null === $sLang) {
|
||||
$sLang = str_replace(' ', '_', strtolower($oConfiguration->GetDefaultLanguage()));
|
||||
}
|
||||
|
||||
$sFileName = dirname(__FILE__)."/data/{$sLang}.data.itop-tickets.xml";
|
||||
SetupLog::Info("Searching file: $sFileName");
|
||||
if (!file_exists($sFileName)) {
|
||||
$sFileName = dirname(__FILE__)."/data/en_us.data.itop-tickets.xml";
|
||||
}
|
||||
SetupLog::Info("Loading file: $sFileName");
|
||||
$oDataLoader->StartSession($oMyChange);
|
||||
$oDataLoader->LoadFile($sFileName, false, true);
|
||||
$oDataLoader->EndSession();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,5 +20,4 @@ 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,5 +20,4 @@ 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,5 +20,4 @@ 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,5 +18,4 @@ 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,5 +20,4 @@ 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,5 +20,4 @@ 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,5 +20,4 @@ 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,5 +20,4 @@ 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,5 +20,4 @@ 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,5 +20,4 @@ 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,5 +20,4 @@ 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,5 +20,4 @@ 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,5 +20,4 @@ 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,5 +20,4 @@ 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,5 +20,4 @@ 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,5 +20,4 @@ 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~~',
|
||||
]);
|
||||
|
||||
3
log/index.php
Normal file
3
log/index.php
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
echo 'Access denied';
|
||||
8
log/web.config
Normal file
8
log/web.config
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<system.web>
|
||||
<authorization>
|
||||
<deny users="*" /> <!-- Denies all users -->
|
||||
</authorization>
|
||||
</system.web>
|
||||
</configuration>
|
||||
@@ -43,53 +43,48 @@ class iTopExtensionsMap
|
||||
*
|
||||
* @param string $sFromEnvironment The environment to scan
|
||||
* @param array $aExtraDirs extensions dir to scan
|
||||
* @param array $aExtraDirs extensions dir to scan
|
||||
* @param string|null $sAppRootForTests
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct(string $sFromEnvironment = ITOP_DEFAULT_ENV, array $aExtraDirs = [], ?string $sAppRootForTests = null)
|
||||
public function __construct(string $sFromEnvironment = ITOP_DEFAULT_ENV, array $aExtraDirs = [])
|
||||
{
|
||||
$this->aExtensions = [];
|
||||
$this->aExtensionsByCode = [];
|
||||
$this->aScannedDirs = [];
|
||||
|
||||
$sAppRoot = $sAppRootForTests ?? APPROOT;
|
||||
$this->ScanDisk($sFromEnvironment, $sAppRoot);
|
||||
$this->ScanDisk($sFromEnvironment);
|
||||
|
||||
$this->aExtraDirs = $aExtraDirs;
|
||||
if (is_dir($sAppRoot.'extensions')) {
|
||||
$this->aExtraDirs [] = $sAppRoot.'extensions';
|
||||
if (is_dir(APPROOT.'extensions')) {
|
||||
$this->aExtraDirs [] = APPROOT.'extensions';
|
||||
}
|
||||
if (is_dir($sAppRoot.'data/'.$sFromEnvironment.'-modules')) {
|
||||
$this->aExtraDirs [] = $sAppRoot.'data/'.$sFromEnvironment.'-modules';
|
||||
if (is_dir(APPROOT.'data/'.$sFromEnvironment.'-modules')) {
|
||||
$this->aExtraDirs [] = APPROOT.'data/'.$sFromEnvironment.'-modules';
|
||||
}
|
||||
|
||||
foreach ($aExtraDirs as $sDir) {
|
||||
$this->ReadDir($sDir, iTopExtension::SOURCE_REMOTE);
|
||||
}
|
||||
$this->CheckDependencies($sAppRoot);
|
||||
$this->CheckDependencies();
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the list of available (pseudo)extensions by scanning the disk
|
||||
* where the iTop files are located
|
||||
* @param string $sEnvironment
|
||||
* @param string $sAppRoot
|
||||
* @return void
|
||||
*/
|
||||
protected function ScanDisk($sEnvironment, string $sAppRoot)
|
||||
protected function ScanDisk($sEnvironment)
|
||||
{
|
||||
if (!$this->ReadInstallationWizard($sAppRoot.'/datamodels/2.x')) {
|
||||
if (!$this->ReadInstallationWizard(APPROOT.'/datamodels/2.x')) {
|
||||
$this->bHasXmlInstallationFile = false;
|
||||
//no installation xml found in 2.x: let's read all extensions in 2.x first
|
||||
if (!$this->ReadDir($sAppRoot.'datamodels/2.x', iTopExtension::SOURCE_WIZARD)) {
|
||||
if (!$this->ReadDir(APPROOT.'datamodels/2.x', iTopExtension::SOURCE_WIZARD)) {
|
||||
//nothing found in 2.x : fallback read in 1.x (flat structure)
|
||||
$this->ReadDir($sAppRoot.'datamodels/1.x', iTopExtension::SOURCE_WIZARD);
|
||||
$this->ReadDir(APPROOT.'datamodels/1.x', iTopExtension::SOURCE_WIZARD);
|
||||
}
|
||||
}
|
||||
$this->ReadDir($sAppRoot.'extensions', iTopExtension::SOURCE_MANUAL);
|
||||
$this->ReadDir($sAppRoot.'data/'.$sEnvironment.'-modules', iTopExtension::SOURCE_REMOTE);
|
||||
$this->ReadDir(APPROOT.'extensions', iTopExtension::SOURCE_MANUAL);
|
||||
$this->ReadDir(APPROOT.'data/'.$sEnvironment.'-modules', iTopExtension::SOURCE_REMOTE);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -104,58 +99,24 @@ class iTopExtensionsMap
|
||||
return false;
|
||||
}
|
||||
|
||||
$aModuleConfigs = [];
|
||||
$this->ListModuleFiles(basename($sDir), dirname($sDir), $aModuleConfigs);
|
||||
|
||||
$oXml = new XMLParameters($sDir.'/installation.xml');
|
||||
foreach ($oXml->Get('steps') as $aStepInfo) {
|
||||
if (array_key_exists('options', $aStepInfo)) {
|
||||
$this->ProcessWizardChoices($aStepInfo['options'], $aModuleConfigs);
|
||||
$this->ProcessWizardChoices($aStepInfo['options']);
|
||||
}
|
||||
if (array_key_exists('alternatives', $aStepInfo)) {
|
||||
$this->ProcessWizardChoices($aStepInfo['alternatives'], $aModuleConfigs);
|
||||
$this->ProcessWizardChoices($aStepInfo['alternatives']);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function ListModuleFiles(string $sRelDir, string $sRootDir, array &$aRes): void
|
||||
{
|
||||
$sDirectory = $sRootDir.'/'.$sRelDir;
|
||||
|
||||
if ($hDir = opendir($sDirectory)) {
|
||||
// This is the correct way to loop over the directory. (according to the documentation)
|
||||
while (($sFile = readdir($hDir)) !== false) {
|
||||
$aMatches = [];
|
||||
if (is_dir($sDirectory.'/'.$sFile)) {
|
||||
if (($sFile != '.') && ($sFile != '..') && ($sFile != '.svn') && ($sFile != 'vendor')) {
|
||||
$this->ListModuleFiles($sRelDir.'/'.$sFile, $sRootDir, $aRes);
|
||||
}
|
||||
} elseif (preg_match('/^module\.(.*).php$/i', $sFile, $aMatches)) {
|
||||
try {
|
||||
$aModuleInfo = ModuleFileReader::GetInstance()->ReadModuleFileInformation($sDirectory.'/'.$sFile);
|
||||
$sModuleId = $aModuleInfo[ModuleFileReader::MODULE_INFO_ID];
|
||||
list($sModuleName, $sModuleVersion) = ModuleDiscovery::GetModuleName($sModuleId);
|
||||
$aModuleConfig = $aModuleInfo[ModuleFileReader::MODULE_INFO_CONFIG];
|
||||
$aModuleConfig['module_version'] = $sModuleVersion;
|
||||
$aRes[$sModuleName] = $aModuleConfig;
|
||||
} catch (ModuleFileReaderException $e) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir($hDir);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to process a "choice" array read from the installation.xml file
|
||||
* @param array $aChoices
|
||||
* @param array $aModuleConfigs
|
||||
* @return void
|
||||
*/
|
||||
protected function ProcessWizardChoices($aChoices, $aModuleConfigs)
|
||||
protected function ProcessWizardChoices($aChoices)
|
||||
{
|
||||
foreach ($aChoices as $aChoiceInfo) {
|
||||
if (array_key_exists('extension_code', $aChoiceInfo)) {
|
||||
@@ -167,23 +128,13 @@ class iTopExtensionsMap
|
||||
if (array_key_exists('modules', $aChoiceInfo)) {
|
||||
// Some wizard choices are not associated with any module
|
||||
$oExtension->aModules = $aChoiceInfo['modules'];
|
||||
foreach ($oExtension->aModules as $sModuleName) {
|
||||
$aCurrentModuleConfig = $aModuleConfigs[$sModuleName] ?? null;
|
||||
if (is_null($aCurrentModuleConfig)) {
|
||||
IssueLog::Debug("Installation choice comes with missing module file", null, ["choice" => $oExtension->sCode, 'module' => $sModuleName]);
|
||||
continue;
|
||||
}
|
||||
$oExtension->aModuleVersion[$sModuleName] = $aCurrentModuleConfig['module_version'];
|
||||
unset($aCurrentModuleConfig['module_version']);
|
||||
$oExtension->aModuleInfo[$sModuleName] = $aCurrentModuleConfig;
|
||||
}
|
||||
}
|
||||
if (array_key_exists('sub_options', $aChoiceInfo)) {
|
||||
if (array_key_exists('options', $aChoiceInfo['sub_options'])) {
|
||||
$this->ProcessWizardChoices($aChoiceInfo['sub_options']['options'], $aModuleConfigs);
|
||||
$this->ProcessWizardChoices($aChoiceInfo['sub_options']['options']);
|
||||
}
|
||||
if (array_key_exists('alternatives', $aChoiceInfo['sub_options'])) {
|
||||
$this->ProcessWizardChoices($aChoiceInfo['sub_options']['alternatives'], $aModuleConfigs);
|
||||
$this->ProcessWizardChoices($aChoiceInfo['sub_options']['alternatives']);
|
||||
}
|
||||
}
|
||||
$this->AddExtension($oExtension);
|
||||
@@ -256,7 +207,7 @@ class iTopExtensionsMap
|
||||
$oExtension = $this->GetFromExtensionCode($sCode);
|
||||
if (!is_null($oExtension)) {
|
||||
$aRemovedExtension [] = $oExtension;
|
||||
\IssueLog::Debug(__METHOD__.": remove extension locally", null, ['extension_code' => $oExtension->sCode]);
|
||||
\IssueLog::Info(__METHOD__.": remove extension locally", null, ['extension_code' => $oExtension->sCode]);
|
||||
} else {
|
||||
\IssueLog::Warning(__METHOD__." cannot find extensions", null, ['code' => $sCode]);
|
||||
}
|
||||
@@ -380,112 +331,22 @@ class iTopExtensionsMap
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the list of extensions found in a given directory (not recursively)
|
||||
*
|
||||
* @param string $sSearchDir The directory to scan
|
||||
*
|
||||
* @return string[]|bool
|
||||
*/
|
||||
public function GetExtensionsFromDir(string $sSearchDir): array|bool
|
||||
{
|
||||
if (!is_readable($sSearchDir)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$aExtensions = [];
|
||||
$hDir = opendir($sSearchDir);
|
||||
if ($hDir !== false) {
|
||||
|
||||
// Then scan the other files and subdirectories
|
||||
while (($sDir = readdir($hDir)) !== false) {
|
||||
if (($sDir === '.') || ($sDir === '..') || !is_dir($sSearchDir.$sDir)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// First check if there is an extension.xml file in this directory
|
||||
if (is_readable($sSearchDir.$sDir.'/extension.xml')) {
|
||||
$oXml = new XMLParameters($sSearchDir.$sDir.'/extension.xml');
|
||||
$aExtensions[$oXml->Get('extension_code')] = $oXml->Get('label');
|
||||
}
|
||||
}
|
||||
|
||||
closedir($hDir);
|
||||
}
|
||||
|
||||
return $aExtensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read (recursively) a directory to find if it contains extensions (or modules)
|
||||
*
|
||||
* @param string $sSearchDir The directory to scan
|
||||
*
|
||||
* @return string[] list of modules
|
||||
* @throws \CoreException
|
||||
*/
|
||||
public function GetModulesFromDir(string $sSearchDir): array
|
||||
{
|
||||
if (!is_readable($sSearchDir)) {
|
||||
throw new CoreException("Cannot read directory: $sSearchDir");
|
||||
}
|
||||
|
||||
$aModules = [];
|
||||
$hDir = opendir($sSearchDir);
|
||||
if ($hDir === false) {
|
||||
throw new CoreException("Cannot open directory: $sSearchDir");
|
||||
}
|
||||
|
||||
$aSubDirectories = [];
|
||||
// Then scan the other files and subdirectories
|
||||
while (($sFile = readdir($hDir)) !== false) {
|
||||
if (($sFile !== '.') && ($sFile !== '..')) {
|
||||
$aMatches = [];
|
||||
if (is_dir($sSearchDir.'/'.$sFile)) {
|
||||
// Recurse after parsing all the regular files
|
||||
$aSubDirectories[] = $sSearchDir.'/'.$sFile;
|
||||
} elseif (preg_match('/^module\.(.*).php$/i', $sFile)) {
|
||||
// Found a module
|
||||
try {
|
||||
$aModuleInfo = ModuleFileReader::GetInstance()->ReadModuleFileInformation($sSearchDir.'/'.$sFile);
|
||||
} catch (ModuleFileReaderException $e) {
|
||||
throw new CoreException("Cannot read module file: $sFile", oPrevious: $e);
|
||||
}
|
||||
$sModuleId = $aModuleInfo[ModuleFileReader::MODULE_INFO_ID];
|
||||
[$sModuleName] = ModuleDiscovery::GetModuleName($sModuleId);
|
||||
$aModules[$sModuleName] = $sModuleName;
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir($hDir);
|
||||
foreach ($aSubDirectories as $sDir) {
|
||||
// Recurse inside the subdirectories
|
||||
$aSubModules = $this->GetModulesFromDir($sDir);
|
||||
$aModules = array_merge($aModules, $aSubModules);
|
||||
}
|
||||
|
||||
return $aModules;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if some extension contains a module with missing dependencies...
|
||||
* If so, populate the aMissingDepenencies array
|
||||
*
|
||||
* @param string $sAppRoot
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
protected function CheckDependencies(string $sAppRoot)
|
||||
protected function CheckDependencies()
|
||||
{
|
||||
$aSearchDirs = [];
|
||||
|
||||
if (is_dir($sAppRoot.'/datamodels/2.x')) {
|
||||
$aSearchDirs[] = $sAppRoot.'/datamodels/2.x';
|
||||
} elseif (is_dir($sAppRoot.'/datamodels/1.x')) {
|
||||
$aSearchDirs[] = $sAppRoot.'/datamodels/1.x';
|
||||
if (is_dir(APPROOT.'/datamodels/2.x')) {
|
||||
$aSearchDirs[] = APPROOT.'/datamodels/2.x';
|
||||
} elseif (is_dir(APPROOT.'/datamodels/1.x')) {
|
||||
$aSearchDirs[] = APPROOT.'/datamodels/1.x';
|
||||
}
|
||||
$aSearchDirs = array_merge($aSearchDirs, $this->aScannedDirs);
|
||||
|
||||
try {
|
||||
ModuleDiscovery::GetModulesOrderedByDependencies($aSearchDirs, true);
|
||||
} catch (MissingDependencyException $e) {
|
||||
@@ -576,7 +437,7 @@ class iTopExtensionsMap
|
||||
'default' => true, // by default offer to install all modules
|
||||
'modules' => $oExtension->aModules,
|
||||
'mandatory' => $oExtension->bMandatory,
|
||||
'source_label' => $oExtension->GetExtensionSourceLabel(),
|
||||
'source_label' => $this->GetExtensionSourceLabel($oExtension->sSource),
|
||||
'uninstallable' => $oExtension->CanBeUninstalled(),
|
||||
'missing' => $oExtension->bRemovedFromDisk,
|
||||
'version' => $oExtension->sVersion,
|
||||
@@ -586,6 +447,22 @@ 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)
|
||||
@@ -727,25 +604,6 @@ class iTopExtensionsMap
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return list of extensions (ie installation choices + added - removed)
|
||||
* @param string[] $aAddedExtensions
|
||||
* @param string[] $aRemovedExtensions
|
||||
* @return string[] :
|
||||
*/
|
||||
public function GetSelectedExtensions(Config $oConfig, array $aAddedExtensions, array $aRemovedExtensions): array
|
||||
{
|
||||
$aDbChoices = self::GetChoicesFromDatabase($oConfig);
|
||||
|
||||
foreach ($aDbChoices as $i => $sChoice) {
|
||||
if (in_array($sChoice, $aRemovedExtensions)) {
|
||||
unset($aDbChoices[$i]);
|
||||
}
|
||||
}
|
||||
|
||||
return array_merge($aDbChoices, $aAddedExtensions);
|
||||
}
|
||||
|
||||
public function GetExtraDirs(): array
|
||||
{
|
||||
return $this->aExtraDirs;
|
||||
|
||||
@@ -107,7 +107,7 @@ abstract class AbstractSetupAudit
|
||||
if (ContextTag::Check(ContextTag::TAG_SETUP)) {
|
||||
SetupLog::Info($sMessage, $sChannel, $aContext);
|
||||
} else {
|
||||
IssueLog::Debug($sMessage, $sChannel, $aContext);
|
||||
IssueLog::Info($sMessage, $sChannel, $aContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ use SetupUtils;
|
||||
|
||||
class DryRemovalRuntimeEnvironment extends RunTimeEnvironment
|
||||
{
|
||||
protected array $aExtensionsToRemoveByCode;
|
||||
protected array $aExtensionsByCode;
|
||||
|
||||
/**
|
||||
* 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->aExtensionsToRemoveByCode = $aExtensionCodesToRemove;
|
||||
$this->aExtensionsByCode = $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->aExtensionsToRemoveByCode);
|
||||
$this->DeclareExtensionAsRemoved($this->aExtensionsByCode);
|
||||
}
|
||||
|
||||
private function DeclareExtensionAsRemoved(array $aExtensionCodes): void
|
||||
|
||||
@@ -6,6 +6,7 @@ use ContextTag;
|
||||
use CoreException;
|
||||
use Exception;
|
||||
use IssueLog;
|
||||
use MetaModel;
|
||||
use SetupLog;
|
||||
use utils;
|
||||
|
||||
@@ -33,7 +34,7 @@ class ModelReflectionSerializer
|
||||
|
||||
public function GetModelFromEnvironment(string $sEnv): array
|
||||
{
|
||||
IssueLog::Debug(__METHOD__, null, ['env' => $sEnv]);
|
||||
IssueLog::Info(__METHOD__, null, ['env' => $sEnv]);
|
||||
|
||||
$sPHPExec = trim(utils::GetConfig()->Get('php_path'));
|
||||
$sOutput = "";
|
||||
@@ -42,7 +43,7 @@ class ModelReflectionSerializer
|
||||
$sCommandLine = sprintf("$sPHPExec %s/get_model_reflection.php --env=%s", __DIR__, escapeshellarg($sEnv));
|
||||
exec($sCommandLine, $sOutput, $iRes);
|
||||
if ($iRes != 0) {
|
||||
$this->LogErrorWithProperLogger("Cannot get classes", null, ['env' => $sEnv, 'code' => $iRes, "output" => $sOutput, 'cmd' => $sCommandLine]);
|
||||
$this->LogErrorWithProperLogger("Cannot get classes", null, ['env' => $sEnv, 'code' => $iRes, "output" => $sOutput]);
|
||||
throw new CoreException("Cannot get classes from env ".$sEnv);
|
||||
}
|
||||
|
||||
|
||||
@@ -141,46 +141,4 @@ class iTopExtension
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function __serialize(): array
|
||||
{
|
||||
return [
|
||||
'sCode' => $this->sCode,
|
||||
'sSource' => $this->sSource,
|
||||
'sVersion' => $this->sVersion,
|
||||
'aModules' => $this->aModules,
|
||||
'aModuleVersion' => $this->aModuleVersion,
|
||||
'aModuleInfo' => $this->aModuleInfo,
|
||||
];
|
||||
}
|
||||
|
||||
public function __unserialize(array $aData): void
|
||||
{
|
||||
$this->sCode = $aData['sCode'] ?? '';
|
||||
$this->sSource = $aData['sSource'] ?? '';
|
||||
$this->sVersion = $aData['sVersion'] ?? '';
|
||||
$this->aModules = $aData['aModules'] ?? '';
|
||||
$this->aModuleVersion = $aData['aModuleVersion'] ?? '';
|
||||
$this->aModuleInfo = $aData['aModuleInfo'] ?? '';
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,11 +355,9 @@ class ModuleDiscovery
|
||||
*/
|
||||
protected static function ListModuleFiles($sRelDir, $sRootDir)
|
||||
{
|
||||
static $iDummyClassIndex = 0;
|
||||
$sDirectory = $sRootDir.'/'.$sRelDir;
|
||||
|
||||
if (!is_dir(utils::RealPath($sDirectory, APPROOT))) {
|
||||
throw new Exception('Data directory ('.$sDirectory.') Does not exist or is outside iTop.');
|
||||
}
|
||||
if ($hDir = opendir($sDirectory)) {
|
||||
// This is the correct way to loop over the directory. (according to the documentation)
|
||||
while (($sFile = readdir($hDir)) !== false) {
|
||||
@@ -427,15 +425,14 @@ class ModuleDiscovery
|
||||
continue;
|
||||
}
|
||||
|
||||
IssueLog::Debug("Module considered as removed", null, ['extension_code' => $oExtension->sCode, 'module_name' => $sModuleName, 'module_version' => $sModuleVersion, ModuleFileReader::MODULE_FILE_PATH => $sCurrentModuleFilePath]);
|
||||
SetupLog::Info("Module considered as removed", null, ['extension_code' => $oExtension->sCode, 'module_name' => $sModuleName, 'module_version' => $sModuleVersion, ModuleFileReader::MODULE_FILE_PATH => $sCurrentModuleFilePath]);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (count($aNonMatchingPaths) > 0) {
|
||||
//add log for support
|
||||
IssueLog::Debug("Module kept as it came from non removed extensions", null, ['module_name' => $sModuleName, 'module_version' => $sModuleVersion, ModuleFileReader::MODULE_FILE_PATH => $sModuleFilePath, 'non_matching_paths' => $aNonMatchingPaths]);
|
||||
SetupLog::Debug("Module kept as it came from non removed extensions", null, ['module_name' => $sModuleName, 'module_version' => $sModuleVersion, ModuleFileReader::MODULE_FILE_PATH => $sModuleFilePath, 'non_matching_paths' => $aNonMatchingPaths]);
|
||||
}
|
||||
IssueLog::Debug(__METHOD__.' Module loaded', null, ['name' => $sModuleName, 'version' => $sModuleVersion]);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -260,6 +260,11 @@ class ModuleFileReader
|
||||
}
|
||||
|
||||
$aModuleConfig = $this->oPhpExpressionEvaluator->EvaluateExpression($oModuleConfigInfo->value);
|
||||
if (isset($aModuleConfig['settings'])) {
|
||||
$oPhpExpressionEvaluator = new PhpExpressionEvaluator();
|
||||
$aArrayWithComments = $oPhpExpressionEvaluator->GetArrayWithComments($oModuleConfigInfo->value);
|
||||
$aModuleConfig['settings'] = array_replace_recursive($aArrayWithComments['settings'], $aModuleConfig['settings']);
|
||||
}
|
||||
|
||||
if (! is_array($aModuleConfig)) {
|
||||
throw new ModuleFileReaderException("3rd parameter to SetupWebPage::AddModule not an array: ".get_class($oModuleConfigInfo->value), 0, null, $sModuleFilePath);
|
||||
|
||||
@@ -308,102 +308,4 @@ abstract class ModuleInstallerAPI
|
||||
|
||||
CMDBSource::CacheReset($sOrigTable);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Config $oConfiguration
|
||||
* @param string $sPreviousVersion The previous version of the module (empty string in case of first install)
|
||||
* @param string $sCurrentVersion The current version of the module
|
||||
* @param string $sFirstLoadingVersion The first module version for which the data loading should be performed (e.g. '3.0.0')
|
||||
* @param string $sFilePattern The pattern of the file to load, with {{language_code}} as placeholder for the language code (e.g. 'data.sample.{{language_code}}.xml')
|
||||
*
|
||||
* @return void
|
||||
* @throws \ConfigException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
*/
|
||||
public static function LoadLocalizedData(Config $oConfiguration, ?string $sPreviousVersion, ?string $sCurrentVersion, string $sFirstLoadingVersion, string $sFilePattern): void
|
||||
{
|
||||
self::AssertLoadLocalizedDataParametersAreValid($sPreviousVersion, $sCurrentVersion, $sFirstLoadingVersion, $sFilePattern);
|
||||
|
||||
// The loading is done only if
|
||||
// - it's a first install of the module
|
||||
// - or it's an upgrade of that module (PreviousVersion is less than the CurrentVersion), which means that we are really upgrading (and not reinstalling the same version or downgrading), and
|
||||
// - either the FirstLoadingVersion is between the PreviousVersion and the CurrentVersion
|
||||
// - or the FirstLoadingVersion is empty, forcing the loading on all upgrades,
|
||||
if (($sPreviousVersion === '') ||
|
||||
(version_compare($sPreviousVersion, $sCurrentVersion, '<') &&
|
||||
(($sFirstLoadingVersion === '') || version_compare($sPreviousVersion, $sFirstLoadingVersion, '<')))) {
|
||||
|
||||
$sDefaultLanguage = $oConfiguration->GetDefaultLanguage();
|
||||
$sFileName = self::GetLocalizedFileName($sDefaultLanguage, $sFilePattern);
|
||||
self::XMLFileLoad($sFileName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \CoreUnexpectedValue
|
||||
*/
|
||||
private static function AssertLoadLocalizedDataParametersAreValid(?string $sPreviousVersion, ?string $sCurrentVersion, string $sFirstLoadingVersion, string $sFilePattern): void
|
||||
{
|
||||
if (($sPreviousVersion !== '') && !self::IsValidLocalizedDataVersion($sPreviousVersion)) {
|
||||
throw new CoreUnexpectedValue("LoadLocalizedData expects sPreviousVersion to be empty or match x.y[.z][-name], got '{$sPreviousVersion}'");
|
||||
}
|
||||
if (!self::IsValidLocalizedDataVersion($sCurrentVersion)) {
|
||||
throw new CoreUnexpectedValue("LoadLocalizedData expects sCurrentVersion to match x.y[.z][-name], got '{$sCurrentVersion}'");
|
||||
}
|
||||
if (($sFirstLoadingVersion !== '') && !self::IsValidLocalizedDataVersion($sFirstLoadingVersion)) {
|
||||
throw new CoreUnexpectedValue("LoadLocalizedData expects sFirstLoadingVersion to match x.y[.z][-name], got '{$sFirstLoadingVersion}'");
|
||||
}
|
||||
if (substr_count($sFilePattern, '{{language_code}}') !== 1) {
|
||||
throw new CoreUnexpectedValue("LoadLocalizedData expects $sFilePattern to contain the exact placeholder '{{language_code}}' exactly once");
|
||||
}
|
||||
}
|
||||
|
||||
private static function IsValidLocalizedDataVersion(string $sVersion): bool
|
||||
{
|
||||
return (preg_match('/^\d+\.\d+(?:\.\d+)?(?:-[A-Za-z0-9]+)?$/', $sVersion) === 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|string $sFileName
|
||||
*
|
||||
* @return void
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function XMLFileLoad(string $sFileName): void
|
||||
{
|
||||
if (!file_exists($sFileName)) {
|
||||
throw new Exception("File $sFileName not found");
|
||||
}
|
||||
$oDataLoader = new XMLDataLoader();
|
||||
CMDBObject::SetTrackInfo("Loading XML data from $sFileName");
|
||||
$oMyChange = CMDBObject::GetCurrentChange();
|
||||
SetupLog::Info("Loading objects in DB from file: $sFileName");
|
||||
$oDataLoader->StartSession($oMyChange);
|
||||
$oDataLoader->LoadFile($sFileName, false, true);
|
||||
$oDataLoader->EndSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sLanguage The language code to use for localization (e.g. 'EN US')
|
||||
* @param string $sFilePattern The full path+name of the file to localize, with {{language_code}} as placeholder for the language code (e.g. 'data.sample.{{language_code}}.xml')
|
||||
*
|
||||
* @return string The localized file name if found, or an empty string if not found
|
||||
*/
|
||||
public static function GetLocalizedFileName($sLanguage, string $sFilePattern): string
|
||||
{
|
||||
$sLang = str_replace(' ', '_', strtolower($sLanguage));
|
||||
$sFileName = str_replace('{{language_code}}', $sLang, $sFilePattern);
|
||||
if (!file_exists($sFileName)) {
|
||||
SetupLog::Debug("No data file found matching the pattern $sFilePattern and language_code $sLang. Trying with 'en_us' as fallback.");
|
||||
$sLang = 'en_us';
|
||||
$sFileName = str_replace('{{language_code}}', $sLang, $sFilePattern);
|
||||
}
|
||||
if (file_exists($sFileName)) {
|
||||
return $sFileName;
|
||||
} else {
|
||||
SetupLog::Warning("No data file matching the pattern $sFilePattern and language_code $sLang was found.");
|
||||
return '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,7 +99,6 @@ class RunTimeEnvironment
|
||||
$this->sBuildEnv = $sEnvironment.'-build';
|
||||
}
|
||||
$this->oExtensionsMap = null;
|
||||
SetupLog::Enable(APPROOT.'log/setup.log');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -477,7 +476,7 @@ class RunTimeEnvironment
|
||||
}
|
||||
|
||||
$aModulesToLoad = $this->GetModulesToLoad($this->sFinalEnv, $aDirsToCompile);
|
||||
$aAvailableModules = $this->AnalyzeInstallation($oSourceConfig, $aDirsToCompile, true, $aModulesToLoad);
|
||||
$aAvailableModules = $this->AnalyzeInstallation($oSourceConfig, $aDirsToCompile, false, $aModulesToLoad);
|
||||
|
||||
// Do load the required modules
|
||||
//
|
||||
@@ -1166,7 +1165,6 @@ class RunTimeEnvironment
|
||||
'ExceptionClass' => get_class($e),
|
||||
'ExceptionMessage' => $e->getMessage(),
|
||||
];
|
||||
IssueLog::Exception($sErrorMessage, $e, null, $aExceptionContextData);
|
||||
throw new CoreException($sErrorMessage, $aExceptionContextData, '', $e);
|
||||
}
|
||||
}
|
||||
@@ -1340,13 +1338,13 @@ class RunTimeEnvironment
|
||||
$iCount = $oSetupAudit->GetDataToCleanupCount();
|
||||
|
||||
if ($iCount > 0) {
|
||||
throw new Exception("$iCount elements require data adjustments or cleanup in the backoffice", DataAuditSequencer::DATA_AUDIT_FAILED);
|
||||
throw new Exception("$iCount elements require data adjustments or cleanup in the backoffice prior to upgrading iTop", DataAuditSequencer::DATA_AUDIT_FAILED);
|
||||
}
|
||||
}
|
||||
|
||||
public function CopySetupFiles(): void
|
||||
{
|
||||
$sSourceEnv = $this->sFinalEnv;
|
||||
$sSourceEnv = ITOP_DEFAULT_ENV;
|
||||
$sDestinationEnv = $this->sBuildEnv;
|
||||
|
||||
if ($sDestinationEnv != $sSourceEnv) {
|
||||
@@ -1449,18 +1447,12 @@ class RunTimeEnvironment
|
||||
}
|
||||
|
||||
if (!is_dir($sSourcePath)) {
|
||||
$sErrorMessage = "Failed to find the source directory '$sSourcePath', please check the rights of the web server";
|
||||
$e = new CoreException($sErrorMessage);
|
||||
IssueLog::Exception($sErrorMessage, $e);
|
||||
throw $e;
|
||||
throw new Exception("Failed to find the source directory '$sSourcePath', please check the rights of the web server");
|
||||
}
|
||||
|
||||
if (!is_dir($sBuildPath)) {
|
||||
if (!mkdir($sBuildPath)) {
|
||||
$sErrorMessage = "Failed to create directory '$sBuildPath', please check the rights of the web server";
|
||||
$e = new CoreException($sErrorMessage);
|
||||
IssueLog::Exception($sErrorMessage, $e);
|
||||
throw $e;
|
||||
throw new Exception("Failed to create directory '$sBuildPath', please check the rights of the web server");
|
||||
} else {
|
||||
// adjust the rights if and only if the directory was just created
|
||||
// owner:rwx user/group:rx
|
||||
@@ -1475,17 +1467,6 @@ class RunTimeEnvironment
|
||||
// Removed modules are stored as static for FindModules()
|
||||
$oExtensionsMap->DeclareExtensionAsRemoved($aRemovedExtensionCodes);
|
||||
|
||||
// Check that all the extensions have a code
|
||||
foreach ($oExtensionsMap->GetAllExtensions() as $oExtension) {
|
||||
if (empty($oExtension->sCode)) {
|
||||
$sExtensionLabel = !empty($oExtension->sLabel) ? $oExtension->sLabel : $oExtension->sSourceDir;
|
||||
$sErrorMessage = sprintf('Extension "%s" cannot be installed: Missing extension code', $sExtensionLabel);
|
||||
$e = new CoreException($sErrorMessage);
|
||||
IssueLog::Exception($sErrorMessage, $e);
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
$oFactory = new ModelFactory($aDirsToScan);
|
||||
|
||||
$oDictModule = new MFDictModule('dictionaries', 'iTop Dictionaries', APPROOT.'dictionaries');
|
||||
@@ -1585,7 +1566,7 @@ class RunTimeEnvironment
|
||||
|
||||
public function ExitMaintenanceMode(): void
|
||||
{
|
||||
if (SetupUtils::IsInMaintenanceMode()) {
|
||||
if (SetupUtils::IsInMaintenanceMode()){
|
||||
SetupUtils::ExitMaintenanceMode();
|
||||
}
|
||||
}
|
||||
@@ -1650,24 +1631,10 @@ class RunTimeEnvironment
|
||||
$oSourceConfig = new Config(utils::GetConfigFilePath($sSourceEnv));
|
||||
|
||||
$aChoices = $this->GetExtensionMap()->GetChoicesFromDatabase($oSourceConfig);
|
||||
return $this->GetModulesToLoadFromChoices($oSourceConfig, $aChoices, $aSearchDirs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return modules based on installation choices+package
|
||||
* @param \Config $oConfig
|
||||
* @param array|bool $aChoices
|
||||
* @param array $aSearchDirs
|
||||
* @return array|null
|
||||
* @throws \ModuleInstallationException
|
||||
*/
|
||||
public function GetModulesToLoadFromChoices(Config $oConfig, array|bool $aChoices, array $aSearchDirs): ?array
|
||||
{
|
||||
if (false === $aChoices) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$sSourceDir = $oConfig->Get('source_dir');
|
||||
$sSourceDir = $oSourceConfig->Get('source_dir');
|
||||
|
||||
$sInstallFilePath = APPROOT.$sSourceDir.'/installation.xml';
|
||||
if (! is_file($sInstallFilePath)) {
|
||||
|
||||
@@ -120,19 +120,23 @@ class ApplicationInstallSequencer extends StepSequencer
|
||||
$aAdminParams = $this->oParams->Get('admin_account');
|
||||
$aSelectedModules = $this->oParams->Get('selected_modules', []);
|
||||
$sMode = $this->oParams->Get('mode');
|
||||
|
||||
$this->oRunTimeEnvironment->AfterDBCreate($this->GetConfig(), $sMode, $aSelectedModules, $aAdminParams);
|
||||
return $this->ComputeNextStep($sStep);
|
||||
|
||||
case 'load-data':
|
||||
$aSelectedModules = $this->oParams->Get('selected_modules', []);
|
||||
$bSampleData = ($this->oParams->Get('sample_data', 0) == 1);
|
||||
|
||||
$this->oRunTimeEnvironment->DoLoadData($this->GetConfig(), $bSampleData, $aSelectedModules);
|
||||
|
||||
return $this->ComputeNextStep($sStep);
|
||||
|
||||
case 'create-config':
|
||||
$sDataModelVersion = $this->oParams->Get('datamodel_version', '0.0.0');
|
||||
$aSelectedModuleCodes = $this->oParams->Get('selected_modules', []);
|
||||
$aSelectedExtensionCodes = $this->oParams->Get('selected_extensions', []);
|
||||
|
||||
$this->oRunTimeEnvironment->DoCreateConfig(
|
||||
$this->GetConfig(),
|
||||
$sDataModelVersion,
|
||||
@@ -210,4 +214,32 @@ class ApplicationInstallSequencer extends StepSequencer
|
||||
$aStepNames = array_merge($aStepNames, $aOthers);
|
||||
return $aStepNames;
|
||||
}
|
||||
|
||||
public function GetStepAfterWithPercent($sCurrentStep): array
|
||||
{
|
||||
$aAllStepNames = $this->GetStepNames();
|
||||
$iKey = array_search($sCurrentStep, $aAllStepNames);
|
||||
$iNextStepIndex = $iKey + 1;
|
||||
$sNextStep = $aAllStepNames[$iNextStepIndex] ?? '';
|
||||
return [$sNextStep, $this->ComputePercent($aAllStepNames, $iNextStepIndex)];
|
||||
}
|
||||
|
||||
public function ComputePercent(array $aAllStepNames, $iKey): int
|
||||
{
|
||||
$iCount = count($aAllStepNames);
|
||||
if ($iKey >= $iCount) {
|
||||
return 100;
|
||||
}
|
||||
|
||||
$iRes = 100 * $iKey / $iCount;
|
||||
return (int) $iRes;
|
||||
}
|
||||
|
||||
private function ComputeNextStep(string $sCurrentStep, string $sMessage = ''): array
|
||||
{
|
||||
[$sNextStep, $iPercent] = $this->GetStepAfterWithPercent($sCurrentStep);
|
||||
$sLabel = self::LABELS[$sNextStep] ?? '';
|
||||
$sCurrentStepSuccessMessage = self::SUCCESS_LABELS[$sCurrentStep] ?? '';
|
||||
return $this->GetNextStep($sNextStep, $sLabel, $iPercent, $sMessage, $sCurrentStepSuccessMessage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,19 +28,6 @@ class DataAuditSequencer extends StepSequencer
|
||||
{
|
||||
public const DATA_AUDIT_FAILED = 100;
|
||||
|
||||
protected const LABELS = [
|
||||
'copy' => 'Copying data model files',
|
||||
'compile' => 'Compiling the data model',
|
||||
'setup-audit' => 'Checking data consistency with the new data model',
|
||||
'complete' => 'Check Completed',
|
||||
];
|
||||
protected const SUCCESS_LABELS = [
|
||||
'copy' => 'Data model files copied',
|
||||
'compile' => 'Data model compilation completed',
|
||||
'setup-audit' => 'Data consistency check completed',
|
||||
'complete' => 'All checks completed',
|
||||
];
|
||||
|
||||
/**
|
||||
* @inherit
|
||||
*/
|
||||
@@ -56,11 +43,11 @@ class DataAuditSequencer extends StepSequencer
|
||||
SetupLog::Info("##### STEP {$sStep} start");
|
||||
switch ($sStep) {
|
||||
case '':
|
||||
return $this->ComputeNextStep($sStep);
|
||||
return $this->GetNextStep('copy', 'Copying data model files', 5);
|
||||
|
||||
case 'copy':
|
||||
$this->oRunTimeEnvironment->CopySetupFiles();
|
||||
return $this->ComputeNextStep($sStep);
|
||||
return $this->GetNextStep('compile', 'Compiling the data model', 20, 'Copying...', 'Data model files copied');
|
||||
|
||||
case 'compile':
|
||||
$aSelectedModules = $this->oParams->Get('selected_modules', []);
|
||||
@@ -68,7 +55,7 @@ class DataAuditSequencer extends StepSequencer
|
||||
$sExtensionDir = $this->oParams->Get('extensions_dir', 'extensions');
|
||||
$aRemovedExtensionCodes = $this->oParams->Get('removed_extensions', []);
|
||||
$bUseSymbolicLinks = $this->oParams->Get('use_symbolic_links', null) === 'on';
|
||||
MetaModel::ResetAllCaches($this->oRunTimeEnvironment->GetBuildEnv());
|
||||
$sMessage = $bUseSymbolicLinks ? 'Using symbolic links instead of copying data model files (for developers only!)' : '';
|
||||
$this->oRunTimeEnvironment->DoCompile(
|
||||
$aRemovedExtensionCodes,
|
||||
$aSelectedModules,
|
||||
@@ -76,18 +63,23 @@ class DataAuditSequencer extends StepSequencer
|
||||
$sExtensionDir,
|
||||
$bUseSymbolicLinks
|
||||
);
|
||||
return $this->ComputeNextStep($sStep);
|
||||
|
||||
if ($this->IsDataAuditRequired()) {
|
||||
return $this->GetNextStep('setup-audit', 'Checking data consistency with the new data model', 70, $sMessage, 'Data model compilation completed');
|
||||
}
|
||||
return $this->GetNextStep('complete', 'Check Completed', 100, '', 'Data model compilation completed');
|
||||
|
||||
case 'setup-audit':
|
||||
$this->oRunTimeEnvironment->DataToCleanupAudit();
|
||||
return $this->ComputeNextStep($sStep);
|
||||
if ($this->IsDataAuditRequired()) {
|
||||
$this->oRunTimeEnvironment->DataToCleanupAudit();
|
||||
}
|
||||
return $this->GetNextStep('complete', 'Check Completed', 100, '', 'Data consistency check completed');
|
||||
|
||||
case 'complete':
|
||||
return $this->GetNextStep('', 'Completed', 100);
|
||||
return $this->GetNextStep('', 'Completed', 100, '', 'All checks completed');
|
||||
|
||||
default:
|
||||
return $this->GetNextStep('', "Unknown setup step '$sStep'.", 100, '', '', self::ERROR);
|
||||
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
SetupLog::Exception("$sStep failed", $e);
|
||||
@@ -120,19 +112,4 @@ class DataAuditSequencer extends StepSequencer
|
||||
$sFinalEnvDir = APPROOT.'env-'.$this->oRunTimeEnvironment->GetFinalEnv();
|
||||
return is_dir($sFinalEnvDir);
|
||||
}
|
||||
|
||||
public function GetStepNames(): array
|
||||
{
|
||||
$aStepNames = [''];
|
||||
if (array_key_exists('copy', $this->oParams->Get('optional_steps', []))) {
|
||||
$aStepNames[] = 'copy';
|
||||
}
|
||||
$aStepNames[] = 'compile';
|
||||
if ($this->IsDataAuditRequired()) {
|
||||
$aStepNames[] = 'setup-audit';
|
||||
}
|
||||
$aStepNames[] = 'complete';
|
||||
|
||||
return $aStepNames;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,36 +193,6 @@ abstract class StepSequencer
|
||||
return $oConfig;
|
||||
}
|
||||
|
||||
public function GetStepAfterWithPercent($sCurrentStep): array
|
||||
{
|
||||
$aAllStepNames = $this->GetStepNames();
|
||||
$iKey = array_search($sCurrentStep, $aAllStepNames);
|
||||
$iNextStepIndex = $iKey + 1;
|
||||
$sNextStep = $aAllStepNames[$iNextStepIndex] ?? '';
|
||||
return [$sNextStep, $this->ComputePercent($aAllStepNames, $iNextStepIndex)];
|
||||
}
|
||||
|
||||
public function ComputePercent(array $aAllStepNames, $iKey): int
|
||||
{
|
||||
$iCount = count($aAllStepNames);
|
||||
if ($iKey >= $iCount) {
|
||||
return 100;
|
||||
}
|
||||
|
||||
$iRes = 100 * $iKey / $iCount;
|
||||
return (int) $iRes;
|
||||
}
|
||||
|
||||
protected function ComputeNextStep(string $sCurrentStep, string $sMessage = ''): array
|
||||
{
|
||||
[$sNextStep, $iPercent] = $this->GetStepAfterWithPercent($sCurrentStep);
|
||||
$sLabel = static::LABELS[$sNextStep] ?? '';
|
||||
$sCurrentStepSuccessMessage = static::SUCCESS_LABELS[$sCurrentStep] ?? '';
|
||||
return $this->GetNextStep($sNextStep, $sLabel, $iPercent, $sMessage, $sCurrentStepSuccessMessage);
|
||||
}
|
||||
|
||||
abstract public function GetStepNames(): array;
|
||||
|
||||
/**
|
||||
* Executes the next step of the installation and reports about the progress
|
||||
* and the next step to perform
|
||||
|
||||
@@ -1576,13 +1576,11 @@ JS
|
||||
* @return array
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function AnalyzeInstallation($oWizard, $bAbortOnMissingDependency = false, $aModulesToLoad = null, ?Config $oConfig = null)
|
||||
public static function AnalyzeInstallation($oWizard, $bAbortOnMissingDependency = false, $aModulesToLoad = null)
|
||||
{
|
||||
require_once(APPROOT.'/setup/moduleinstaller.class.inc.php');
|
||||
|
||||
if (is_null($oConfig)) {
|
||||
$oConfig = self::GetConfig($oWizard);
|
||||
}
|
||||
$oConfig = self::GetConfig($oWizard);
|
||||
|
||||
$aDirsToScan = [$oWizard->GetParameter('source_dir', '')];
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<log-parameters>1</log-parameters>
|
||||
<migrate-before>1</migrate-before>
|
||||
<migrate-after>1</migrate-after>
|
||||
<copy>1</copy>
|
||||
</optional_steps>
|
||||
<source_dir>datamodels/2.x/</source_dir>
|
||||
<datamodel_version>3.3.0</datamodel_version>
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<log-parameters>1</log-parameters>
|
||||
<migrate-before>1</migrate-before>
|
||||
<migrate-after>1</migrate-after>
|
||||
<copy>1</copy>
|
||||
</optional_steps>
|
||||
<source_dir>datamodels/2.x/</source_dir>
|
||||
<datamodel_version>3.3.0</datamodel_version>
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<log-parameters>1</log-parameters>
|
||||
<migrate-before>1</migrate-before>
|
||||
<migrate-after>1</migrate-after>
|
||||
<copy>1</copy>
|
||||
</optional_steps>
|
||||
<source_dir>datamodels/2.x/</source_dir>
|
||||
<datamodel_version>3.3.0</datamodel_version>
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
<log-parameters>1</log-parameters>
|
||||
<migrate-before>1</migrate-before>
|
||||
<migrate-after>1</migrate-after>
|
||||
<copy>1</copy>
|
||||
</optional_steps>
|
||||
<source_dir>datamodels/2.x/</source_dir>
|
||||
<datamodel_version>3.3.0</datamodel_version>
|
||||
|
||||
@@ -38,7 +38,7 @@ require_once(APPROOT.'setup/extensionsmap.class.inc.php');
|
||||
|
||||
class WizardController
|
||||
{
|
||||
protected $aWizardSteps;
|
||||
protected $aSteps;
|
||||
protected $sInitialStepClass;
|
||||
protected $sInitialState;
|
||||
protected $aParameters;
|
||||
@@ -53,7 +53,7 @@ class WizardController
|
||||
$this->sInitialStepClass = $sInitialStepClass;
|
||||
$this->sInitialState = $sInitialState;
|
||||
$this->aParameters = [];
|
||||
$this->aWizardSteps = [];
|
||||
$this->aSteps = [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -62,7 +62,7 @@ class WizardController
|
||||
*/
|
||||
protected function PushStep($aStepInfo)
|
||||
{
|
||||
array_push($this->aWizardSteps, $aStepInfo);
|
||||
array_push($this->aSteps, $aStepInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -71,7 +71,7 @@ class WizardController
|
||||
*/
|
||||
protected function PopStep()
|
||||
{
|
||||
return array_pop($this->aWizardSteps);
|
||||
return array_pop($this->aSteps);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -235,9 +235,9 @@ HTML;
|
||||
$oPage->add('<input type="hidden" name="_params['.$sCode.']" value="'.utils::EscapeHtml($value).'"/>');
|
||||
}
|
||||
|
||||
$oPage->add('<input type="hidden" name="_steps" value="'.utils::EscapeHtml(json_encode($this->aWizardSteps)).'"/>');
|
||||
$oPage->add('<input type="hidden" name="_steps" value="'.utils::EscapeHtml(json_encode($this->aSteps)).'"/>');
|
||||
$oPage->add('<table style="width:100%;" class="ibo-setup--wizard--buttons-container"><tr>');
|
||||
if ((count($this->aWizardSteps) > 0) && ($oStep->CanMoveBackward())) {
|
||||
if ((count($this->aSteps) > 0) && ($oStep->CanMoveBackward())) {
|
||||
$oPage->add('<td style="text-align: left"><button id="btn_back" class="ibo-button ibo-is-alternative ibo-is-neutral" type="submit" name="operation" value="back"><span class="ibo-button--label">Back</span></button></td>');
|
||||
}
|
||||
if ($oStep->CanMoveForward()) {
|
||||
@@ -296,7 +296,7 @@ on the page's parameters
|
||||
|
||||
$sOperation = utils::ReadParam('operation');
|
||||
$this->aParameters = utils::ReadParam('_params', [], false, 'raw_data');
|
||||
$this->SetWizardSteps(json_decode(utils::ReadParam('_steps', '[]', false, 'raw_data'), true));
|
||||
$this->aSteps = json_decode(utils::ReadParam('_steps', '[]', false, 'raw_data'), true /* bAssoc */);
|
||||
|
||||
switch ($sOperation) {
|
||||
case 'next':
|
||||
@@ -371,11 +371,6 @@ on the page's parameters
|
||||
return $sOutput;
|
||||
}
|
||||
|
||||
public function SetWizardSteps(array $aWizardSteps): void
|
||||
{
|
||||
$this->aWizardSteps = $aWizardSteps;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sCurrentStepClass
|
||||
* @param string $sCurrentState
|
||||
|
||||
@@ -31,7 +31,6 @@ abstract class AbstractWizStepInstall extends WizardStep
|
||||
$aSelectedExtensions = json_decode($this->oWizard->GetParameter('selected_extensions'), true);
|
||||
$sBackupDestination = '';
|
||||
$sPreviousConfigurationFile = '';
|
||||
$bCopySetupFiles = $this->oWizard->GetParameter('copy_setup_files', true);
|
||||
$sDBName = $this->oWizard->GetParameter('db_name');
|
||||
if ($sMode == 'upgrade') {
|
||||
$sPreviousVersionDir = $this->oWizard->GetParameter('previous_version_dir', '');
|
||||
@@ -46,6 +45,7 @@ abstract class AbstractWizStepInstall extends WizardStep
|
||||
$sBackupDestination = $this->oWizard->GetParameter('db_backup_path', '');
|
||||
}
|
||||
} else {
|
||||
|
||||
$sDBNewName = $this->oWizard->GetParameter('db_new_name', '');
|
||||
if ($sDBNewName != '') {
|
||||
$sDBName = $sDBNewName; // Database will be created
|
||||
@@ -54,7 +54,7 @@ abstract class AbstractWizStepInstall extends WizardStep
|
||||
|
||||
$sSourceDir = $this->oWizard->GetParameter('source_dir');
|
||||
if (($sMode == 'upgrade') && ($this->oWizard->GetParameter('upgrade_type') == 'keep-previous')) {
|
||||
//$sPreviousVersionDir = $this->oWizard->GetParameter('previous_version_dir');
|
||||
$sPreviousVersionDir = $this->oWizard->GetParameter('previous_version_dir');
|
||||
//$aCopies[] = ['source' => $sSourceDir, 'destination' => 'modules']; // Source is an absolute path, destination is relative to APPROOT
|
||||
//$aCopies[] = ['source' => $sPreviousVersionDir.'/portal', 'destination' => 'portal']; // Source is an absolute path, destination is relative to APPROOT
|
||||
$sSourceDir = APPROOT.'modules';
|
||||
@@ -72,7 +72,7 @@ abstract class AbstractWizStepInstall extends WizardStep
|
||||
'source_dir' => str_replace(APPROOT, '', $sSourceDir),
|
||||
'datamodel_version' => $this->oWizard->GetParameter('datamodel_version'), //TODO: let the installer compute this automatically...
|
||||
'previous_configuration_file' => $sPreviousConfigurationFile,
|
||||
'extensions_dir' => $this->oWizard->GetParameter('extensions_dir', 'extensions'),
|
||||
'extensions_dir' => 'extensions',
|
||||
'target_env' => 'production',
|
||||
'workspace_dir' => '',
|
||||
'database' => [
|
||||
@@ -108,10 +108,6 @@ abstract class AbstractWizStepInstall extends WizardStep
|
||||
];
|
||||
}
|
||||
|
||||
if ($bCopySetupFiles) {
|
||||
$aInstallParams['optional_steps']['copy'] = true;
|
||||
}
|
||||
|
||||
return $aInstallParams;
|
||||
}
|
||||
|
||||
|
||||
@@ -44,29 +44,12 @@ abstract class AbstractWizStepMiscParams extends WizardStep
|
||||
{
|
||||
$sChecked = $this->oWizard->GetParameter('force-uninstall', false) ? ' checked ' : '';
|
||||
$oPage->add('<fieldset>');
|
||||
|
||||
$oPage->add('<div id="prefix_option" class="collapsable-options">');
|
||||
$oPage->add('<span data-role="setup-collapsable-options--toggler"><label style="font-weight: normal;">Advanced parameters</label></span>');
|
||||
$oPage->add('<div class="" style="'.(mb_strlen($sChecked) === 0 ? 'display:none' : '').'">');
|
||||
$oPage->add('<input id="force-uninstall" type="checkbox"'.$sChecked.' name="force-uninstall"><label for="force-uninstall"> Unlock any extension uninstallation</label>');
|
||||
$oPage->add('<div class="message message-warning">This could result in data corruption and application crashes.</div>');
|
||||
$oPage->add('</div>');
|
||||
$oPage->add('</div>');
|
||||
$oPage->add('<legend>Advanced parameters</legend>');
|
||||
$oPage->p('<input id="force-uninstall" type="checkbox"'.$sChecked.' name="force-uninstall"><label for="force-uninstall"> Disable uninstallation checks for extensions');
|
||||
$oPage->add('</fieldset>');
|
||||
$oPage->add_style(
|
||||
<<<CSS
|
||||
#force-uninstall:not(:checked) ~ .message-warning{
|
||||
display:none;
|
||||
}
|
||||
CSS
|
||||
);
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<'JS'
|
||||
$("[data-role=\"setup-collapsable-options--toggler\"").on('click', function() {
|
||||
var $tbody = $(this).closest("div");
|
||||
$tbody.children().not(":first-child").toggle();
|
||||
$tbody.toggleClass('setup-is-opened');
|
||||
});
|
||||
$("#force-uninstall").on("click", function() {
|
||||
let $this = $(this);
|
||||
let bForceUninstall = $this.prop("checked");
|
||||
|
||||
@@ -100,31 +100,39 @@ JS);
|
||||
{
|
||||
$sApplicationUrl = utils::GetAbsoluteUrlModulePage('combodo-data-feature-removal', 'index.php');
|
||||
|
||||
$aParams = [
|
||||
'selected_modules' => '[]',
|
||||
'selected_extensions' => '[]',
|
||||
'display_choices' => '[]',
|
||||
'added_extensions' => '[]',
|
||||
'removed_extensions' => '[]',
|
||||
'extensions_not_uninstallable' => '[]',
|
||||
'copy_setup_files' => 1,
|
||||
];
|
||||
$aHiddenInputs = '';
|
||||
foreach ($aParams as $sParamName => $defaultValue) {
|
||||
$sElements = utils::HtmlEntities($this->oWizard->GetParameter($sParamName, $defaultValue));
|
||||
$sParamName = utils::HtmlEntities($sParamName);
|
||||
$aHiddenInputs .= <<<INPUT
|
||||
<input type="hidden" name="$sParamName" value="$sElements"/>
|
||||
$aRemovedExtensions = json_decode($this->oWizard->GetParameter('removed_extensions', '[]'), true);
|
||||
$aHiddenRemovedExtensionInputs = '';
|
||||
if (!is_array($aRemovedExtensions)) {
|
||||
IssueLog::Warning('Posted removed_extensions is not an array');
|
||||
$aRemovedExtensions = [];
|
||||
}
|
||||
foreach ($aRemovedExtensions as $sExtCode => $sExtLabel) {
|
||||
$sSafeExtCode = utils::HtmlEntities($sExtCode);
|
||||
$aHiddenRemovedExtensionInputs .= <<<INPUT
|
||||
<input type="hidden" name="aRemovedExtensions[$sSafeExtCode]" value="$sExtLabel"/>
|
||||
INPUT;
|
||||
}
|
||||
|
||||
$aAddedExtensions = json_decode($this->oWizard->GetParameter('extensions_added', "[]"), true);
|
||||
$aHiddenAddedExtensionInputs = "";
|
||||
if (!is_array($aAddedExtensions)) {
|
||||
IssueLog::Warning('Posted extensions_added is not an array');
|
||||
$aAddedExtensions = [];
|
||||
}
|
||||
foreach ($aAddedExtensions as $sExtCode => $sExtLabel) {
|
||||
$sSafeExtCode = utils::HtmlEntities($sExtCode);
|
||||
$aHiddenAddedExtensionInputs .= <<<INPUT
|
||||
<input type="hidden" name="aAddedExtensions[$sSafeExtCode]" value="$sExtLabel"/>
|
||||
INPUT;
|
||||
}
|
||||
$sUID = Session::Get('setup_token');
|
||||
$oPage->add(
|
||||
<<<HTML
|
||||
<form id="data-feature-removal" class="ibo-setup--wizard ibo-is-hidden" method="post" action="$sApplicationUrl">
|
||||
<input type="hidden" name="operation" value="AnalysisResult"/>
|
||||
<input type="hidden" name="setup_token" value="$sUID"/>
|
||||
$aHiddenInputs
|
||||
$aHiddenRemovedExtensionInputs
|
||||
$aHiddenAddedExtensionInputs
|
||||
</form>
|
||||
HTML
|
||||
);
|
||||
@@ -133,18 +141,17 @@ HTML
|
||||
protected function AddProgressErrorScript($oPage, $aRes)
|
||||
{
|
||||
if (isset($aRes['error_code']) && $aRes['error_code'] === DataAuditSequencer::DATA_AUDIT_FAILED) {
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('.ibo-setup--wizard--buttons-container tr td:nth-child(2)').before('<td style="text-align:center;"><button class="ibo-button ibo-is-alternative ibo-is-neutral" type="submit" name="operation" value="next" id="ignore_and_continue"><span class="ibo-button--label">Ignore and continue</span></button></td>');
|
||||
$('#ignore_and_continue').on('click', function() {
|
||||
return confirm("If you skip the cleanup you won't be able to run the process later. You'll have to migrate or delete unconsistent data manually.");
|
||||
});
|
||||
$('.ibo-setup--wizard--buttons-container tr td:nth-child(2)').after('<td style="text-align:center;"><span id="submit-wait" class="ibo-spinner ibo-is-inline ibo-is-hidden ibo-spinner ibo-block" data-role="ibo-spinner"><i class="ibo-spinner--icon fas fa-sync-alt fa-spin" aria-hidden="true"></i></span> <button id="goto-data-feature-removal" class="default ibo-button ibo-is-regular ibo-is-primary" type="button"><span class="ibo-button--label">Cleanup my data</span></button></td>');
|
||||
$('.ibo-setup--wizard--buttons-container tr td:nth-child(2)').before('<td style="text-align:center;"><button class="ibo-button ibo-is-alternative ibo-is-neutral" type="submit" name="operation" value="next"><span class="ibo-button--label">Ignore and continue</span></button></td>');
|
||||
|
||||
$('.ibo-setup--wizard--buttons-container tr td:nth-child(2)').after('<td style="text-align:center;"><span id="submit-wait" class="ibo-spinner ibo-is-inline ibo-is-hidden ibo-spinner ibo-block" data-role="ibo-spinner"><i class="ibo-spinner--icon fas fa-sync-alt fa-spin" aria-hidden="true"></i></span> <button id="goto-data-feature-removal" class="default ibo-button ibo-is-regular ibo-is-primary" type="button"><span class="ibo-button--label">Go to backoffice</span></button></td>');
|
||||
$('#goto-data-feature-removal').on("click", function() {
|
||||
$('#goto-data-feature-removal').prop('disabled', true);
|
||||
$('#submit-wait').removeClass("ibo-is-hidden");
|
||||
$('#data-feature-removal').submit();
|
||||
});
|
||||
})
|
||||
|
||||
$("#wiz_form").data("installation_status", "cleanup_needed");
|
||||
$('#btn_next').hide();
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2026 Combodo SAS
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
class WizStepLandingBeforeAudit extends WizStepModulesChoice
|
||||
{
|
||||
public function __construct(WizardController $oWizard, $sCurrentState)
|
||||
{
|
||||
$oProductionEnv = new RunTimeEnvironment();
|
||||
$sBuildConfigFile = APPCONF.$oProductionEnv->GetBuildEnv().'/'.ITOP_CONFIG_FILE;
|
||||
$this->oConfig = new Config($sBuildConfigFile);
|
||||
|
||||
$oWizard->SetParameter('previous_version_dir', APPROOT);
|
||||
$oWizard->SetParameter('install_mode', 'upgrade');
|
||||
$oWizard->SetParameter('source_dir', APPROOT.$this->oConfig->Get('source_dir'));
|
||||
$oWizard->SetParameter('graphviz_path', $this->oConfig->Get('graphviz_path'));
|
||||
$oWizard->SetParameter('application_url', $this->oConfig->Get('app_root_url'));
|
||||
$oWizard->SetParameter('datamodel_version', ITOP_CORE_VERSION);
|
||||
$oWizard->SetParameter('upgrade_type', 'use-compatible');
|
||||
|
||||
$oWizard->SaveParameter('use_symbolic_links', MFCompiler::UseSymbolicLinks());
|
||||
$oWizard->SaveParameter('force-uninstall', '');
|
||||
|
||||
// should be done at the end
|
||||
parent::__construct($oWizard, $sCurrentState, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function Display(SetupPage $oPage): void
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function UpdateWizardStateAndGetNextStep($bMoveForward = true): WizardState
|
||||
{
|
||||
$oProductionEnv = new RunTimeEnvironment();
|
||||
$sBuildConfigFile = APPCONF.$oProductionEnv->GetBuildEnv().'/'.ITOP_CONFIG_FILE;
|
||||
@chmod($sBuildConfigFile, 0770); // In case it exists: RWX for owner and group, nothing for others
|
||||
|
||||
$oConfig = new Config($sBuildConfigFile);
|
||||
$this->oWizard->SetParameter('db_server', $oConfig->Get('db_host'));
|
||||
$this->oWizard->SetParameter('db_user', $oConfig->Get('db_user'));
|
||||
$this->oWizard->SetParameter('db_pwd', $oConfig->Get('db_pwd'));
|
||||
$this->oWizard->SetParameter('db_name', $oConfig->Get('db_name'));
|
||||
$this->oWizard->SetParameter('db_prefix', $oConfig->Get('db_subname'));
|
||||
$this->oWizard->SetParameter('db_tls_enabled', $oConfig->Get('db_tls.enabled'));
|
||||
$this->oWizard->SetParameter('db_tls_ca', $oConfig->Get('db_tls.ca') ?? '');
|
||||
|
||||
$this->oWizard->SetParameter('display_choices', '[]');
|
||||
$this->oWizard->SetParameter('extensions_not_uninstallable', '[]');
|
||||
|
||||
$aWizardSteps = $this->GetWizardSteps();
|
||||
$this->oWizard->SetWizardSteps($aWizardSteps);
|
||||
$this->sCurrentState = count($aWizardSteps) - 1;
|
||||
|
||||
$aSelectedComponents = $this->GetSelectedComponents($this->aSteps, $this->oWizard->GetParameter('selected_extensions'));
|
||||
$this->oWizard->SetParameter('selected_components', json_encode($aSelectedComponents));
|
||||
|
||||
return new WizardState(WizStepDataAudit::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function GetTitle(): string
|
||||
{
|
||||
return 'Before checking compatibility';
|
||||
}
|
||||
|
||||
public function GetPossibleSteps()
|
||||
{
|
||||
return [WizStepDataAudit::class];
|
||||
}
|
||||
|
||||
public function GetNextButtonLabel()
|
||||
{
|
||||
return 'Next';
|
||||
}
|
||||
|
||||
public function CanComeBack()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ use Combodo\iTop\Setup\ModuleDiscovery\ModuleFileReaderException;
|
||||
/**
|
||||
* Choice of the modules to be installed
|
||||
*/
|
||||
class WizStepModulesChoice extends AbstractWizStepInstall
|
||||
class WizStepModulesChoice extends WizardStep
|
||||
{
|
||||
protected static string $SEP = '_';
|
||||
protected bool $bUpgrade = false;
|
||||
@@ -38,7 +38,7 @@ class WizStepModulesChoice extends AbstractWizStepInstall
|
||||
*/
|
||||
protected iTopExtensionsMap $oExtensionsMap;
|
||||
|
||||
protected ?array $aSteps = null;
|
||||
private ?array $aSteps = null;
|
||||
|
||||
protected PhpExpressionEvaluator $oPhpExpressionEvaluator;
|
||||
|
||||
@@ -51,7 +51,7 @@ class WizStepModulesChoice extends AbstractWizStepInstall
|
||||
private array $aAnalyzeInstallationModules = [];
|
||||
private ?MissingDependencyException $oMissingDependencyException = null;
|
||||
|
||||
public function __construct(WizardController $oWizard, $sCurrentState, bool $bOverWriteConfig = true)
|
||||
public function __construct(WizardController $oWizard, $sCurrentState)
|
||||
{
|
||||
parent::__construct($oWizard, $sCurrentState);
|
||||
$this->bChoicesFromDatabase = false;
|
||||
@@ -69,10 +69,8 @@ class WizStepModulesChoice extends AbstractWizStepInstall
|
||||
if ($sConfigPath !== null) {
|
||||
$this->oConfig = new Config($sConfigPath);
|
||||
|
||||
if ($bOverWriteConfig) {
|
||||
$aParamValues = $oWizard->GetParamForConfigArray();
|
||||
$this->oConfig->UpdateFromParams($aParamValues);
|
||||
}
|
||||
$aParamValues = $oWizard->GetParamForConfigArray();
|
||||
$this->oConfig->UpdateFromParams($aParamValues);
|
||||
|
||||
$this->oExtensionsMap->LoadChoicesFromDatabase($this->oConfig);
|
||||
$this->bChoicesFromDatabase = true;
|
||||
@@ -80,9 +78,7 @@ class WizStepModulesChoice extends AbstractWizStepInstall
|
||||
|
||||
// Sanity check (not stopper, to let developers go further...)
|
||||
try {
|
||||
$aModulesToLoad = json_decode($oWizard->GetParameter('selected_modules'), true) ?? null;
|
||||
SetupLog::Error(__METHOD__, null, [$aModulesToLoad]);
|
||||
$this->aAnalyzeInstallationModules = SetupUtils::AnalyzeInstallation($this->oWizard, true, $aModulesToLoad, $this->oConfig);
|
||||
$this->aAnalyzeInstallationModules = SetupUtils::AnalyzeInstallation($this->oWizard, true);
|
||||
} catch (MissingDependencyException $e) {
|
||||
$this->oMissingDependencyException = $e;
|
||||
$this->aAnalyzeInstallationModules = SetupUtils::AnalyzeInstallation($this->oWizard);
|
||||
@@ -122,6 +118,17 @@ class WizStepModulesChoice extends AbstractWizStepInstall
|
||||
return [$aExtensionsAdded, $aExtensionsRemoved, $aExtensionsNotUninstallable];
|
||||
}
|
||||
|
||||
public function IsDataAuditEnabled(): bool
|
||||
{
|
||||
$sPath = APPROOT.'env-production';
|
||||
if (!is_dir($sPath)) {
|
||||
SetupLog::Info("Reinstallation of an iTop from a backup (No env-production found). Setup data audit disabled");
|
||||
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public function UpdateWizardStateAndGetNextStep($bMoveForward = true): WizardState
|
||||
{
|
||||
// Accumulates the selected modules:
|
||||
@@ -156,7 +163,7 @@ class WizStepModulesChoice extends AbstractWizStepInstall
|
||||
$this->oWizard->SetParameter('selected_modules', json_encode(array_keys($aModules)));
|
||||
$this->oWizard->SetParameter('selected_extensions', json_encode($aExtensions));
|
||||
$this->oWizard->SetParameter('display_choices', $sDisplayChoices);
|
||||
$this->oWizard->SetParameter('added_extensions', json_encode($aExtensionsAdded));
|
||||
$this->oWizard->SetParameter('extensions_added', json_encode($aExtensionsAdded));
|
||||
$this->oWizard->SetParameter('removed_extensions', json_encode($aExtensionsRemoved));
|
||||
$this->oWizard->SetParameter('extensions_not_uninstallable', json_encode(array_keys($aExtensionsNotUninstallable)));
|
||||
|
||||
@@ -168,97 +175,6 @@ class WizStepModulesChoice extends AbstractWizStepInstall
|
||||
return new WizardState(WizStepModulesChoice::class, (string)($index - 1));
|
||||
}
|
||||
|
||||
public function GetWizardSteps(): array
|
||||
{
|
||||
$aSteps = [
|
||||
["class" => "WizStepWelcome","state" => ""],
|
||||
["class" => "WizStepInstallOrUpgrade","state" => ""],
|
||||
["class" => "WizStepDetectedInfo","state" => ""],
|
||||
["class" => "WizStepUpgradeMiscParams","state" => ""],
|
||||
];
|
||||
$i = 0;
|
||||
$this->aSteps = null;
|
||||
while (null != $this->GetStepInfo($i)) {
|
||||
$this->aSteps = null;
|
||||
$aSteps [] = ["class" => "WizStepModulesChoice","state" => "$i"];
|
||||
$i++;
|
||||
}
|
||||
|
||||
return $aSteps;
|
||||
}
|
||||
|
||||
public function GetSelectedComponents(array $aSteps, string $sSelectedExtensionJson): array
|
||||
{
|
||||
$aExtensions = json_decode($sSelectedExtensionJson, true);
|
||||
$aRes = [];
|
||||
foreach ($aSteps as $aStepInfo) {
|
||||
$aStepRes = [];
|
||||
$this->ProcessOptions("", $aStepInfo, $aExtensions, $aStepRes);
|
||||
$this->ProcessAlternatives("", $aStepInfo, $aExtensions, $aStepRes);
|
||||
$aRes [] = $aStepRes;
|
||||
}
|
||||
|
||||
return $aRes;
|
||||
}
|
||||
|
||||
public function ProcessOptions(string $sCurrentIndex, array $aInfo, array $aExtensions, array &$aStepRes)
|
||||
{
|
||||
$aOptions = $aInfo["options"] ?? null;
|
||||
if (is_null($aOptions) || !is_array($aOptions)) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($aOptions as $i => $aOptionsInfo) {
|
||||
$sExtensionCode = $aOptionsInfo["extension_code"] ?? null;
|
||||
|
||||
if (in_array($sExtensionCode, $aExtensions)) {
|
||||
$aStepRes = $this->ProcessSelectedOption($sCurrentIndex, $i, $aStepRes, $aOptionsInfo, $aExtensions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function ProcessAlternatives(string $sCurrentIndex, array $aInfo, array $aExtensions, array &$aStepRes)
|
||||
{
|
||||
$aAlternatives = $aInfo["alternatives"] ?? null;
|
||||
if (is_null($aAlternatives) || ! is_array($aAlternatives)) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($aAlternatives as $i => $aAlternativeInfo) {
|
||||
$sExtensionCode = $aAlternativeInfo["extension_code"] ?? null;
|
||||
|
||||
if (in_array($sExtensionCode, $aExtensions)) {
|
||||
$aStepRes = $this->ProcessSelectedOption($sCurrentIndex, $i, $aStepRes, $aAlternativeInfo, $aExtensions);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sCurrentIndex
|
||||
* @param int|string $i
|
||||
* @param array $aStepRes
|
||||
* @param mixed $aOptionsInfo
|
||||
* @param array $aExtensions
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function ProcessSelectedOption(string $sCurrentIndex, int|string $i, array $aStepRes, mixed $aOptionsInfo, array $aExtensions): array
|
||||
{
|
||||
$sNextIndex = "{$sCurrentIndex}_{$i}";
|
||||
$aStepRes[$sNextIndex] = $sNextIndex;
|
||||
|
||||
$aSubOptions = $aOptionsInfo['sub_options'] ?? null;
|
||||
if (!is_null($aSubOptions) && is_array($aSubOptions)) {
|
||||
$this->ProcessOptions($sNextIndex, $aSubOptions, $aExtensions, $aStepRes);
|
||||
$this->ProcessAlternatives($sNextIndex, $aSubOptions, $aExtensions, $aStepRes);
|
||||
}
|
||||
|
||||
$this->ProcessAlternatives($sNextIndex, $aOptionsInfo, $aExtensions, $aStepRes);
|
||||
|
||||
return $aStepRes;
|
||||
}
|
||||
|
||||
public function Display(SetupPage $oPage): void
|
||||
{
|
||||
$this->DisplayStep($oPage);
|
||||
@@ -711,6 +627,7 @@ 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);
|
||||
@@ -944,7 +861,7 @@ EOF
|
||||
return 'Non-uninstallable extension missing';
|
||||
}
|
||||
|
||||
if ($this->GetStepInfo(1 + $this->GetStepIndex()) === null) {
|
||||
if ($this->GetStepInfo(1 + $this->GetStepIndex()) === null && $this->IsDataAuditEnabled()) {
|
||||
return 'Check compatibility';
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
|
||||
/**
|
||||
* Summary of the installation tasks
|
||||
@@ -83,7 +84,7 @@ class WizStepSummary extends AbstractWizStepInstall
|
||||
$oPage->add('<div id="params_summary">');
|
||||
|
||||
$oPage->add('<div class="closed"><a class="title ibo-setup-summary-title" href="#" aria-label="Extensions to be installed">Extensions to be installed</a>');
|
||||
$aExtensionsAdded = json_decode($this->oWizard->GetParameter('added_extensions'), true) ?? [];
|
||||
$aExtensionsAdded = json_decode($this->oWizard->GetParameter('extensions_added'), true);
|
||||
|
||||
if (count($aExtensionsAdded) > 0) {
|
||||
$sExtensionsAdded = '<ul>';
|
||||
|
||||
@@ -18,5 +18,4 @@ require_once(APPROOT.'setup/wizardsteps/WizStepInstallMiscParams.php');
|
||||
require_once(APPROOT.'setup/wizardsteps/WizStepModulesChoice.php');
|
||||
require_once(APPROOT.'setup/wizardsteps/WizStepSummary.php');
|
||||
require_once(APPROOT.'setup/wizardsteps/WizStepUpgradeMiscParams.php');
|
||||
require_once(APPROOT.'setup/wizardsteps/WizStepLandingBeforeAudit.php');
|
||||
require_once(APPROOT.'setup/wizardcontroller.class.inc.php');
|
||||
|
||||
@@ -127,7 +127,6 @@ abstract class Controller extends AbstractController
|
||||
*/
|
||||
public function __construct($sViewPath = '', $sModuleName = 'core', $aAdditionalPaths = [], array $aThemes = ['application/forms/itop_console_layout.html.twig', 'application/forms/wip_form_demonstrator.html.twig'])
|
||||
{
|
||||
IssueLog::Enable(APPROOT.'log/error.log');
|
||||
$this->aLinkedScripts = [];
|
||||
$this->aLinkedStylesheets = [];
|
||||
$this->aSaas = [];
|
||||
|
||||
@@ -24,8 +24,6 @@ class Form extends UIContentBlock
|
||||
protected $sOnSubmitJsCode;
|
||||
/** @var string */
|
||||
protected $sAction;
|
||||
/** @var string */
|
||||
protected $sEncType = "multipart/form-data";
|
||||
|
||||
public function __construct(?string $sId = null)
|
||||
{
|
||||
@@ -67,25 +65,4 @@ class Form extends UIContentBlock
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override default enctype (default : "multipart/form-data")
|
||||
* @param string $sEncType
|
||||
* @return $this
|
||||
* @since 3.3.0
|
||||
*/
|
||||
public function SetEncType(string $sEncType)
|
||||
{
|
||||
$this->sEncType = $sEncType;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @since 3.3.0
|
||||
*/
|
||||
public function GetEncType(): string
|
||||
{
|
||||
return $this->sEncType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user