Compare commits

..

3 Commits

Author SHA1 Message Date
Anne-Cath
c904a625d7 Changes GetAsCSV() to AttributeEnum->GetValueLabel() 2026-06-23 11:03:36 +02:00
Anne-Catherine
492c955fc8 Update dictionaries/nl.dictionary.itop.core.php
Co-authored-by: Thomas Casteleyn <thomas.casteleyn@super-visions.com>
2026-06-23 11:03:36 +02:00
Anne-Cath
2244d24676 N°6327 - Enum, Date, FinalClass in Complementary Name not labelized 2026-06-23 11:03:36 +02:00
442 changed files with 3213 additions and 8802 deletions

View File

@@ -9,6 +9,11 @@ Any PRs not following the guidelines or with missing information will not be con
## Base information
| Question | Answer
|----------------------------------------------------------------|--------
| Related to a SourceForge thread / Another PR / A GitHub Issue / Combodo ticket? | <!-- Put the URL --> |
| Type of change? | Bug fix / Enhancement / Translations
| Question | Answer |
|---------------------------------------------------------------------------------|--------------------------------------|
| Related to a SourceForge thread / Another PR / A GitHub Issue / Combodo ticket? | <!-- Put the URL --> |

0
.make/license/gen-community-license.sh Executable file → Normal file
View File

0
.make/license/sortLicenceXml.php Executable file → Normal file
View File

0
.make/license/updateLicenses.php Executable file → Normal file
View File

0
.make/release/changelog.php Executable file → Normal file
View File

0
.make/release/update-versions.php Executable file → Normal file
View File

0
.make/release/update-xml.php Executable file → Normal file
View File

0
.make/release/update.classes.inc.php Executable file → Normal file
View File

View File

@@ -582,26 +582,16 @@ class UserRightsProfile extends UserRightsAddOnAPI
*/
public function ListProfiles($oUser)
{
if (count($oUser->ListChanges()) === 0) { // backward compatibility
$aRet = [];
$oSearch = new DBObjectSearch('URP_UserProfile');
$oSearch->AllowAllData();
$oSearch->NoContextParameters();
$oSearch->Addcondition('userid', $oUser->GetKey(), '=');
$oProfiles = new DBObjectSet($oSearch);
while ($oUserProfile = $oProfiles->Fetch()) {
$aRet[$oUserProfile->Get('profileid')] = $oUserProfile->Get('profileid_friendlyname');
}
return $aRet;
} else {
$aRet = [];
$oProfilesSet = $oUser->Get('profile_list');
foreach ($oProfilesSet as $oUserProfile) {
$aRet[$oUserProfile->Get('profileid')] = $oUserProfile->Get('profileid_friendlyname');
}
return $aRet;
$aRet = [];
$oSearch = new DBObjectSearch('URP_UserProfile');
$oSearch->AllowAllData();
$oSearch->NoContextParameters();
$oSearch->Addcondition('userid', $oUser->GetKey(), '=');
$oProfiles = new DBObjectSet($oSearch);
while ($oUserProfile = $oProfiles->Fetch()) {
$aRet[$oUserProfile->Get('profileid')] = $oUserProfile->Get('profileid_friendlyname');
}
return $aRet;
}
public function GetSelectFilter($oUser, $sClass, $aSettings = [])
@@ -715,23 +705,26 @@ class UserRightsProfile extends UserRightsAddOnAPI
protected function GetUserActionGrant($oUser, $sClass, $iActionCode)
{
$this->LoadCache();
if (count($oUser->ListChanges()) === 0) {
// load and cache permissions for the current user on the given class
if (isset($this->m_aObjectActionGrants[$oUser->GetKey()][$sClass][$iActionCode])) {
$aTest = $this->m_aObjectActionGrants[$oUser->GetKey()][$sClass][$iActionCode];
if (is_array($aTest)) {
return $aTest;
}
// load and cache permissions for the current user on the given class
//
$iUser = $oUser->GetKey();
if (isset($this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode])) {
$aTest = $this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode];
if (is_array($aTest)) {
return $aTest;
}
}
$sAction = self::$m_aActionCodes[$iActionCode];
$bStatus = null;
$aProfileList = $this->GetProfileList($oUser);
// Cache user's profiles
if (false === array_key_exists($iUser, $this->aUsersProfilesList)) {
$this->aUsersProfilesList[$iUser] = UserRights::ListProfiles($oUser);
}
// Call the API of UserRights because it caches the list for us
foreach ($aProfileList as $iProfile => $oProfile) {
foreach ($this->aUsersProfilesList[$iUser] as $iProfile => $oProfile) {
$bGrant = $this->GetProfileActionGrant($iProfile, $sClass, $sAction);
if (!is_null($bGrant)) {
if ($bGrant) {
@@ -749,9 +742,7 @@ class UserRightsProfile extends UserRightsAddOnAPI
$aRes = [
'permission' => $iPermission,
];
if (count($oUser->ListChanges()) === 0) {
$this->m_aObjectActionGrants[$oUser->GetKey()][$sClass][$iActionCode] = $aRes;
}
$this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode] = $aRes;
return $aRes;
}
@@ -833,14 +824,18 @@ class UserRightsProfile extends UserRightsAddOnAPI
{
$this->LoadCache();
// Note: this code is VERY close to the code of IsActionAllowed()
$iUser = $oUser->GetKey();
$aProfileList = $this->GetProfileList($oUser);
// Cache user's profiles
if (false === array_key_exists($iUser, $this->aUsersProfilesList)) {
$this->aUsersProfilesList[$iUser] = UserRights::ListProfiles($oUser);
}
// Note: The object set is ignored because it was interesting to optimize for huge data sets
// and acceptable to consider only the root class of the object set
$bStatus = null;
// Call the API of UserRights because it caches the list for us
foreach ($aProfileList as $iProfile => $oProfile) {
foreach ($this->aUsersProfilesList[$iUser] as $iProfile => $oProfile) {
$bGrant = $this->GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode);
if (!is_null($bGrant)) {
if ($bGrant) {
@@ -898,25 +893,6 @@ class UserRightsProfile extends UserRightsAddOnAPI
}
return $bHasSharing;
}
/**
* @param \User $oUser
*
* @return array
* @throws \Exception
*/
public function GetProfileList(User $oUser): array
{
if (count($oUser->ListChanges()) === 0) { // if user is already in db and not changed
$iUser = $oUser->GetKey();
if (false === array_key_exists($iUser, $this->aUsersProfilesList)) {
$aProfiles = UserRights::ListProfiles($oUser);
$this->aUsersProfilesList[$iUser] = $aProfiles;
}
return $this->aUsersProfilesList[$iUser];
}
return UserRights::ListProfiles($oUser);
}
}
UserRights::SelectModule('UserRightsProfile');

View File

@@ -113,43 +113,17 @@ abstract class Query extends cmdbAbstractObject
]
));
MetaModel::Init_AddAttribute(new AttributeExternalKey(
"owner_id",
[
"targetclass" => 'Contact',
"allowed_values" => null,
"sql" => 'owner_id',
"is_null_allowed" => true,
"depends_on" => [],
"display_style" => 'select',
"always_load_in_tables" => false,
"on_target_delete" => DEL_AUTO,
]
));
MetaModel::Init_AddAttribute(new AttributeEnumSet(
"usages",
[
"allowed_values" => null,
"possible_values" => new ValueSetEnumPadded("export,reference,notif,draft,dashlet"),
"sql" => "usages",
"depends_on" => [],
"is_null_allowed" => true,
"max_items" => 12,
]
));
// Display lists
MetaModel::Init_SetZListItems(
'details',
['name', 'is_template', 'owner_id', 'usages', 'description']
['name', 'is_template', 'description']
); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', ['description', 'usages']); // Attributes to be displayed for a list
MetaModel::Init_SetZListItems('list', ['description']); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems('standard_search', ['name', 'description', 'is_template']); // Criteria of the std search form
MetaModel::Init_SetZListItems(
'default_search',
['name', 'description', 'is_template', 'owner_id', 'usages']
['name', 'description', 'is_template']
); // Criteria of the default search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
@@ -169,15 +143,6 @@ abstract class Query extends cmdbAbstractObject
return parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState);
}
public function GetInitialStateAttributeFlags($sAttCode, &$aReasons = [])
{
// read only attribute
if (in_array($sAttCode, ['export_count', 'export_last_date', 'export_last_user_id'])) {
return OPT_ATT_READONLY;
}
return parent::GetInitialStateAttributeFlags($sAttCode, $aReasons);
}
/**
* Return export url.
*
@@ -249,15 +214,15 @@ class QueryOQL extends Query
MetaModel::Init_SetZListItems(
'details',
[
'col:col1' => ['fieldset:Query:baseinfo' => ['name', 'is_template', 'owner_id', 'usages', 'description', 'oql', 'fields']],
'col:col1' => ['fieldset:Query:baseinfo' => ['name', 'is_template', 'description', 'oql', 'fields']],
'col:col2' => ['fieldset:Query:exportInfo' => ['export_count', 'export_last_date', 'export_last_user_id', 'export_last_user_contact']],
]
); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', ['description', 'usages']); // Attributes to be displayed for a list
MetaModel::Init_SetZListItems('list', ['description']); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems(
'standard_search',
['name', 'description', 'is_template', 'owner_id', 'usages', 'oql']
['name', 'description', 'is_template', 'fields', 'oql']
); // Criteria of the std search form
}

View File

@@ -284,7 +284,8 @@ class UIExtKeyWidget
if ($bAddingValue) {
$aArguments = [];
foreach ($aAdditionalField as $sAdditionalField) {
array_push($aArguments, $oObj->Get($sAdditionalField));
$oAttrDef = MetaModel::GetAttributeDef(get_class($oObj), $sAdditionalField);
array_push($aArguments, $oAttrDef->GetValueLabel($oObj->Get($sAdditionalField)));
}
$aOption['additional_field'] = utils::HtmlEntities(utils::VSprintf($sFormatAdditionalField, $aArguments));
}

14
composer.lock generated
View File

@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "24e7507794b971955358df5f2b143ac4",
"content-hash": "1cca58a0e26794fb9c546a001f7f7de8",
"packages": [
{
"name": "apereo/phpcas",
@@ -5570,16 +5570,16 @@
},
{
"name": "twig/twig",
"version": "v3.28.0",
"version": "v3.24.0",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "597c12ed286fb9d1701a36684ce6e0cbe28ebc8b"
"reference": "a6769aefb305efef849dc25c9fd1653358c148f0"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/597c12ed286fb9d1701a36684ce6e0cbe28ebc8b",
"reference": "597c12ed286fb9d1701a36684ce6e0cbe28ebc8b",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/a6769aefb305efef849dc25c9fd1653358c148f0",
"reference": "a6769aefb305efef849dc25c9fd1653358c148f0",
"shasum": ""
},
"require": {
@@ -5634,7 +5634,7 @@
],
"support": {
"issues": "https://github.com/twigphp/Twig/issues",
"source": "https://github.com/twigphp/Twig/tree/v3.28.0"
"source": "https://github.com/twigphp/Twig/tree/v3.24.0"
},
"funding": [
{
@@ -5646,7 +5646,7 @@
"type": "tidelift"
}
],
"time": "2026-07-03T20:44:34+00:00"
"time": "2026-03-17T21:31:11+00:00"
}
],
"packages-dev": [

View File

@@ -916,9 +916,7 @@ class CMDBSource
$aColumn = [];
$aData = self::QueryToArray($sSql);
foreach ($aData as $aRow) {
if ($aRow[$col] !== null) {
$aColumn[] = $aRow[$col];
}
@$aColumn[] = $aRow[$col];
}
return $aColumn;
}

View File

@@ -1935,8 +1935,9 @@ class DBObjectSearch extends DBSearch
/**
* @inheritDoc
* @return DBObjectSearch
*/
protected function ApplyDataFilters(): DBSearch
protected function ApplyDataFilters(): DBObjectSearch
{
if ($this->IsAllDataAllowed() || $this->IsDataFiltered()) {
return $this;

View File

@@ -676,8 +676,9 @@ class DBUnionSearch extends DBSearch
/**
* @inheritDoc
* @return DBUnionSearch
*/
protected function ApplyDataFilters(): DBSearch
protected function ApplyDataFilters(): DBUnionSearch
{
if ($this->IsAllDataAllowed() || $this->IsDataFiltered()) {
return $this;

View File

@@ -434,7 +434,7 @@ JS
* Resize an image so that it fits the maximum width/height defined in the config file
* @param ormDocument $oImage The original image stored as an array (content / mimetype / filename)
* @return ormDocument The resampled image (or the original one if it already fit)
* @deprecated 3.3.0 Use ormDocument::ResizeImageToFit instead
* @deprecated since 3.3.0 Replaced by ormDocument::ResizeImageToFit
*/
public static function ResizeImageToFit(ormDocument $oImage, &$aDimensions = null)
{

View File

@@ -614,13 +614,6 @@ class LogChannels
* @since 3.2.0
*/
public const SECURITY = 'Security';
/**
* For Session parameters
*
* @Since 3.3.0
*/
public const SESSION_PARAMETERS = 'SessionParameters';
}
abstract class LogAPI

View File

@@ -5761,37 +5761,36 @@ abstract class MetaModel
self::$m_sEnvironment = $sEnvironment;
if (!defined('MODULESROOT')) {
define('MODULESROOT', APPROOT.'env-'.self::$m_sEnvironment.'/');
try {
if (!defined('MODULESROOT')) {
define('MODULESROOT', APPROOT.'env-'.self::$m_sEnvironment.'/');
self::$m_bTraceSourceFiles = $bTraceSourceFiles;
self::$m_bTraceSourceFiles = $bTraceSourceFiles;
// $config can be either a filename, or a Configuration object (volatile!)
if ($config instanceof Config) {
self::LoadConfig($config, $bAllowCache);
} else {
self::LoadConfig(new Config($config), $bAllowCache);
// $config can be either a filename, or a Configuration object (volatile!)
if ($config instanceof Config) {
self::LoadConfig($config, $bAllowCache);
} else {
self::LoadConfig(new Config($config), $bAllowCache);
}
if ($bModelOnly) {
return;
}
}
if ($bModelOnly) {
// Event service must be initialized after the MetaModel startup, otherwise it cannot discover classes implementing the iEventServiceSetup interface
EventService::InitService();
EventService::FireEvent(new EventData(ApplicationEvents::APPLICATION_EVENT_METAMODEL_STARTED));
return;
CMDBSource::SelectDB(self::$m_sDBName);
foreach (MetaModel::EnumPlugins('ModuleHandlerApiInterface') as $oPHPClass) {
$oPHPClass::OnMetaModelStarted();
}
ExpressionCache::Warmup();
} finally {
// Event service must be initialized after the MetaModel startup, otherwise it cannot discover classes implementing the iEventServiceSetup interface
EventService::InitService();
EventService::FireEvent(new EventData(ApplicationEvents::APPLICATION_EVENT_METAMODEL_STARTED));
}
CMDBSource::SelectDB(self::$m_sDBName);
foreach (MetaModel::EnumPlugins('ModuleHandlerApiInterface') as $oPHPClass) {
$oPHPClass::OnMetaModelStarted();
}
ExpressionCache::Warmup();
// Event service must be initialized after the MetaModel startup, otherwise it cannot discover classes implementing the iEventServiceSetup interface
EventService::InitService();
EventService::FireEvent(new EventData(ApplicationEvents::APPLICATION_EVENT_METAMODEL_STARTED));
}
/**

View File

@@ -408,7 +408,7 @@ class ormDocument
* @param int $iMaxImageHeight Maximum height for the resized image
* @param array|null $aFinalDimensions Image dimensions after resizing or null if unable to read the image
* @return ormDocument The resampled image
* @since 3.3.0 N°3124
*
*/
public function ResizeImageToFit(int $iMaxWidth, int $iMaxHeight, array|null &$aFinalDimensions = null): static
{

View File

@@ -39,7 +39,7 @@ abstract class Trigger extends cmdbAbstractObject
"category" => "grant_by_profile,core/cmdb",
"key_type" => "autoincrement",
"name_attcode" => "description",
"complementary_name_attcode" => ['finalclass', 'complement'],
"complementary_name_attcode" => ['finalclass', 'target_class'],
"state_attcode" => "",
"reconc_keys" => ['description'],
"db_table" => "priv_trigger",
@@ -174,7 +174,7 @@ abstract class TriggerOnObject extends Trigger
"category" => "grant_by_profile,core/cmdb",
"key_type" => "autoincrement",
"name_attcode" => "description",
"complementary_name_attcode" => ['finalclass', 'complement'],
"complementary_name_attcode" => ['finalclass', 'target_class'],
"state_attcode" => "",
"reconc_keys" => ['description'],
"db_table" => "priv_trigger_onobject",
@@ -401,7 +401,7 @@ class TriggerOnPortalUpdate extends TriggerOnObject
"category" => "grant_by_profile,core/cmdb,application",
"key_type" => "autoincrement",
"name_attcode" => "description",
"complementary_name_attcode" => ['finalclass', 'complement'],
"complementary_name_attcode" => ['finalclass', 'target_class'],
"state_attcode" => "",
"reconc_keys" => ['description'],
"db_table" => "priv_trigger_onportalupdate",
@@ -434,7 +434,7 @@ abstract class TriggerOnStateChange extends TriggerOnObject
"category" => "grant_by_profile,core/cmdb",
"key_type" => "autoincrement",
"name_attcode" => "description",
"complementary_name_attcode" => ['finalclass', 'complement'],
"complementary_name_attcode" => ['finalclass', 'target_class'],
"state_attcode" => "",
"reconc_keys" => ['description'],
"db_table" => "priv_trigger_onstatechange",
@@ -469,7 +469,7 @@ class TriggerOnStateEnter extends TriggerOnStateChange
"category" => "grant_by_profile,core/cmdb,application",
"key_type" => "autoincrement",
"name_attcode" => "description",
"complementary_name_attcode" => ['finalclass', 'complement'],
"complementary_name_attcode" => ['finalclass', 'target_class'],
"state_attcode" => "",
"reconc_keys" => ['description'],
"db_table" => "priv_trigger_onstateenter",
@@ -503,7 +503,7 @@ class TriggerOnStateLeave extends TriggerOnStateChange
"category" => "grant_by_profile,core/cmdb,application",
"key_type" => "autoincrement",
"name_attcode" => "description",
"complementary_name_attcode" => ['finalclass', 'complement'],
"complementary_name_attcode" => ['finalclass', 'target_class'],
"state_attcode" => "",
"reconc_keys" => ['description'],
"db_table" => "priv_trigger_onstateleave",
@@ -537,7 +537,7 @@ class TriggerOnObjectCreate extends TriggerOnObject
"category" => "grant_by_profile,core/cmdb,application",
"key_type" => "autoincrement",
"name_attcode" => "description",
"complementary_name_attcode" => ['finalclass', 'complement'],
"complementary_name_attcode" => ['finalclass', 'target_class'],
"state_attcode" => "",
"reconc_keys" => ['description'],
"db_table" => "priv_trigger_onobjcreate",
@@ -572,7 +572,7 @@ class TriggerOnObjectDelete extends TriggerOnObject
"category" => "grant_by_profile,core/cmdb,application",
"key_type" => "autoincrement",
"name_attcode" => "description",
"complementary_name_attcode" => ['finalclass', 'complement'],
"complementary_name_attcode" => ['finalclass', 'target_class'],
"state_attcode" => "",
"reconc_keys" => ['description'],
"db_table" => "priv_trigger_onobjdelete",
@@ -607,7 +607,7 @@ class TriggerOnObjectUpdate extends TriggerOnObject
"category" => "grant_by_profile,core/cmdb,application",
"key_type" => "autoincrement",
"name_attcode" => "description",
"complementary_name_attcode" => ['finalclass', 'complement'],
"complementary_name_attcode" => ['finalclass', 'target_class'],
"state_attcode" => "",
"reconc_keys" => ['description'],
"db_table" => "priv_trigger_onobjupdate",
@@ -695,7 +695,7 @@ class TriggerOnObjectMention extends TriggerOnObject
"category" => "grant_by_profile,core/cmdb,application",
"key_type" => "autoincrement",
"name_attcode" => "description",
"complementary_name_attcode" => ['finalclass', 'complement'],
"complementary_name_attcode" => ['finalclass', 'target_class'],
"state_attcode" => "",
"reconc_keys" => ['description'],
"db_table" => "priv_trigger_onobjmention",
@@ -773,7 +773,7 @@ class TriggerOnAttributeBlobDownload extends TriggerOnObject
"category" => "grant_by_profile,core/cmdb,application",
"key_type" => "autoincrement",
"name_attcode" => "description",
"complementary_name_attcode" => ['finalclass', 'complement'],
"complementary_name_attcode" => ['finalclass', 'target_class'],
"state_attcode" => "",
"reconc_keys" => ['description'],
"db_table" => "priv_trigger_onattblobdownload",
@@ -852,7 +852,7 @@ class TriggerOnThresholdReached extends TriggerOnObject
"category" => "grant_by_profile,core/cmdb,application",
"key_type" => "autoincrement",
"name_attcode" => "description",
"complementary_name_attcode" => ['finalclass', 'complement'],
"complementary_name_attcode" => ['finalclass', 'target_class'],
"state_attcode" => "",
"reconc_keys" => ['description'],
"db_table" => "priv_trigger_threshold",

View File

@@ -1530,37 +1530,6 @@ class UserRights
}
}
/**
* @param User $oUser
* @param array $aExcludedProfilesId Administrator by default, but can also be other proofiles depending on needs (e.g. power portal user or REST profile)
* @return bool
* @throws ArchivedObjectException
* @throws CoreException
* @throws CoreUnexpectedValue
* @throws MySQLException
*/
public static function IsUserReadOnly(User $oUser, array $aExcludedProfilesId = [1]): bool
{
$oUserProfiles = $oUser->Get('profile_list');
$oUserRights = UserRights::GetModuleInstance();
while ($oUserProfile = $oUserProfiles->Fetch()) {
$iProfileId = $oUserProfile->Get('profileid');
if (in_array($iProfileId, $aExcludedProfilesId)) {
return false;
}
foreach (MetaModel::GetClasses('bizmodel,grant_by_profile') as $sClass) {
foreach (['w', 'bw', 'd', 'bd'] as $sWriteActionCode) {
$bIsGranted = $oUserRights->GetProfileActionGrant($iProfileId, $sClass, $sWriteActionCode);
if ($bIsGranted === true) {
return false;
}
}
}
}
return true;
}
/**
* @param string $sClass
* @param int $iActionCode see UR_ACTION_* constants

View File

@@ -404,7 +404,8 @@ class ValueSetObjects extends ValueSetDefinition
if (count($aAdditionalField) > 0) {
$aArguments = [];
foreach ($aAdditionalField as $sAdditionalField) {
array_push($aArguments, $oObject->Get($sAdditionalField));
$oAttrDef = MetaModel::GetAttributeDef(get_class($oObject), $sAdditionalField);
array_push($aArguments, $oAttrDef->GetValueLabel($oObject->Get($sAdditionalField)));
}
$aData['additional_field'] = utils::VSprintf($sFormatAdditionalField, $aArguments);
} else {

View File

@@ -19,8 +19,6 @@ $ibo-badge-colors: (
'orange' : ($ibo-color-orange-100, $ibo-color-orange-900),
'red': ($ibo-color-red-100, $ibo-color-red-900),
'pink': ($ibo-color-pink-100, $ibo-color-pink-900),
'purple': ($ibo-color-purple-100, $ibo-color-purple-900),
'yellow': ($ibo-color-yellow-200, $ibo-color-yellow-900),
) !default;

View File

@@ -3,9 +3,9 @@
* @license http://opensource.org/licenses/AGPL-3.0
*/
$ibo-input-select-icon--max-height: 100% !default;
$ibo-input-select-icon--max-width: 100% !default;
$ibo-input-select-icon--padding-right: $ibo-spacing-200 !default;
$ibo-input-select-icon--menu--icon--max-height: 100% !default;
$ibo-input-select-icon--menu--icon--max-width: 100% !default;
$ibo-input-select-icon--icon--padding-right: $ibo-spacing-200 !default;
$ibo-input-select-icon--menu--z-index: 21 !default;
$ibo-input-select-icon--menu--max-height: 300px !default;
@@ -18,9 +18,9 @@ $ibo-input-select-icon--menu--icon--margin-right: 10px !default;
display: inline-flex;
text-align: left;
>img{
max-height: $ibo-input-select-icon--max-height;
max-width: $ibo-input-select-icon--max-width;
padding-right: $ibo-input-select-icon--padding-right;
max-height: $ibo-input-select-icon--menu--icon--max-height;
max-width: $ibo-input-select-icon--menu--icon--max-width;
padding-right: $ibo-input-select-icon--icon--padding-right;
}
>span{
overflow: hidden;

View File

@@ -4,7 +4,7 @@
*/
/* SCSS variables */
$common-has-description--content: "?" !default;
$common-has-description--content: "\1F6C8" !default;
$common-has-description--padding-left: $common-spacing-200 !default;
$common-has-description--color: $common-color-grey-600 !default;
$common-has-description--font-size: 0.7em !default; /* Font size is em on purpose as we want it to be proportional to its context */

View File

@@ -11,9 +11,6 @@
*
* Usage: @extend %common-font-size-XXX;
*/
%common-font-size-20 {
font-size: $common-font-size-20;
}
%common-font-size-50 {
font-size: $common-font-size-50;
}

File diff suppressed because one or more lines are too long

View File

@@ -611,6 +611,32 @@ body {
.setup-extension--missing .setup-extension--icon{
color:#a00000;
}
.setup-extension-tag {
display: inline-flex;
background-color: grey;
border-radius: 8px;
padding-left: 3px;
padding-right: 3px;
margin-right: 3px;
&.installed{
background-color:#9eff9e
}
&.notinstalled{
background-color:#ed9eff
}
&.tobeinstalled{
background-color:#9ef0ff
}
&.tobeuninstalled{
background-color:#ff9e9e
}
&.notuninstallable{
background-color:#ffc98c
}
&.removed{
background-color: #969594
}
}
.ibo-extension-details {
align-items: flex-start;

View File

@@ -8,6 +8,7 @@
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;
@@ -17,8 +18,7 @@ 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\DataFeatureRemoval\Service\StaticDeletionPlan;
use Combodo\iTop\Service\Session\SessionParameters;
use Combodo\iTop\Setup\FeatureRemoval\DryRemovalRuntimeEnvironment;
use Combodo\iTop\Setup\FeatureRemoval\SetupAudit;
use ContextTag;
use CoreException;
@@ -37,18 +37,15 @@ class DataFeatureRemovalController extends Controller
private array $aCountClassesToCleanup = [];
private array $aAnalysisDataTable = [];
private array $aDeletionExecutionSummary = [];
private ?RuntimeEnvironment $oRuntimeEnvironment = null;
private int $iCount = 0;
private int $iColumnCount = 2;
private RunTimeEnvironment $oRuntimeEnvironment;
public function OperationMain($sErrorMessage = null): void
{
$aParams = [];
SetupUtils::EraseSetupToken();
(new SessionParameters(SetupUtils::SESSION_PARAMETERS_NAME))->Erase();
$this->AddAnalyzeParams();
$aParams['sTransactionId'] = utils::GetNewTransactionId();
$aParams['iColumnCount'] = $this->iColumnCount;
@@ -127,11 +124,10 @@ class DataFeatureRemovalController extends Controller
$aRemovedExtensions = $this->aExtensionsToCheck['to_be_removed'];
$aHiddenInputs['removed_extensions'] = $this->ConvertIntoSetupFormat($aRemovedExtensions);
$aExtensionsNotUninstallable = $this->aExtensionsToCheck['extensions_not_uninstallable'];
$aHiddenInputs['extensions_not_uninstallable'] = $this->ConvertIntoSetupFormat($aExtensionsNotUninstallable);
}
$aRemoveExtensionCodes = array_keys($aRemovedExtensions);
$aParams['aAddedExtensions'] = $aAddedExtensions;
$aParams['aRemovedExtensions'] = $aRemovedExtensions;
@@ -143,24 +139,9 @@ class DataFeatureRemovalController extends Controller
$aParams['iColumnCount'] = $this->iColumnCount;
$aParams['aAvailableExtensions'] = $this->SplitArrayIntoColumns($this->GetExtensionsDiff($aAddedExtensions, $aRemovedExtensions), $this->iColumnCount);
//to make setup redirection work, we need to pass complex data structures to setup wizards (ie extension/module lists)
$sSourceEnv = MetaModel::GetEnvironment();
$this->oRuntimeEnvironment = new RunTimeEnvironment($sSourceEnv, false);
if ('[]' === $aHiddenInputs['selected_modules']) {
$oConfig = MetaModel::GetConfig();
$aSelectedExtensions = DataFeatureRemoverExtensionService::GetInstance()->GetExtensionMap()->GetSelectedExtensions($oConfig, array_keys($aAddedExtensions), array_keys($aRemovedExtensions));
$aHiddenInputs['selected_extensions'] = $this->ConvertIntoSetupFormat($aSelectedExtensions);
$aSelectedModules = []; // keep it to compile method
} else {
$aSelectedExtensions = json_decode($aHiddenInputs['selected_extensions'], true);
$aSelectedModules = json_decode($aHiddenInputs['selected_modules'], true);
}
$bForceCompilation = Session::Get('bForceCompilation', false);
try {
$this->Compile($aSelectedExtensions, array_keys($aRemovedExtensions), $aSelectedModules);
$aHiddenInputs['selected_modules'] = $this->ConvertIntoSetupFormat($aSelectedModules);
$this->Compile($aAddedExtensions, $aRemoveExtensionCodes, $bForceCompilation);
} catch (CoreException $e) {
$aParams['DataFeatureRemovalErrorMessage'] = $e->getHtmlDesc();
$this->DisplayPage($aParams, 'AnalysisResult');
@@ -171,6 +152,19 @@ class DataFeatureRemovalController extends Controller
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, array_keys($aAddedExtensions), array_keys($aRemovedExtensions));
$aHiddenInputs['selected_extensions'] = $this->ConvertIntoSetupFormat($aSelectedExtensions);
$oRunTimeEnvironment = $this->GetRuntimeEnvironment($aAddedExtensions, $aRemovedExtensions);
$aSearchDirs = [$oRunTimeEnvironment->GetBuildDir()];
$aSelectedModules = $oRunTimeEnvironment->GetModulesToLoadFromChoices($oConfig, $aSelectedExtensions, $aSearchDirs);
$aHiddenInputs['selected_modules'] = $this->ConvertIntoSetupFormat($aSelectedModules);
}
$sSourceEnv = MetaModel::GetEnvironment();
$oSetupAudit = new SetupAudit($sSourceEnv);
$aGetRemovedClasses = array_keys($oSetupAudit->RunDataAudit());
DataFeatureRemovalLog::Debug(__METHOD__, null, ['aGetRemovedClasses' => $aGetRemovedClasses]);
@@ -185,7 +179,7 @@ class DataFeatureRemovalController extends Controller
];
foreach ($aHiddenInputs as $sInputName => $sInputValue) {
$aParams['aSetupParams'][$sInputName] = $sInputValue;
$aParams['aSetupParams']["_params[$sInputName]"] = $sInputValue;
}
[$aParams['aDeletionPlanSummary'], $aParams['iQueryCount'], $aParams['bDeletionPossible']] = $this->GetDeletionPlanSummaryTable($aGetRemovedClasses);
@@ -194,7 +188,6 @@ class DataFeatureRemovalController extends Controller
Session::Set('aDeletionExecutionSummary', serialize($this->aDeletionExecutionSummary));
if (!$aParams['bDeletionNeeded']) {
// Erase session setup parameters
SetupUtils::CreateSetupToken();
}
@@ -212,15 +205,14 @@ class DataFeatureRemovalController extends Controller
}
/**
* @param array $aSelectedExtensions
* @param array $aRemovedExtensions
* @param array $aSelectedModules
*
* @return void
* @throws \ConfigException
* @throws \CoreException
* @param array $aAddedExtensions
* @param array $aRemovedExtensions
* @param bool $bForceCompilation
* @return void
* @throws \ConfigException
* @throws \CoreException
*/
private function Compile(array $aSelectedExtensions, array $aRemovedExtensions, array &$aSelectedModules): void
private function Compile(array $aAddedExtensions, array $aRemovedExtensions, bool $bForceCompilation = true): void
{
$sSourceEnv = MetaModel::GetEnvironment();
$sBuildDir = APPROOT."/env-$sSourceEnv-build";
@@ -228,28 +220,27 @@ class DataFeatureRemovalController extends Controller
SetupUtils::builddir($sBuildDir);
}
$bIsDirEmpty = count(scandir($sBuildDir)) === 2;
$bForceCompilation = Session::Get('bForceCompilation', false);
$oConfig = MetaModel::GetConfig();
if ($bIsDirEmpty || $bForceCompilation) {
Session::Unset('bForceCompilation');
$this->oRuntimeEnvironment->CopySetupFiles();
if (count($aSelectedModules) === 0) {
$aSelectedModules = $this->oRuntimeEnvironment->GetModulesToLoadFromChoices($oConfig, $aSelectedExtensions);
}
DataFeatureRemovalLog::Debug(
__METHOD__,
null,
['sSourceEnv' => $sSourceEnv, 'sBuildDir' => $sBuildDir, 'bIsDirEmpty' => $bIsDirEmpty, glob("$sBuildDir/*")]
);
$this->oRuntimeEnvironment->DoCompile($aSelectedExtensions, $aRemovedExtensions, $aSelectedModules, MFCompiler::CanUseSymbolicLinks());
} else {
if (count($aSelectedModules) === 0) {
$aSelectedModules = $this->oRuntimeEnvironment->GetModulesToLoadFromChoices($oConfig, $aSelectedExtensions);
}
$this->GetRuntimeEnvironment($aAddedExtensions, $aRemovedExtensions)->CompileFrom($sSourceEnv);
}
}
private function GetRuntimeEnvironment(array $aAddedExtensions, array $aRemovedExtensions): RunTimeEnvironment
{
if (is_null($this->oRuntimeEnvironment)) {
$sSourceEnv = MetaModel::GetEnvironment();
$this->oRuntimeEnvironment = new DryRemovalRuntimeEnvironment($sSourceEnv, $aAddedExtensions, $aRemovedExtensions);
}
return $this->oRuntimeEnvironment;
}
private function GetExecutionSummaryTable(): array
{
$sName = 'ExcutionSummary';
@@ -281,7 +272,7 @@ class DataFeatureRemovalController extends Controller
private function GetDeletionPlanSummaryTable(array $aRemovedClasses): array
{
$sName = 'DeletionPlanSummary';
$oDataCleanupService = new StaticDeletionPlan();
$oDataCleanupService = new DataCleanupService();
$aDeletionPlanSummaryEntities = $oDataCleanupService->GetCleanupSummary($aRemovedClasses);
$aColumns = ['Class', 'Delete Count' , 'Update Count', 'Issue Count'];
$aRows = [];
@@ -347,7 +338,6 @@ class DataFeatureRemovalController extends Controller
'uninstallable' => $oExtension->CanBeUninstalled(),
'remote' => $oExtension->IsRemote(),
'missing' => $oExtension->bRemovedFromDisk,
'dependency_issue' => $oExtension->HasDependencyIssue(),
],
];
@@ -428,7 +418,6 @@ class DataFeatureRemovalController extends Controller
$this->aExtensionsToCheck = [
'to_be_installed' => [],
'to_be_removed' => [],
'extensions_not_uninstallable' => [],
];
foreach ($aAvailableExtensions as $sCode => &$aExtensionData) {
if (!isset($aSelectedExtensionsFromUI[$sCode])) {
@@ -442,9 +431,6 @@ class DataFeatureRemovalController extends Controller
if (! $this->bForcedUninstallation && $aExtensionData['extra_flags']['uninstallable']) {
$this->bForcedUninstallation = true;
}
if (false === $aExtensionData['extra_flags']['uninstallable'] || true === $aExtensionData['extra_flags']['remote']) {
$this->aExtensionsToCheck['extensions_not_uninstallable'][] = $sCode;
}
} elseif (!$aExtensionData['installed'] && $aSelectedExtensionsFromUI[$sCode] === 'on') {
$aExtensionData['extra_flags']['selected'] = true;
$sLabel = $aAvailableExtensions[$sCode]['label'];

View File

@@ -1,37 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\DataFeatureRemoval\Entity;
class DeletionPlanEntity
{
public readonly DeletionPlanItem $oDelete;
public readonly DeletionPlanItem $oUpdate;
public readonly DeletionPlanItem $oIssue;
/**
* @param \Combodo\iTop\DataFeatureRemoval\Entity\DeletionPlanItem $oDelete
* @param \Combodo\iTop\DataFeatureRemoval\Entity\DeletionPlanItem $oUpdate
* @param \Combodo\iTop\DataFeatureRemoval\Entity\DeletionPlanItem $oIssue
*/
public function __construct()
{
$this->oDelete = $oDelete ?? new DeletionPlanItem();
$this->oUpdate = $oUpdate ?? new DeletionPlanItem();
$this->oIssue = $oIssue ?? new DeletionPlanItem();
}
public function TotalCount(): int
{
return $this->oDelete->Count() + $this->oUpdate->Count() + $this->oIssue->Count();
}
public function FilterUpdatesByDeletes()
{
$this->oUpdate->FilterBy($this->oDelete);
}
}

View File

@@ -1,36 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\DataFeatureRemoval\Entity;
class DeletionPlanItem
{
public array $aIds = [];
/**
* @param array $aIds
*/
public function __construct(array $aIds = [])
{
$this->aIds = $aIds;
}
public function Merge(DeletionPlanItem $oItem): void
{
$this->aIds = array_unique(array_merge($this->aIds, $oItem->aIds));
}
public function Count(): int
{
return count($this->aIds);
}
public function FilterBy(DeletionPlanItem $oItem): void
{
$this->aIds = array_diff($this->aIds, $oItem->aIds);
}
}

View File

@@ -134,6 +134,10 @@ class DataCleanupService
/** @var DBObject $oDependentObj */
while ($oDependentObj = $oSet->Fetch()) {
$iDeletePropagationOption = $oExtKeyAttDef->GetDeletionPropagationOption();
if ($iDeletePropagationOption == DEL_MANUAL) {
$this->oObjectService->SetIssue(get_class($oDependentObj));
continue;
}
if ($oExtKeyAttDef->IsNullAllowed()) {
// Optional external key, list to reset
@@ -148,12 +152,6 @@ class DataCleanupService
return false;
}
} else {
// Mandatory external key
if ($iDeletePropagationOption == DEL_MANUAL) {
// Cannot be deleted automatically, must be handled manually
$this->oObjectService->SetIssue(get_class($oDependentObj));
continue;
}
// Propagate deletion only if not visited
if ($this->IsVisited($oDependentObj)) {
continue;

View File

@@ -1,221 +0,0 @@
<?php
/*
* @copyright Copyright (C) 2010-2026 Combodo SAS
* @license http://opensource.org/licenses/AGPL-3.0
*/
namespace Combodo\iTop\DataFeatureRemoval\Service;
use CMDBSource;
use Combodo\iTop\DataFeatureRemoval\Entity\DataCleanupSummaryEntity;
use Combodo\iTop\DataFeatureRemoval\Entity\DeletionPlanEntity;
use Combodo\iTop\DataFeatureRemoval\Entity\DeletionPlanItem;
use MetaModel;
class StaticDeletionPlan
{
/** @var array<DeletionPlanEntity> */
private array $aDeletionPlan = [];
/**
* Get a summary of the deletion plan computed for the classes.
* The result is used for display
*
* @param array|null $aClasses
*
* @return array<\Combodo\iTop\DataFeatureRemoval\Entity\DataCleanupSummaryEntity>
* @throws \CoreException
*/
public function GetCleanupSummary(?array $aClasses): array
{
$aSummary = [];
$aDeletionPlan = $this->GetStaticDeletionPlan($aClasses ?? []);
foreach ($aDeletionPlan as $sClass => $oDeletionPlanEntity) {
if ($oDeletionPlanEntity->TotalCount() === 0) {
continue;
}
$oDeletionPlanEntity->FilterUpdatesByDeletes();
$oDataCleanupSummary = new DataCleanupSummaryEntity($sClass);
$oDataCleanupSummary->iUpdateCount = $oDeletionPlanEntity->oUpdate->Count();
$oDataCleanupSummary->iDeleteCount = $oDeletionPlanEntity->oDelete->Count();
$oDataCleanupSummary->iIssueCount = $oDeletionPlanEntity->oIssue->Count();
$aSummary[$sClass] = $oDataCleanupSummary;
}
return $aSummary;
}
/**
* @param array $aClasses Classes to clean entirely
*
* @return array ['class' => DeletionPlanEntity];
*
* @throws \CoreException
*/
public function GetStaticDeletionPlan(array $aClasses): array
{
foreach ($aClasses as $sClass) {
$oDeletionPlanItem = $this->GetInitialClassDeletionPlan($sClass);
// N°9831 Do not overwrite existing entity as it may already exist for this class if a previously processed class references it (issues/updates already accumulated must be kept)
if (false === array_key_exists($sClass, $this->aDeletionPlan)) {
$this->aDeletionPlan[$sClass] = new DeletionPlanEntity();
}
$this->aDeletionPlan[$sClass]->oDelete->Merge($oDeletionPlanItem);
$this->DeletionPlanForReferencingClasses($sClass);
}
return $this->aDeletionPlan;
}
private function DeletionPlanForReferencingClasses(string $sClass): void
{
$sIdsToRemove = implode(', ', $this->aDeletionPlan[$sClass]->oDelete->aIds);
$aReferencingMe = MetaModel::EnumReferencingClasses($sClass);
foreach ($aReferencingMe as $sRemoteClass => $aExtKeys) {
if (!isset($this->aDeletionPlan[$sRemoteClass])) {
$this->aDeletionPlan[$sRemoteClass] = new DeletionPlanEntity();
}
$oDeletionPlanEntity = $this->aDeletionPlan[$sRemoteClass];
/** @var \AttributeExternalKey $oExtKeyAttDef */
foreach ($aExtKeys as $sExtKeyAttCode => $oExtKeyAttDef) {
// skip if this external key is behind an external field
if (!$oExtKeyAttDef->IsExternalKey(EXTKEY_ABSOLUTE)) {
continue;
}
if ($oExtKeyAttDef->IsNullAllowed()) {
// update
$oUpdateItem = $this->UpdateExtKeyNullable($sRemoteClass, $sExtKeyAttCode, $sIdsToRemove);
$oDeletionPlanEntity->oUpdate->Merge($oUpdateItem);
} else {
// delete
$aRemoteIdsToRemove = $this->GetRemoteIdsForExtKey($sRemoteClass, $sExtKeyAttCode, $sIdsToRemove);
$iDeletePropagationOption = $oExtKeyAttDef->GetDeletionPropagationOption();
if ($iDeletePropagationOption == DEL_MANUAL) {
// Issue, do not recurse
$oDeletionPlanItem = new DeletionPlanItem(aIds: $aRemoteIdsToRemove);
$oDeletionPlanEntity->oIssue->Merge($oDeletionPlanItem);
continue;
}
if (($iDeletePropagationOption == DEL_MOVEUP) && ($oExtKeyAttDef->IsHierarchicalKey())) {
// update hierarchical keys due to row cleanup in the same table
$sTargetIdsToRemove = implode(',', $this->aDeletionPlan[$sRemoteClass]->oDelete->aIds);
$oUpdateItem = $this->UpdateHierarchicalExtKey($sRemoteClass, $sExtKeyAttCode, $sTargetIdsToRemove);
$oDeletionPlanEntity->oUpdate->Merge($oUpdateItem);
}
// Delete entries in Remote Class
if (count($aRemoteIdsToRemove) !== 0) {
$oDeletionPlanEntity->oDelete->Merge(new DeletionPlanItem($aRemoteIdsToRemove));
// Infinite loops do not occurs due to the datamodel structure
$this->DeletionPlanForReferencingClasses($sRemoteClass);
}
}
}
}
}
/**
* @param string $sRemoteClass
* @param string $sExtKeyAttCode
* @param string $sIdsToRemoveInTargetClass
*
* @return \Combodo\iTop\DataFeatureRemoval\Entity\DeletionPlanItem
* @throws \CoreException
*/
public function UpdateExtKeyNullable(string $sRemoteClass, string $sExtKeyAttCode, string $sIdsToRemoveInTargetClass): DeletionPlanItem
{
$aIds = $this->GetRemoteIdsForExtKey($sRemoteClass, $sExtKeyAttCode, $sIdsToRemoveInTargetClass);
return new DeletionPlanItem($aIds);
}
/**
* @param string $sRemoteClass
* @param string $sExtKeyAttCode
* @param string $sIdsToRemoveInTargetClass
*
* @return \Combodo\iTop\DataFeatureRemoval\Entity\DeletionPlanItem
* @throws \CoreException
* @throws \MySQLException
*/
public function UpdateHierarchicalExtKey(string $sRemoteClass, string $sExtKeyAttCode, string $sIdsToRemoveInTargetClass): DeletionPlanItem
{
[$sDBTable, $sDBField, $sDBKey] = $this->GetDBInfoForAttcode($sRemoteClass, $sExtKeyAttCode);
$sSQL = <<<SQL
SELECT `$sDBKey`
FROM `$sDBTable` AS `updated`
INNER JOIN `$sDBTable` AS `removed` ON `updated`.`$sDBField` = `removed`.`$sDBKey`
WHERE `removed`.`$sDBKey` IN ($sIdsToRemoveInTargetClass)
SQL;
$aIds = CMDBSource::QueryToCol($sSQL, $sDBKey);
return new DeletionPlanItem($aIds);
}
/**
* @param string $sRemoteClass
* @param string $sExtKeyAttCode
* @param string $sIdsToRemoveInTargetClass
*
* @return array
* @throws \CoreException
* @throws \MySQLException
*/
public function GetRemoteIdsForExtKey(string $sRemoteClass, string $sExtKeyAttCode, string $sIdsToRemoveInTargetClass): array
{
if (\utils::IsNullOrEmptyString($sIdsToRemoveInTargetClass)) {
return [];
}
[$sDBTable, $sDBField, $sDBKey] = $this->GetDBInfoForAttcode($sRemoteClass, $sExtKeyAttCode);
$sSQL = "SELECT `$sDBKey` FROM `$sDBTable` WHERE `$sDBField` IN ($sIdsToRemoveInTargetClass)";
return CMDBSource::QueryToCol($sSQL, $sDBKey);
}
/**
* @param string $sClass
*
* @return \Combodo\iTop\DataFeatureRemoval\Entity\DeletionPlanItem
* @throws \CoreException
* @throws \MySQLException
*/
public function GetInitialClassDeletionPlan(string $sClass): DeletionPlanItem
{
$sTable = MetaModel::DBGetTable($sClass);
$sDBKey = MetaModel::DBGetKey($sClass);
$sSQL = "SELECT `$sDBKey` FROM `$sTable`";
$aIds = CMDBSource::QueryToCol($sSQL, $sDBKey);
return new DeletionPlanItem($aIds);
}
/**
* Get database table for an attcode
*
* @param string $sClass
* @param string $sExtKeyAttCode
*
* @return array
* @throws \CoreException
* @throws \Exception
*/
public function GetDBInfoForAttcode(string $sClass, string $sExtKeyAttCode): array
{
$sOriginClass = MetaModel::GetAttributeOrigin($sClass, $sExtKeyAttCode);
$sDBTable = MetaModel::DBGetTable($sOriginClass);
$oAttDef = MetaModel::GetAttributeDef($sOriginClass, $sExtKeyAttCode);
// External key is on a single DB column
$sDBField = array_keys($oAttDef->GetSQLColumns())[0];
$sDBKey = MetaModel::DBGetKey($sClass);
return [$sDBTable, $sDBField, $sDBKey];
}
}

View File

@@ -8,8 +8,6 @@ $baseDir = dirname($vendorDir);
return array(
'Combodo\\iTop\\DataFeatureRemoval\\Controller\\DataFeatureRemovalController' => $baseDir . '/src/Controller/DataFeatureRemovalController.php',
'Combodo\\iTop\\DataFeatureRemoval\\Entity\\DataCleanupSummaryEntity' => $baseDir . '/src/Entity/DataCleanupSummaryEntity.php',
'Combodo\\iTop\\DataFeatureRemoval\\Entity\\DeletionPlanEntity' => $baseDir . '/src/Entity/DeletionPlanEntity.php',
'Combodo\\iTop\\DataFeatureRemoval\\Entity\\DeletionPlanItem' => $baseDir . '/src/Entity/DeletionPlanItem.php',
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalConfig' => $baseDir . '/src/Helper/DataFeatureRemovalConfig.php',
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalException' => $baseDir . '/src/Helper/DataFeatureRemovalException.php',
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalHelper' => $baseDir . '/src/Helper/DataFeatureRemovalHelper.php',
@@ -18,7 +16,6 @@ return array(
'Combodo\\iTop\\DataFeatureRemoval\\Service\\DataFeatureRemoverExtensionService' => $baseDir . '/src/Service/DataFeatureRemoverExtensionService.php',
'Combodo\\iTop\\DataFeatureRemoval\\Service\\ObjectService' => $baseDir . '/src/Service/ObjectService.php',
'Combodo\\iTop\\DataFeatureRemoval\\Service\\ObjectServiceSummary' => $baseDir . '/src/Service/ObjectServiceSummary.php',
'Combodo\\iTop\\DataFeatureRemoval\\Service\\StaticDeletionPlan' => $baseDir . '/src/Service/StaticDeletionPlan.php',
'Combodo\\iTop\\DataFeatureRemoval\\Service\\iObjectService' => $baseDir . '/src/Service/iObjectService.php',
'Composer\\InstalledVersions' => $vendorDir . '/composer/InstalledVersions.php',
);

View File

@@ -23,8 +23,6 @@ class ComposerStaticInit4f96a7199e2c0d90e547333758b26464
public static $classMap = array (
'Combodo\\iTop\\DataFeatureRemoval\\Controller\\DataFeatureRemovalController' => __DIR__ . '/../..' . '/src/Controller/DataFeatureRemovalController.php',
'Combodo\\iTop\\DataFeatureRemoval\\Entity\\DataCleanupSummaryEntity' => __DIR__ . '/../..' . '/src/Entity/DataCleanupSummaryEntity.php',
'Combodo\\iTop\\DataFeatureRemoval\\Entity\\DeletionPlanEntity' => __DIR__ . '/../..' . '/src/Entity/DeletionPlanEntity.php',
'Combodo\\iTop\\DataFeatureRemoval\\Entity\\DeletionPlanItem' => __DIR__ . '/../..' . '/src/Entity/DeletionPlanItem.php',
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalConfig' => __DIR__ . '/../..' . '/src/Helper/DataFeatureRemovalConfig.php',
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalException' => __DIR__ . '/../..' . '/src/Helper/DataFeatureRemovalException.php',
'Combodo\\iTop\\DataFeatureRemoval\\Helper\\DataFeatureRemovalHelper' => __DIR__ . '/../..' . '/src/Helper/DataFeatureRemovalHelper.php',
@@ -33,7 +31,6 @@ class ComposerStaticInit4f96a7199e2c0d90e547333758b26464
'Combodo\\iTop\\DataFeatureRemoval\\Service\\DataFeatureRemoverExtensionService' => __DIR__ . '/../..' . '/src/Service/DataFeatureRemoverExtensionService.php',
'Combodo\\iTop\\DataFeatureRemoval\\Service\\ObjectService' => __DIR__ . '/../..' . '/src/Service/ObjectService.php',
'Combodo\\iTop\\DataFeatureRemoval\\Service\\ObjectServiceSummary' => __DIR__ . '/../..' . '/src/Service/ObjectServiceSummary.php',
'Combodo\\iTop\\DataFeatureRemoval\\Service\\StaticDeletionPlan' => __DIR__ . '/../..' . '/src/Service/StaticDeletionPlan.php',
'Combodo\\iTop\\DataFeatureRemoval\\Service\\iObjectService' => __DIR__ . '/../..' . '/src/Service/iObjectService.php',
'Composer\\InstalledVersions' => __DIR__ . '/..' . '/composer/InstalledVersions.php',
);

View File

@@ -90,6 +90,6 @@ Dict::Add('FR FR', 'French', 'Français', [
'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+' => 'Si coché, le fichier supprimé sera automatiquement joint à l\'email quand une action email sera lancée',
'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',
]);

View File

@@ -24,7 +24,7 @@ class TriggerOnAttachmentCreate extends TriggerOnObject
"category" => "grant_by_profile,core/cmdb,application",
"key_type" => "autoincrement",
"name_attcode" => "description",
"complementary_name_attcode" => ['finalclass', 'complement'],
"complementary_name_attcode" => ['finalclass', 'target_class'],
"state_attcode" => "",
"reconc_keys" => ['description'],
"db_table" => "priv_trigger_onattcreate",

View File

@@ -24,7 +24,7 @@ class TriggerOnAttachmentDelete extends TriggerOnObject
"category" => "grant_by_profile,core/cmdb,application",
"key_type" => "autoincrement",
"name_attcode" => "description",
"complementary_name_attcode" => ['finalclass', 'complement'],
"complementary_name_attcode" => ['finalclass', 'target_class'],
"state_attcode" => "",
"reconc_keys" => ['description'],
"db_table" => "priv_trigger_onattdelete",

View File

@@ -19,7 +19,7 @@ class TriggerOnAttachmentDownload extends TriggerOnAttributeBlobDownload
"category" => "grant_by_profile,core/cmdb,application",
"key_type" => "autoincrement",
"name_attcode" => "description",
"complementary_name_attcode" => ['finalclass', 'complement'],
"complementary_name_attcode" => ['finalclass', 'target_class'],
"state_attcode" => "",
"reconc_keys" => ['description'],
"db_table" => "priv_trigger_onattdownload",

View File

@@ -21,11 +21,11 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', [
'Menu:SearchChanges' => 'Hledat změny',
'Menu:SearchChanges+' => 'Hledat změnové tikety',
'Menu:Change:Shortcuts' => 'Odkazy',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => 'Změny čekající na přijetí',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Změny čekající na schválení',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:WaitingApproval+' => '',
'Menu:Changes' => 'Otevřené změny',
'Menu:Changes+' => 'Všechny otevřené změny',
'Menu:MyChanges' => 'Změny přidělené mně',

View File

@@ -20,11 +20,11 @@ Dict::Add('DA DA', 'Danish', 'Dansk', [
'Menu:SearchChanges' => 'Søg efter Changes',
'Menu:SearchChanges+' => 'Søg efter Change Tickets',
'Menu:Change:Shortcuts' => 'Genveje',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => 'Changes, som afventer accept',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Changes, som afventer godkendelse',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:WaitingApproval+' => '',
'Menu:Changes' => 'Offene Changes',
'Menu:Changes+' => 'Alle åbne Changes',
'Menu:MyChanges' => 'Mine Changes',

View File

@@ -19,8 +19,8 @@ Dict::Add('DE DE', 'German', 'Deutsch', [
'Menu:NewChange+' => 'Einen neuen Change erstellen',
'Menu:SearchChanges' => 'Suche nach Changes',
'Menu:SearchChanges+' => 'Unter den bestehenden Changes suchen',
'Menu:Change:Shortcuts' => 'Changes~~',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:Change:Shortcuts' => 'Shortcuts',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => 'Changes, die auf Annahme warten',
'Menu:WaitingAcceptance+' => 'Changes, die auf Annahme warten',
'Menu:WaitingApproval' => 'Changes, die auf Genehmigung warten',

View File

@@ -30,16 +30,16 @@ Dict::Add('EN US', 'English', 'English', [
'Menu:NewChange+' => 'Create a new change ticket',
'Menu:SearchChanges' => 'Search for changes',
'Menu:SearchChanges+' => 'Search for change tickets',
'Menu:Change:Shortcuts' => 'Changes',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes',
'Menu:Change:Shortcuts' => 'Shortcuts',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => 'Changes awaiting acceptance',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Changes awaiting approval',
'Menu:WaitingApproval+' => 'Changes in planned status',
'Menu:WaitingApproval+' => '',
'Menu:Changes' => 'Open changes',
'Menu:Changes+' => 'All changes which are not in closed status',
'Menu:Changes+' => 'All open changes',
'Menu:MyChanges' => 'Changes assigned to me',
'Menu:MyChanges+' => 'Non-closed changes assigned to me (as an Agent)',
'Menu:MyChanges+' => 'Changes assigned to me (as Agent)',
'UI-ChangeManagementOverview-ChangeByCategory-last-7-days' => 'Changes by category for the last 7 days',
'UI-ChangeManagementOverview-Last-7-days' => 'Number of changes for the last 7 days',
'UI-ChangeManagementOverview-ChangeByDomain-last-7-days' => 'Changes by domain for the last 7 days',

View File

@@ -30,16 +30,16 @@ Dict::Add('EN GB', 'British English', 'British English', [
'Menu:NewChange+' => 'Create a new change ticket',
'Menu:SearchChanges' => 'Search for changes',
'Menu:SearchChanges+' => 'Search for change tickets',
'Menu:Change:Shortcuts' => 'Changes~~',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:Change:Shortcuts' => 'Shortcuts',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => 'Changes awaiting acceptance',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Changes awaiting approval',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:WaitingApproval+' => '',
'Menu:Changes' => 'Open changes',
'Menu:Changes+' => 'All changes which are not in closed status',
'Menu:Changes+' => 'All open changes',
'Menu:MyChanges' => 'Changes assigned to me',
'Menu:MyChanges+' => 'Non-closed changes assigned to me (as an Agent)',
'Menu:MyChanges+' => 'Changes assigned to me (as Agent)',
'UI-ChangeManagementOverview-ChangeByCategory-last-7-days' => 'Changes by category for the last 7 days',
'UI-ChangeManagementOverview-Last-7-days' => 'Number of changes for the last 7 days',
'UI-ChangeManagementOverview-ChangeByDomain-last-7-days' => 'Changes by domain for the last 7 days',

View File

@@ -18,16 +18,16 @@ Dict::Add('FR FR', 'French', 'Français', [
'Menu:NewChange+' => 'Créer un nouveau ticket de changement',
'Menu:SearchChanges' => 'Rechercher des changements',
'Menu:SearchChanges+' => 'Rechercher parmi les tickets de changement',
'Menu:Change:Shortcuts' => 'Changements',
'Menu:Change:Shortcuts+' => 'Raccourcis vers différents groupes de changements',
'Menu:WaitingAcceptance' => 'En attente de validation',
'Menu:WaitingAcceptance+' => 'Changements à l\'état nouveau, en attente d\'acceptation',
'Menu:WaitingApproval' => 'En attente d\'approbation',
'Menu:WaitingApproval+' => 'Changements dans l\'état programmé, en attente d\'approbation',
'Menu:Changes' => 'En cours',
'Menu:Changes+' => 'Tickets de changement qui ne sont pas dans l\'état fermé',
'Menu:MyChanges' => 'Qui me sont assignés',
'Menu:MyChanges+' => 'Changements ni fermés, ni résolus, dont je suis l\'agent assigné',
'Menu:Change:Shortcuts' => 'Raccourcis',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => 'Changements en attente d\'acceptance',
'Menu:WaitingAcceptance+' => 'Changements en attente d\'acceptance',
'Menu:WaitingApproval' => 'Changements en attente d\'approbation',
'Menu:WaitingApproval+' => 'Changements en attente d\'approbation',
'Menu:Changes' => 'Changements ouverts',
'Menu:Changes+' => 'Tickets de changement ouverts',
'Menu:MyChanges' => 'Mes changements',
'Menu:MyChanges+' => 'Tickets de changement qui me sont assignés',
'UI-ChangeManagementOverview-ChangeByCategory-last-7-days' => 'Changements par catégorie',
'UI-ChangeManagementOverview-Last-7-days' => 'Changements par jour',
'UI-ChangeManagementOverview-ChangeByDomain-last-7-days' => 'Changements par domaine',

View File

@@ -19,11 +19,11 @@ Dict::Add('IT IT', 'Italian', 'Italiano', [
'Menu:SearchChanges' => 'Cerca per cambi',
'Menu:SearchChanges+' => 'Cerca i cambi per tickets',
'Menu:Change:Shortcuts' => 'Scorciatoie',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => 'Modifiche in attesa di accettazione',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Modifiche in attesa di approvazione',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:WaitingApproval+' => '',
'Menu:Changes' => 'Modifiche aperte',
'Menu:Changes+' => 'Tutte le Modifiche aperte',
'Menu:MyChanges' => 'Modifiche assegnate a me',

View File

@@ -19,13 +19,13 @@ Dict::Add('JA JP', 'Japanese', '日本語', [
'Menu:SearchChanges' => '変更検索',
'Menu:SearchChanges+' => '変更チケット検索',
'Menu:Change:Shortcuts' => 'ショートカット',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => '受理待ちの変更',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => '承認待ちの変更',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:WaitingApproval+' => '',
'Menu:Changes' => 'オープン状態の変更',
'Menu:Changes+' => 'All changes which are not in closed status~~',
'Menu:Changes+' => '',
'Menu:MyChanges' => '担当している変更',
'Menu:MyChanges+' => '担当している変更(エージェントとして)',
'UI-ChangeManagementOverview-ChangeByCategory-last-7-days' => '最近7日間のカテゴリ別の変更',

View File

@@ -21,11 +21,11 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', [
'Menu:SearchChanges' => 'Zoek naar changes',
'Menu:SearchChanges+' => 'Zoek naar changes',
'Menu:Change:Shortcuts' => 'Snelkoppelingen',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => 'Changes die acceptatie vereisen',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Changes die goedkeuring vereisen',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:WaitingApproval+' => '',
'Menu:Changes' => 'Open changes',
'Menu:Changes+' => 'Alle open changes',
'Menu:MyChanges' => 'Changes toegewezen aan mij',

View File

@@ -19,11 +19,11 @@ Dict::Add('PL PL', 'Polish', 'Polski', [
'Menu:SearchChanges' => 'Szukaj zmian',
'Menu:SearchChanges+' => 'Szukaj zgłoszeń zmian',
'Menu:Change:Shortcuts' => 'Skróty',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => 'Zmiany do akceptacji',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Zmiany do zatwierdzenia',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:WaitingApproval+' => '',
'Menu:Changes' => 'Otwarte zmiany',
'Menu:Changes+' => 'Wszystkie otwarte zmiany',
'Menu:MyChanges' => 'Zmiany przypisane do mnie',

View File

@@ -19,13 +19,13 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', [
'Menu:SearchChanges' => 'Pesquisar por mudanças',
'Menu:SearchChanges+' => 'Pesquisar por solicitações de mudança',
'Menu:Change:Shortcuts' => 'Atalhos',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => 'Mudanças aguardando aceitação',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Mudanças aguardando aprovação',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:WaitingApproval+' => '',
'Menu:Changes' => 'Mudanças abertas',
'Menu:Changes+' => 'All changes which are not in closed status~~',
'Menu:Changes+' => '',
'Menu:MyChanges' => 'Mudanças atribuídas a mim',
'Menu:MyChanges+' => 'Mudanças atribuídas a mim (como Agente)',
'UI-ChangeManagementOverview-ChangeByCategory-last-7-days' => 'Mudanças por categoria nos últimos 7 dias',

View File

@@ -23,11 +23,11 @@ Dict::Add('SK SK', 'Slovak', 'Slovenčina', [
'Menu:WaitingAcceptance' => 'Zmeny očakávajúce prijatie',
'Menu:WaitingAcceptance+' => '~~',
'Menu:WaitingApproval' => 'Zmeny očakávajúce schválenie',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:WaitingApproval+' => '~~',
'Menu:Changes' => 'Otvorené zmeny',
'Menu:Changes+' => 'All changes which are not in closed status~~',
'Menu:Changes+' => 'All open changes~~',
'Menu:MyChanges' => 'Zmeny pridelené mne',
'Menu:MyChanges+' => 'Non-closed changes assigned to me (as an Agent)~~',
'Menu:MyChanges+' => 'Changes assigned to me (as Agent)~~',
'UI-ChangeManagementOverview-ChangeByCategory-last-7-days' => 'Zmeny podľa kategórie za posledných 7 dní',
'UI-ChangeManagementOverview-Last-7-days' => 'Počet zmien za posledných 7 dní',
'UI-ChangeManagementOverview-ChangeByDomain-last-7-days' => 'Zmeny podľa domény za posledných 7 dní',

View File

@@ -20,13 +20,13 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', [
'Menu:SearchChanges' => 'Değişiklik ara',
'Menu:SearchChanges+' => 'Değişiklik isteği ara',
'Menu:Change:Shortcuts' => 'Kısayollar',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => 'Kabul bekleyen değişiklik talepleri',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Onay bekleyen değişiklik talepleri',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:WaitingApproval+' => '',
'Menu:Changes' => 'Açık değişiklikler',
'Menu:Changes+' => 'All changes which are not in closed status~~',
'Menu:Changes+' => '',
'Menu:MyChanges' => 'Bana atanan değişiklik istekleri',
'Menu:MyChanges+' => 'Bana atanan değişiklik istekleri',
'UI-ChangeManagementOverview-ChangeByCategory-last-7-days' => 'Son 7 gün için kategoriye göre değişiklikler',

View File

@@ -31,11 +31,11 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Menu:SearchChanges' => '搜索变更',
'Menu:SearchChanges+' => '搜索变更',
'Menu:Change:Shortcuts' => '快捷方式',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => '等待审核的变更',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => '等待批准的变更',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:WaitingApproval+' => '',
'Menu:Changes' => '所有打开的变更',
'Menu:Changes+' => '所有打开的变更',
'Menu:MyChanges' => '分配给我的变更',

View File

@@ -21,11 +21,11 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', [
'Menu:SearchChanges' => 'Hledat změny',
'Menu:SearchChanges+' => 'Hledat změnové tikety',
'Menu:Change:Shortcuts' => 'Odkazy',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => 'Změny čekající na přijetí',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Změny čekající na schválení',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:WaitingApproval+' => '',
'Menu:Changes' => 'Otevřené změny',
'Menu:Changes+' => 'Všechny otevřené změny',
'Menu:MyChanges' => 'Změny přidělené mně',

View File

@@ -20,13 +20,13 @@ Dict::Add('DA DA', 'Danish', 'Dansk', [
'Menu:SearchChanges' => 'Søg efter Changes',
'Menu:SearchChanges+' => '',
'Menu:Change:Shortcuts' => 'Genveje',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => 'Changes der afventer accept',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Changes der afventer godkendelse',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:WaitingApproval+' => '',
'Menu:Changes' => 'Åbne Changes',
'Menu:Changes+' => 'All changes which are not in closed status~~',
'Menu:Changes+' => '',
'Menu:MyChanges' => 'Changes tildelt til mig',
'Menu:MyChanges+' => '',
'UI-ChangeManagementOverview-ChangeByCategory-last-7-days' => 'Changes de sidste 7 dage efter kategori',

View File

@@ -19,8 +19,8 @@ Dict::Add('DE DE', 'German', 'Deutsch', [
'Menu:NewChange+' => 'Einen neuen Change erstellen',
'Menu:SearchChanges' => 'Suche nach Changes',
'Menu:SearchChanges+' => 'Unter den bestehenden Changes suchen',
'Menu:Change:Shortcuts' => 'Changes~~',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:Change:Shortcuts' => 'Shortcuts',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => 'Changes, die auf Annahme warten',
'Menu:WaitingAcceptance+' => 'Changes, die auf Annahme warten',
'Menu:WaitingApproval' => 'Changes, die auf Genehmigung warten',

View File

@@ -30,16 +30,16 @@ Dict::Add('EN US', 'English', 'English', [
'Menu:NewChange+' => 'Create a new change ticket',
'Menu:SearchChanges' => 'Search for changes',
'Menu:SearchChanges+' => 'Search for change tickets',
'Menu:Change:Shortcuts' => 'Changes',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes',
'Menu:WaitingAcceptance' => 'Awaiting acceptance',
'Menu:Change:Shortcuts' => 'Shortcuts',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => 'Changes awaiting acceptance',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Awaiting approval',
'Menu:WaitingApproval+' => 'Changes in planned status',
'Menu:Changes' => 'Open',
'Menu:Changes+' => 'All changes which are not in closed status',
'Menu:MyChanges' => 'Assigned to me',
'Menu:MyChanges+' => 'Non-closed changes assigned to me (as an Agent)',
'Menu:WaitingApproval' => 'Changes awaiting approval',
'Menu:WaitingApproval+' => '',
'Menu:Changes' => 'Open changes',
'Menu:Changes+' => 'All open changes',
'Menu:MyChanges' => 'Changes assigned to me',
'Menu:MyChanges+' => 'Changes assigned to me (as Agent)',
'UI-ChangeManagementOverview-ChangeByCategory-last-7-days' => 'Changes by category for the last 7 days',
'UI-ChangeManagementOverview-Last-7-days' => 'Number of changes for the last 7 days',
'UI-ChangeManagementOverview-ChangeByDomain-last-7-days' => 'Changes by domain for the last 7 days',

View File

@@ -30,16 +30,16 @@ Dict::Add('EN GB', 'British English', 'British English', [
'Menu:NewChange+' => 'Create a new change ticket',
'Menu:SearchChanges' => 'Search for changes',
'Menu:SearchChanges+' => 'Search for change tickets',
'Menu:Change:Shortcuts' => 'Changes~~',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:Change:Shortcuts' => 'Shortcuts',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => 'Changes awaiting acceptance',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Changes awaiting approval',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:WaitingApproval+' => '',
'Menu:Changes' => 'Open changes',
'Menu:Changes+' => 'All changes which are not in closed status',
'Menu:Changes+' => 'All open changes',
'Menu:MyChanges' => 'Changes assigned to me',
'Menu:MyChanges+' => 'Non-closed changes assigned to me (as an Agent)',
'Menu:MyChanges+' => 'Changes assigned to me (as Agent)',
'UI-ChangeManagementOverview-ChangeByCategory-last-7-days' => 'Changes by category for the last 7 days',
'UI-ChangeManagementOverview-Last-7-days' => 'Number of changes for the last 7 days',
'UI-ChangeManagementOverview-ChangeByDomain-last-7-days' => 'Changes by domain for the last 7 days',

View File

@@ -18,16 +18,16 @@ Dict::Add('FR FR', 'French', 'Français', [
'Menu:NewChange+' => 'Créer un nouveau ticket de changement',
'Menu:SearchChanges' => 'Rechercher des changements',
'Menu:SearchChanges+' => 'Rechercher parmi les tickets de changement',
'Menu:Change:Shortcuts' => 'Changements',
'Menu:Change:Shortcuts+' => 'Raccourcis vers différents groupes de changements',
'Menu:WaitingAcceptance' => 'En attente d\'acceptation',
'Menu:WaitingAcceptance+' => 'Changements en attente d\'acceptation',
'Menu:WaitingApproval' => 'En attente d\'approbation',
'Menu:WaitingApproval+' => 'Changements dans l\'état planifié',
'Menu:Changes' => 'En cours',
'Menu:Changes+' => 'Tickets de changement qui ne sont pas dans l\'état fermé',
'Menu:MyChanges' => 'Qui me sont assignés',
'Menu:MyChanges+' => 'Changements non fermés dont je suis l\'agent assigné',
'Menu:Change:Shortcuts' => 'Raccourcis',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => 'Changements en attente d\'acceptance',
'Menu:WaitingAcceptance+' => 'Changements en attente d\'acceptance',
'Menu:WaitingApproval' => 'Changement en attente d\'approbation',
'Menu:WaitingApproval+' => 'Changement en attente d\'approbation',
'Menu:Changes' => 'Changements ouverts',
'Menu:Changes+' => 'Tickets de changement ouverts',
'Menu:MyChanges' => 'Mes tickets de changement',
'Menu:MyChanges+' => 'Tickets de changement qui me sont assignés',
'UI-ChangeManagementOverview-ChangeByCategory-last-7-days' => 'Changements par catégorie',
'UI-ChangeManagementOverview-Last-7-days' => 'Changements par jour',
'UI-ChangeManagementOverview-ChangeByDomain-last-7-days' => 'Changements par domaine',

View File

@@ -23,7 +23,7 @@ Dict::Add('IT IT', 'Italian', 'Italiano', [
'Menu:WaitingAcceptance' => 'Modifiche in attesa di accettazione',
'Menu:WaitingAcceptance+' => '~~',
'Menu:WaitingApproval' => 'Modifiche in attesa di approvazione',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:WaitingApproval+' => '~~',
'Menu:Changes' => 'Modifiche aperte',
'Menu:Changes+' => 'Tutte le Modifiche aperte',
'Menu:MyChanges' => 'Modifiche assegnate a me',

View File

@@ -19,13 +19,13 @@ Dict::Add('JA JP', 'Japanese', '日本語', [
'Menu:SearchChanges' => '変更検索',
'Menu:SearchChanges+' => '',
'Menu:Change:Shortcuts' => 'ショートカット',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => '受け付け待ちの変更',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => '承認待ちの変更',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:WaitingApproval+' => '',
'Menu:Changes' => 'オープンな変更',
'Menu:Changes+' => 'All changes which are not in closed status~~',
'Menu:Changes+' => '',
'Menu:MyChanges' => '私に割り当てられた変更',
'Menu:MyChanges+' => '',
'UI-ChangeManagementOverview-ChangeByCategory-last-7-days' => '最近7日間のカテゴリ別の変更',

View File

@@ -21,11 +21,11 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', [
'Menu:SearchChanges' => 'Zoek naar changes',
'Menu:SearchChanges+' => 'Zoek naar changes',
'Menu:Change:Shortcuts' => 'Snelkoppelingen',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => 'Changes die acceptatie vereisen',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Changes die goedkeuring vereisen',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:WaitingApproval+' => '',
'Menu:Changes' => 'Open changes',
'Menu:Changes+' => 'Alle open changes',
'Menu:MyChanges' => 'Changes toegewezen aan mij',

View File

@@ -19,11 +19,11 @@ Dict::Add('PL PL', 'Polish', 'Polski', [
'Menu:SearchChanges' => 'Szukaj zmian',
'Menu:SearchChanges+' => 'Szukaj zgłoszeń zmian',
'Menu:Change:Shortcuts' => 'Skróty',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => 'Zmiany do akceptacji',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Zmiany do zatwierdzenia',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:WaitingApproval+' => '',
'Menu:Changes' => 'Otwarte zmiany',
'Menu:Changes+' => 'Wszystkie otwarte zmiany',
'Menu:MyChanges' => 'Zmiany przypisane do mnie',

View File

@@ -19,11 +19,11 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', [
'Menu:SearchChanges' => 'Pesquisar por mudanças',
'Menu:SearchChanges+' => 'Pesquisar por solicitações de mudanças',
'Menu:Change:Shortcuts' => 'Atalhos',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => 'Mudanças aguardando aceitação',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Mudanças aguardando aprovação',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:WaitingApproval+' => '',
'Menu:Changes' => 'Mudanças abertas',
'Menu:Changes+' => 'Todas as mudanças abertas',
'Menu:MyChanges' => 'Mudanças atribuídas a mim',

View File

@@ -23,11 +23,11 @@ Dict::Add('SK SK', 'Slovak', 'Slovenčina', [
'Menu:WaitingAcceptance' => 'Zmeny očakávajúce prijatie',
'Menu:WaitingAcceptance+' => '~~',
'Menu:WaitingApproval' => 'Zmeny očakávajúce schválenie',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:WaitingApproval+' => '~~',
'Menu:Changes' => 'Otvorené zmeny',
'Menu:Changes+' => 'All changes which are not in closed status~~',
'Menu:Changes+' => 'All open changes~~',
'Menu:MyChanges' => 'Zmeny pridelené mne',
'Menu:MyChanges+' => 'Non-closed changes assigned to me (as an Agent)~~',
'Menu:MyChanges+' => 'Changes assigned to me (as Agent)~~',
'UI-ChangeManagementOverview-ChangeByCategory-last-7-days' => 'Zmeny podľa kategórie za posledných 7 dní',
'UI-ChangeManagementOverview-Last-7-days' => 'Počet zmien za posledných 7 dní',
'UI-ChangeManagementOverview-ChangeByDomain-last-7-days' => 'Zmeny podľa domény za posledných 7 dní',

View File

@@ -23,9 +23,9 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', [
'Menu:WaitingAcceptance' => 'Kabul bekleyen değişiklik talepleri',
'Menu:WaitingAcceptance+' => '~~',
'Menu:WaitingApproval' => 'Onay bekleyen değişiklik talepleri',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:WaitingApproval+' => '~~',
'Menu:Changes' => 'Açık değişiklikler',
'Menu:Changes+' => 'All changes which are not in closed status~~',
'Menu:Changes+' => 'All open changes~~',
'Menu:MyChanges' => 'Bana atanan değişiklik istekleri',
'Menu:MyChanges+' => 'Bana atanan değişiklik istekleri',
'UI-ChangeManagementOverview-ChangeByCategory-last-7-days' => 'Son 7 gün için kategoriye göre değişiklikler',

View File

@@ -30,11 +30,11 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Menu:SearchChanges' => '搜索变更',
'Menu:SearchChanges+' => '搜索变更',
'Menu:Change:Shortcuts' => '快捷方式',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => '等待审核的变更',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => '等待批准的变更',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:WaitingApproval+' => '',
'Menu:Changes' => '所有打开的变更',
'Menu:Changes+' => '所有打开的变更',
'Menu:MyChanges' => '分配给我的变更',

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<Set>
<NetworkDeviceType alias="NetworkDeviceType" id="10">
<name>Router</name>
</NetworkDeviceType>
<NetworkDeviceType alias="NetworkDeviceType" id="11">
<name>Switch</name>
</NetworkDeviceType>
</Set>

View File

@@ -32,6 +32,7 @@ SetupWebPage::AddModule(
],
'data.sample' => [
'data/data.sample.model.xml',
'data/data.sample.networkdevicetype.xml',
'data/data.sample.servers.xml',
'data/data.sample.nw-devices.xml',
'data/data.sample.software.xml',
@@ -105,7 +106,6 @@ if (!class_exists('ConfigMgmtInstaller')) {
*/
public static function AfterDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
{
}
}
}

View File

@@ -242,7 +242,8 @@ class AjaxController extends Controller
throw new SecurityException('Access forbidden');
}
SetupUtils::CreateSetupToken();
$sConfigFile = APPCONF.'production/config-itop.php';
@chmod($sConfigFile, 0770); // Allow overwriting the file
header('Location: ../setup/');
}

View File

@@ -166,6 +166,8 @@ class UpdateController extends Controller
public function OperationRunSetup()
{
SetupUtils::CheckSetupToken(true);
$sConfigFile = APPCONF.'production/'.ITOP_CONFIG_FILE;
@chmod($sConfigFile, 0770);
$sRedirectURL = utils::GetAbsoluteUrlAppRoot().'setup/index.php';
header("Location: $sRedirectURL");
}

View File

@@ -46,10 +46,10 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', [
]);
Dict::Add('CS CZ', 'Czech', 'Čeština', [
'Menu:ProblemManagement' => 'Správa problémů',
'Menu:ProblemManagement+' => 'An ITIL process that identifies root causes of incidents, documents Known Errors and FAQs, in order to reduce helpdesk workload~~',
'Menu:ProblemManagement+' => 'Správa problémů',
'Menu:Problem:Shortcuts' => 'Odkazy',
'Menu:FAQCategory' => 'Kategorie FAQ',
'Menu:FAQCategory+' => 'A typology to categorize frequently asked questions (FAQ)~~',
'Menu:FAQCategory+' => '',
'Menu:FAQ' => 'FAQ',
'Menu:FAQ+' => 'FAQ - Často kladené dotazy',
'Brick:Portal:FAQ:Menu' => 'FAQ',

View File

@@ -45,10 +45,10 @@ Dict::Add('DA DA', 'Danish', 'Dansk', [
]);
Dict::Add('DA DA', 'Danish', 'Dansk', [
'Menu:ProblemManagement' => 'Problem Management',
'Menu:ProblemManagement+' => 'An ITIL process that identifies root causes of incidents, documents Known Errors and FAQs, in order to reduce helpdesk workload~~',
'Menu:ProblemManagement+' => 'Problem Management',
'Menu:Problem:Shortcuts' => 'Genvej',
'Menu:FAQCategory' => 'FAQ-Kategorier',
'Menu:FAQCategory+' => 'A typology to categorize frequently asked questions (FAQ)~~',
'Menu:FAQCategory+' => '',
'Menu:FAQ' => 'FAQs',
'Menu:FAQ+' => '',
'Brick:Portal:FAQ:Menu' => 'FAQ~~',

View File

@@ -45,10 +45,10 @@ Dict::Add('DE DE', 'German', 'Deutsch', [
]);
Dict::Add('DE DE', 'German', 'Deutsch', [
'Menu:ProblemManagement' => 'Problem Management',
'Menu:ProblemManagement+' => 'An ITIL process that identifies root causes of incidents, documents Known Errors and FAQs, in order to reduce helpdesk workload~~',
'Menu:ProblemManagement+' => 'Problem Management',
'Menu:Problem:Shortcuts' => 'Shortcuts',
'Menu:FAQCategory' => 'FAQ-Kategorien',
'Menu:FAQCategory+' => 'A typology to categorize frequently asked questions (FAQ)~~',
'Menu:FAQCategory+' => '',
'Menu:FAQ' => 'FAQs',
'Menu:FAQ+' => '',
'Brick:Portal:FAQ:Menu' => 'FAQ',

View File

@@ -85,12 +85,12 @@ Dict::Add('EN US', 'English', 'English', [
]);
Dict::Add('EN US', 'English', 'English', [
'Menu:ProblemManagement' => 'Problem management',
'Menu:ProblemManagement+' => 'An ITIL process that identifies root causes of incidents, documents Known Errors and FAQs, in order to reduce helpdesk workload',
'Menu:ProblemManagement+' => 'Problem management',
'Menu:Problem:Shortcuts' => 'Shortcuts',
'Menu:FAQCategory' => 'FAQ categories',
'Menu:FAQCategory+' => 'A typology to categorize frequently asked questions (FAQ)',
'Menu:FAQCategory+' => 'All FAQ categories',
'Menu:FAQ' => 'FAQs',
'Menu:FAQ+' => 'All Frequently Asked Questions',
'Menu:FAQ+' => 'All FAQs',
'Brick:Portal:FAQ:Menu' => 'FAQ',
'Brick:Portal:FAQ:Title' => 'Frequently Asked Questions',
'Brick:Portal:FAQ:Title+' => '<p>In a hurry?</p><p>Check out the list of most common questions and (maybe) find the expected answer right away.</p>',

View File

@@ -85,12 +85,12 @@ Dict::Add('EN GB', 'British English', 'British English', [
]);
Dict::Add('EN GB', 'British English', 'British English', [
'Menu:ProblemManagement' => 'Problem management',
'Menu:ProblemManagement+' => 'An ITIL process that identifies root causes of incidents, documents Known Errors and FAQs, in order to reduce helpdesk workload~~',
'Menu:ProblemManagement+' => 'Problem management',
'Menu:Problem:Shortcuts' => 'Shortcuts',
'Menu:FAQCategory' => 'FAQ categories',
'Menu:FAQCategory+' => 'A typology to categorize frequently asked questions (FAQ)',
'Menu:FAQCategory+' => 'All FAQ categories',
'Menu:FAQ' => 'FAQs',
'Menu:FAQ+' => 'All Frequently Asked Questions',
'Menu:FAQ+' => 'All FAQs',
'Brick:Portal:FAQ:Menu' => 'FAQ',
'Brick:Portal:FAQ:Title' => 'Frequently Asked Questions',
'Brick:Portal:FAQ:Title+' => '<p>In a hurry?</p><p>Check out the list of most common questions and (maybe) find the expected answer right away.</p>',

View File

@@ -42,7 +42,7 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', [
]);
Dict::Add('ES CR', 'Spanish', 'Español, Castellano', [
'Menu:ProblemManagement' => 'Administración de Problemas',
'Menu:ProblemManagement+' => 'An ITIL process that identifies root causes of incidents, documents Known Errors and FAQs, in order to reduce helpdesk workload~~',
'Menu:ProblemManagement+' => 'GestAdministraciónión de problemas',
'Menu:Problem:Shortcuts' => 'Acceso Rápido',
'Menu:FAQCategory' => 'Categorías de FAQ',
'Menu:FAQCategory+' => 'Categorías FAQ',

View File

@@ -36,7 +36,7 @@ Dict::Add('FR FR', 'French', 'Français', [
Dict::Add('FR FR', 'French', 'Français', [
'Class:FAQCategory' => 'Catégorie de FAQ',
'Class:FAQCategory+' => 'Segmentation de la Foire Aux Questions (FAQ)',
'Class:FAQCategory+' => 'Typologie. Segmentation des Questions fréquement posées (FAQ)',
'Class:FAQCategory/Attribute:name' => 'Nom',
'Class:FAQCategory/Attribute:name+' => '',
'Class:FAQCategory/Attribute:faq_list' => 'FAQs',
@@ -50,7 +50,7 @@ Dict::Add('FR FR', 'French', 'Français', [
]);
Dict::Add('FR FR', 'French', 'Français', [
'Menu:ProblemManagement' => 'Gestion des problèmes',
'Menu:ProblemManagement+' => 'Un processus ITIL qui identifie la cause des incidents répétitifs, documente les Erreurs connues et les FAQs, afin de réduire la charge de travail du heldesk',
'Menu:ProblemManagement+' => 'Gestion des problèmes',
'Menu:Problem:Shortcuts' => 'Raccourcis',
'Menu:FAQCategory' => 'Catégories de FAQ',
'Menu:FAQCategory+' => 'Toutes les catégories de FAQ',

View File

@@ -44,7 +44,7 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', [
]);
Dict::Add('HU HU', 'Hungarian', 'Magyar', [
'Menu:ProblemManagement' => 'Problémakezelés',
'Menu:ProblemManagement+' => 'An ITIL process that identifies root causes of incidents, documents Known Errors and FAQs, in order to reduce helpdesk workload~~',
'Menu:ProblemManagement+' => '',
'Menu:Problem:Shortcuts' => 'Gyorsgombok',
'Menu:FAQCategory' => 'Tudástár kategória',
'Menu:FAQCategory+' => 'Tudástár kategóriák',

View File

@@ -44,7 +44,7 @@ Dict::Add('IT IT', 'Italian', 'Italiano', [
]);
Dict::Add('IT IT', 'Italian', 'Italiano', [
'Menu:ProblemManagement' => 'Gestione dei problemi',
'Menu:ProblemManagement+' => 'An ITIL process that identifies root causes of incidents, documents Known Errors and FAQs, in order to reduce helpdesk workload~~',
'Menu:ProblemManagement+' => 'Gestione dei problemi',
'Menu:Problem:Shortcuts' => 'Scorciatoia',
'Menu:FAQCategory' => 'Categoria FAQ',
'Menu:FAQCategory+' => 'Tutte le categorie FAQ',

View File

@@ -44,7 +44,7 @@ Dict::Add('JA JP', 'Japanese', '日本語', [
]);
Dict::Add('JA JP', 'Japanese', '日本語', [
'Menu:ProblemManagement' => '問題管理',
'Menu:ProblemManagement+' => 'An ITIL process that identifies root causes of incidents, documents Known Errors and FAQs, in order to reduce helpdesk workload~~',
'Menu:ProblemManagement+' => '問題管理',
'Menu:Problem:Shortcuts' => 'ショートカット',
'Menu:FAQCategory' => 'FAQカテゴリ',
'Menu:FAQCategory+' => '全てのFAQカテゴリ',

View File

@@ -46,7 +46,7 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', [
]);
Dict::Add('NL NL', 'Dutch', 'Nederlands', [
'Menu:ProblemManagement' => 'Probleem Management',
'Menu:ProblemManagement+' => 'An ITIL process that identifies root causes of incidents, documents Known Errors and FAQs, in order to reduce helpdesk workload~~',
'Menu:ProblemManagement+' => 'Probleem Management',
'Menu:Problem:Shortcuts' => 'Snelkoppelingen',
'Menu:FAQCategory' => 'FAQ-categorieën',
'Menu:FAQCategory+' => 'Alle FAQ-categorieën',

View File

@@ -44,7 +44,7 @@ Dict::Add('PL PL', 'Polish', 'Polski', [
]);
Dict::Add('PL PL', 'Polish', 'Polski', [
'Menu:ProblemManagement' => 'Zarządzanie problemami',
'Menu:ProblemManagement+' => 'An ITIL process that identifies root causes of incidents, documents Known Errors and FAQs, in order to reduce helpdesk workload~~',
'Menu:ProblemManagement+' => 'Zarządzanie problemami',
'Menu:Problem:Shortcuts' => 'Skróty',
'Menu:FAQCategory' => 'Kategorie pytań FAQ',
'Menu:FAQCategory+' => 'Wszystkie kategorie pytań FAQ',

View File

@@ -44,7 +44,7 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', [
]);
Dict::Add('PT BR', 'Brazilian', 'Brazilian', [
'Menu:ProblemManagement' => 'Gerencimento de problemas',
'Menu:ProblemManagement+' => 'An ITIL process that identifies root causes of incidents, documents Known Errors and FAQs, in order to reduce helpdesk workload~~',
'Menu:ProblemManagement+' => '',
'Menu:Problem:Shortcuts' => 'Atalhos',
'Menu:FAQCategory' => 'Categorias de FAQ',
'Menu:FAQCategory+' => 'Lista de Categorias de FAQ',

View File

@@ -45,7 +45,7 @@ Dict::Add('RU RU', 'Russian', 'Русский', [
]);
Dict::Add('RU RU', 'Russian', 'Русский', [
'Menu:ProblemManagement' => 'Управление проблемами',
'Menu:ProblemManagement+' => 'An ITIL process that identifies root causes of incidents, documents Known Errors and FAQs, in order to reduce helpdesk workload~~',
'Menu:ProblemManagement+' => 'Управление проблемами',
'Menu:Problem:Shortcuts' => 'Ярлыки',
'Menu:FAQCategory' => 'Категории FAQ',
'Menu:FAQCategory+' => 'Категории FAQ',

View File

@@ -44,12 +44,12 @@ Dict::Add('SK SK', 'Slovak', 'Slovenčina', [
]);
Dict::Add('SK SK', 'Slovak', 'Slovenčina', [
'Menu:ProblemManagement' => 'Problem management~~',
'Menu:ProblemManagement+' => 'An ITIL process that identifies root causes of incidents, documents Known Errors and FAQs, in order to reduce helpdesk workload~~',
'Menu:ProblemManagement+' => 'Problem management~~',
'Menu:Problem:Shortcuts' => 'Shortcuts~~',
'Menu:FAQCategory' => 'FAQ categories~~',
'Menu:FAQCategory+' => 'A typology to categorize frequently asked questions (FAQ)~~',
'Menu:FAQCategory+' => 'All FAQ categories~~',
'Menu:FAQ' => 'FAQs~~',
'Menu:FAQ+' => 'All Frequently Asked Questions~~',
'Menu:FAQ+' => 'All FAQs~~',
'Brick:Portal:FAQ:Menu' => 'FAQ~~',
'Brick:Portal:FAQ:Title' => 'Frequently Asked Questions~~',
'Brick:Portal:FAQ:Title+' => '<p>In a hurry?</p><p>Check out the list of most common questions and (maybe) find the expected answer right away.</p>~~',

View File

@@ -45,7 +45,7 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', [
]);
Dict::Add('TR TR', 'Turkish', 'Türkçe', [
'Menu:ProblemManagement' => 'Problem yönetimi',
'Menu:ProblemManagement+' => 'An ITIL process that identifies root causes of incidents, documents Known Errors and FAQs, in order to reduce helpdesk workload~~',
'Menu:ProblemManagement+' => 'Problem yönetimi',
'Menu:Problem:Shortcuts' => 'Kısayollar',
'Menu:FAQCategory' => 'SSS kategorileri',
'Menu:FAQCategory+' => 'Tüm SSS kategorileri',

View File

@@ -85,7 +85,7 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', [
]);
Dict::Add('ZH CN', 'Chinese', '简体中文', [
'Menu:ProblemManagement' => '问题管理',
'Menu:ProblemManagement+' => 'An ITIL process that identifies root causes of incidents, documents Known Errors and FAQs, in order to reduce helpdesk workload~~',
'Menu:ProblemManagement+' => '问题管理',
'Menu:Problem:Shortcuts' => '快捷方式',
'Menu:FAQCategory' => 'FAQ 类别',
'Menu:FAQCategory+' => '所有 FAQ 类别',

View File

@@ -159,7 +159,7 @@ function DoInstall(WebPage $oPage)
foreach ($oExtensionsMap->GetAllExtensions() as $oExtension) {
if ($oExtension->sSource == iTopExtension::SOURCE_REMOTE) {
if ($oExtension->HasDependencyIssue()) {
if (count($oExtension->aMissingDependencies) > 0) {
$oPage->add('<div class="choice">');
$oPage->add('<input type="checkbox" disabled>&nbsp;');
$sTitle = Dict::Format('iTopHub:InstallationEffect:MissingDependencies_Details', implode(', ', $oExtension->aMissingDependencies));

View File

@@ -133,7 +133,8 @@ class HubController
throw new Exception('Sorry the installation of extensions is not allowed in demo mode');
}
$oRuntimeEnv->CompileFrom('production'); // WARNING symlinks does not seem to be compatible with manual Commit
$aSelectModules = $oRuntimeEnv->CompileFrom('production'); // WARNING symlinks does not seem to be compatible with manual Commit
$oRuntimeEnv->UpdateIncludes($oConfig);
$oRuntimeEnv->InitDataModel($oConfig, true /* model only */);

View File

@@ -1767,13 +1767,6 @@
<do_search>1</do_search>
<auto_reload>fast</auto_reload>
</menu>
<menu id="Incident:MySupportIncidents" xsi:type="OQLMenuNode" _delta="define">
<rank>3</rank>
<parent>Incident:Shortcuts</parent>
<oql><![CDATA[SELECT Incident WHERE caller_id = :current_contact_id AND status NOT IN ("closed")]]></oql>
<do_search/>
<auto_reload>fast</auto_reload>
</menu>
</menus>
<user_rights>
<profiles>

View File

@@ -25,8 +25,6 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', [
'Menu:Incident:Shortcuts+' => '',
'Menu:Incident:MyIncidents' => 'Incidenty přidělené mně',
'Menu:Incident:MyIncidents+' => 'Incidenty přidělené mně (jako řešiteli)',
'Menu:Incident:MySupportIncidents' => 'Reported by me~~',
'Menu:Incident:MySupportIncidents+' => 'Non closed incidents where I am the caller~~',
'Menu:Incident:EscalatedIncidents' => 'Eskalované incidenty',
'Menu:Incident:EscalatedIncidents+' => 'Eskalované incidenty',
'Menu:Incident:OpenIncidents' => 'Všechny otevřené incidenty',

View File

@@ -24,12 +24,10 @@ Dict::Add('DA DA', 'Danish', 'Dansk', [
'Menu:Incident:Shortcuts+' => '',
'Menu:Incident:MyIncidents' => 'Mine Incidents',
'Menu:Incident:MyIncidents+' => '',
'Menu:Incident:MySupportIncidents' => 'Reported by me~~',
'Menu:Incident:MySupportIncidents+' => 'Non closed incidents where I am the caller~~',
'Menu:Incident:EscalatedIncidents' => 'Eskalerede Incidents',
'Menu:Incident:EscalatedIncidents+' => 'Incident which are under escalation, by status or hot flag~~',
'Menu:Incident:EscalatedIncidents+' => '',
'Menu:Incident:OpenIncidents' => 'Alle åbne Incidents',
'Menu:Incident:OpenIncidents+' => 'All incidents that are not closed~~',
'Menu:Incident:OpenIncidents+' => '',
'UI-IncidentManagementOverview-IncidentByPriority-last-14-days' => 'Incidents de sidste 14 dage efter prioritet',
'UI-IncidentManagementOverview-Last-14-days' => 'Antal Incidents de sidste 14 dage',
'UI-IncidentManagementOverview-OpenIncidentByStatus' => 'Åbne Incidents efter status',

View File

@@ -20,12 +20,10 @@ Dict::Add('DE DE', 'German', 'Deutsch', [
'Menu:NewIncident+' => 'Einen neuen Incident dokumentieren',
'Menu:SearchIncidents' => 'Nach Incidents suchen',
'Menu:SearchIncidents+' => 'Suche nach einem bestehendem Incident',
'Menu:Incident:Shortcuts' => 'Incidents',
'Menu:Incident:Shortcuts' => 'Shortcuts',
'Menu:Incident:Shortcuts+' => '',
'Menu:Incident:MyIncidents' => 'Mir zugewiesene Incidents',
'Menu:Incident:MyIncidents+' => 'Incidents die mir als Bearbeiter zugewiesen sind',
'Menu:Incident:MySupportIncidents' => 'Reported by me~~',
'Menu:Incident:MySupportIncidents+' => 'Non closed incidents where I am the caller~~',
'Menu:Incident:EscalatedIncidents' => 'Eskalierte Incidents',
'Menu:Incident:EscalatedIncidents+' => 'Incidents die eskaliert sind',
'Menu:Incident:OpenIncidents' => 'Alle offenen Incidents',

View File

@@ -31,16 +31,14 @@ Dict::Add('EN US', 'English', 'English', [
'Menu:NewIncident+' => 'Create a new incident ticket',
'Menu:SearchIncidents' => 'Search for incidents',
'Menu:SearchIncidents+' => 'Search for incident tickets',
'Menu:Incident:Shortcuts' => 'Incidents',
'Menu:Incident:Shortcuts' => 'Shortcuts',
'Menu:Incident:Shortcuts+' => '',
'Menu:Incident:MyIncidents' => 'Assigned to me',
'Menu:Incident:MyIncidents+' => 'Incidents assigned to me (as an Agent)',
'Menu:Incident:MySupportIncidents' => 'Reported by me',
'Menu:Incident:MySupportIncidents+' => 'Non closed incidents where I am the caller',
'Menu:Incident:EscalatedIncidents' => 'Under escalation',
'Menu:Incident:EscalatedIncidents+' => 'Incident which are under escalation, by status or hot flag',
'Menu:Incident:OpenIncidents' => 'Open',
'Menu:Incident:OpenIncidents+' => 'All incidents that are not closed',
'Menu:Incident:MyIncidents' => 'Incidents assigned to me',
'Menu:Incident:MyIncidents+' => 'Incidents assigned to me (as Agent)',
'Menu:Incident:EscalatedIncidents' => 'Escalated incidents',
'Menu:Incident:EscalatedIncidents+' => '',
'Menu:Incident:OpenIncidents' => 'All open incidents',
'Menu:Incident:OpenIncidents+' => '',
'UI-IncidentManagementOverview-IncidentByPriority-last-14-days' => 'Last 14 days incident per priority',
'UI-IncidentManagementOverview-Last-14-days' => 'Last 14 days number of incidents',
'UI-IncidentManagementOverview-OpenIncidentByStatus' => 'Open incidents by status',
@@ -136,7 +134,7 @@ Dict::Add('EN US', 'English', 'English', [
'Class:Incident/Attribute:servicesubcategory_name' => 'Service subcategory name',
'Class:Incident/Attribute:servicesubcategory_name+' => '',
'Class:Incident/Attribute:escalation_flag' => 'Hot Flag',
'Class:Incident/Attribute:escalation_flag+' => 'When set, the Ticket is added to the "Under escalation" menu',
'Class:Incident/Attribute:escalation_flag+' => '',
'Class:Incident/Attribute:escalation_flag/Value:no' => 'No',
'Class:Incident/Attribute:escalation_flag/Value:no+' => '',
'Class:Incident/Attribute:escalation_flag/Value:yes' => 'Yes',

View File

@@ -31,16 +31,14 @@ Dict::Add('EN GB', 'British English', 'British English', [
'Menu:NewIncident+' => 'Create a new incident ticket',
'Menu:SearchIncidents' => 'Search for incidents',
'Menu:SearchIncidents+' => 'Search for incident tickets',
'Menu:Incident:Shortcuts' => 'Incidents',
'Menu:Incident:Shortcuts' => 'Shortcuts',
'Menu:Incident:Shortcuts+' => '',
'Menu:Incident:MyIncidents' => 'Assigned to me',
'Menu:Incident:MyIncidents+' => 'Incidents assigned to me (as an Agent)',
'Menu:Incident:MySupportIncidents' => 'Reported by me~~',
'Menu:Incident:MySupportIncidents+' => 'Non closed incidents where I am the caller~~',
'Menu:Incident:EscalatedIncidents' => 'Under escalation',
'Menu:Incident:EscalatedIncidents+' => 'Incident which are under escalation, by status or hot flag',
'Menu:Incident:OpenIncidents' => 'Open',
'Menu:Incident:OpenIncidents+' => 'All incidents that are not closed~~',
'Menu:Incident:MyIncidents' => 'Incidents assigned to me',
'Menu:Incident:MyIncidents+' => 'Incidents assigned to me (as Agent)',
'Menu:Incident:EscalatedIncidents' => 'Escalated incidents',
'Menu:Incident:EscalatedIncidents+' => '',
'Menu:Incident:OpenIncidents' => 'All open incidents',
'Menu:Incident:OpenIncidents+' => '',
'UI-IncidentManagementOverview-IncidentByPriority-last-14-days' => 'Last 14 days incident per priority',
'UI-IncidentManagementOverview-Last-14-days' => 'Last 14 days number of incidents',
'UI-IncidentManagementOverview-OpenIncidentByStatus' => 'Open incidents by status',

View File

@@ -21,8 +21,6 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', [
'Menu:Incident:Shortcuts+' => 'Accesos Rápidos',
'Menu:Incident:MyIncidents' => 'Incidentes Asignados a Mí',
'Menu:Incident:MyIncidents+' => 'Incidentes Asignados a Mí (como Analista)',
'Menu:Incident:MySupportIncidents' => 'Reported by me~~',
'Menu:Incident:MySupportIncidents+' => 'Non closed incidents where I am the caller~~',
'Menu:Incident:EscalatedIncidents' => 'Incidentes Escalados',
'Menu:Incident:EscalatedIncidents+' => 'Incidentes Escalados',
'Menu:Incident:OpenIncidents' => 'Incidentes Abiertos',

View File

@@ -19,15 +19,13 @@ Dict::Add('FR FR', 'French', 'Français', [
'Menu:NewIncident+' => 'Créer un nouveau ticket d\'incident',
'Menu:SearchIncidents' => 'Rechercher des incidents',
'Menu:SearchIncidents+' => 'Rechercher parmi les tickets d\'incidents',
'Menu:Incident:Shortcuts' => 'Incidents',
'Menu:Incident:Shortcuts' => 'Raccourcis',
'Menu:Incident:Shortcuts+' => '',
'Menu:Incident:MyIncidents' => 'Qui me sont assignés',
'Menu:Incident:MyIncidents+' => 'Les tickets d\'incident en cours qui me sont assignés',
'Menu:Incident:MySupportIncidents' => 'Que j\'ai déclarés',
'Menu:Incident:MySupportIncidents+' => 'Les incidents en cours dont je suis le demandeur',
'Menu:Incident:EscalatedIncidents' => 'En escalade',
'Menu:Incident:EscalatedIncidents+' => 'Ticket d\'incident en cours d\'escalade ou à surveiller',
'Menu:Incident:OpenIncidents' => 'En cours',
'Menu:Incident:MyIncidents' => 'Mes incidents',
'Menu:Incident:MyIncidents+' => 'Tickets d\'incident qui me sont assignés',
'Menu:Incident:EscalatedIncidents' => 'Incidents en cours d\'escalade',
'Menu:Incident:EscalatedIncidents+' => 'Ticket d\'incident en cours d\'escalade',
'Menu:Incident:OpenIncidents' => 'Incidents ouverts',
'Menu:Incident:OpenIncidents+' => 'Tous les tickets d\'incident ouverts',
'UI-IncidentManagementOverview-IncidentByPriority-last-14-days' => 'Incidents des 14 derniers jours par priorité',
'UI-IncidentManagementOverview-Last-14-days' => 'Incidents des 14 derniers jours',
@@ -122,7 +120,7 @@ Dict::Add('FR FR', 'French', 'Français', [
'Class:Incident/Attribute:servicesubcategory_name' => 'Nom Sous-catégorie de service',
'Class:Incident/Attribute:servicesubcategory_name+' => '',
'Class:Incident/Attribute:escalation_flag' => 'Ticket à surveiller',
'Class:Incident/Attribute:escalation_flag+' => 'Ce Ticket sera ajouté au menu des incidents en cours d\'escalade',
'Class:Incident/Attribute:escalation_flag+' => '',
'Class:Incident/Attribute:escalation_flag/Value:no' => 'Non',
'Class:Incident/Attribute:escalation_flag/Value:no+' => '',
'Class:Incident/Attribute:escalation_flag/Value:yes' => 'Oui',

View File

@@ -23,8 +23,6 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', [
'Menu:Incident:Shortcuts+' => 'Gyorselérés gombok',
'Menu:Incident:MyIncidents' => 'Hozzám rendelt incidensek',
'Menu:Incident:MyIncidents+' => 'Hozzám rendelt incidensek (ügyintézőként)',
'Menu:Incident:MySupportIncidents' => 'Reported by me~~',
'Menu:Incident:MySupportIncidents+' => 'Non closed incidents where I am the caller~~',
'Menu:Incident:EscalatedIncidents' => 'Eszkalált incidensek',
'Menu:Incident:EscalatedIncidents+' => 'Eszkalált incidensek',
'Menu:Incident:OpenIncidents' => 'Nyitott incidensek',

View File

@@ -23,8 +23,6 @@ Dict::Add('IT IT', 'Italian', 'Italiano', [
'Menu:Incident:Shortcuts+' => '~~',
'Menu:Incident:MyIncidents' => 'Incidenti assegnati a me',
'Menu:Incident:MyIncidents+' => 'Incidenti assegnati a me (come agente)',
'Menu:Incident:MySupportIncidents' => 'Reported by me~~',
'Menu:Incident:MySupportIncidents+' => 'Non closed incidents where I am the caller~~',
'Menu:Incident:EscalatedIncidents' => 'Evoluzione Incidente',
'Menu:Incident:EscalatedIncidents+' => 'Evoluzione Incidente',
'Menu:Incident:OpenIncidents' => 'Tutti gli incidenti aperti',

Some files were not shown because too many files have changed in this diff Show More