Compare commits

..

69 Commits

Author SHA1 Message Date
lenaick.moreira
c6e50a0ed7 N°9830 - Fix setup error when trying to remove class with a TagSet attribute 2026-07-23 11:39:42 +02:00
Molkobain
76a410e00d Revert "N°9541 itop-virtualization-mgmt cannot currently be uninstalled" now that N°9831 has been fixed
This reverts commit 52fca750b0.
2026-07-23 10:45:44 +02:00
Molkobain
c68887c2bc N°9831 - Fix ext. management deletion plan analysis by avoiding overwriting entity for a previously processed class 2026-07-23 10:21:31 +02:00
Molkobain
837b433622 N°9831 - Fix DataCleanupService so it handles external keys the same way as \Combodo\iTop\DataFeatureRemoval\Service\StaticDeletionPlan::DeletionPlanForReferencingClasses and \DBObject::MakeDeletionPlan
- Check if ext. key is nullable first
- Then check if its a DEL_MANUAL option
2026-07-23 10:21:31 +02:00
Timmy38
52fca750b0 N°9541 itop-virtualization-mgmt cannot currently be uninstalled 2026-07-22 17:37:19 +02:00
Timmy38
d1aedee245 N°9692 - Fix flag name 2026-07-21 17:04:37 +02:00
lenaick.moreira
85d50f31bd N°9692 - Fix null coalescing for extension installation status and clean up test cases 2026-07-17 17:05:06 +02:00
lenaick.moreira
3c301affb3 N°9679 - Add remote extensions as uninstallable extension in "Extension management" 2026-07-17 14:32:46 +02:00
Lenaick
147fae7f8c N°9679 - Forced uninstallation is not logged when done by extensions management (#956) 2026-07-17 11:25:36 +02:00
odain-cbd
a5aa8c279f fix broken cache warmup after setup (#974)
* fix broken cache warmup after setup

* clear all caches after setup
2026-07-17 10:40:55 +02:00
lenaick.moreira
04f91ab4a2 Fix error CI 2026-07-16 09:40:33 +02:00
lenaick.moreira
8e0246601a Fix unit tests failed 2026-07-15 14:33:55 +02:00
Eric Espie
e6cdcd0a5a N°9808 - Wrong dependency when module is in production-modules 2026-07-15 12:09:55 +02:00
Lenaick
2ab3081926 N°9692 - Uninstall / Disable install when extension has module with missing dependencies (#967)
* N°9692 - Uninstall / Disable install when extension has module with missing dependencies

* N°9692 - Uninstall / Disable install when extension has module with missing dependencies

* N°9692 - Uninstall / Disable install when extension has module with missing dependencies

* N°9692 - Refactor dependency handling for extensions to use HasDependencyIssue method

* Rename cannot-be-installed to dependency_issue

* Changes following the review
2026-07-15 09:20:25 +02:00
Molkobain
5cabac63e7 N°7984 - Complete previous revert 2026-07-14 23:32:52 +02:00
Molkobain
3918dcf830 N°7984 - Update setup compiled SCSS 2026-07-14 23:08:40 +02:00
Molkobain
489300552a Revert "Issue/7984 (#688)"
The ticket was not discussed.
2026-07-14 23:07:11 +02:00
Timmy38
8507c606ba N°9788 Adapt html for behat 2026-07-13 10:48:01 +02:00
Molkobain
128989450b 🌐 Translated missing french entries 2026-07-12 21:25:17 +02:00
Molkobain
1bd404af6f 💚 Add executable flag to scripts in .make/release folder 2026-07-12 21:10:10 +02:00
Molkobain
6c770d3e16 📝 Update third-party libraries licenses 2026-07-12 21:05:54 +02:00
Molkobain
a74dbb3a73 💚 Add executable flag to scripts in .make/license folder 2026-07-12 20:57:06 +02:00
Stephen Abello
b365aa0971 N°9628 - Fix issue following 5b9e0a1d being applied to non-jQuery elements (#961) 2026-07-10 15:57:04 +02:00
v-dumas
56aa50c9b1 N°9553 - Skip test due to unexplained CI failure 2026-07-10 15:53:37 +02:00
Vincent Dumas
eacb7f3401 N°9553 - Allow loading of localized sample and structural data based on iTop default language
* Add English, French and German structural and sample data in iTop Community

* Add helper methods to allow :
  * Checking of supported module version format
  * Finding a localized file name based on a provided en_us file name and a language
  * Loading a file if the module upgrade crossed a given version
2026-07-10 14:21:56 +02:00
Eric Espie
b14045af29 N°9648 - Better dependencies error message 2026-07-10 12:10:21 +02:00
Eric Espie
7321eeb23f N°9648 - Better dependencies error message 2026-07-10 12:02:12 +02:00
odain
05b8c529fe Fix cache-warmup after any succesfull setup 2026-07-10 11:14:59 +02:00
Timmy38
a68c017225 N°9681 Fixing edge case where an installed extension may have lost its dependencies 2026-07-09 16:40:43 +02:00
Timmy38
82b52b95a1 N°9681 Update badge tooltip 2026-07-09 14:17:42 +02:00
Molkobain
556f612f7e N°9625 - Update welcome popup messages for iTop 3.3.0 (#955)
* N°9625 - Update welcome popup messages for iTop 3.3.0

* N°9625 - Update illustrations
2026-07-09 11:42:27 +02:00
Eric Espie
edc69bebba Refactor form action URL construction in WizStepDone.php 2026-07-09 08:59:44 +02:00
odain-cbd
dce1994b85 N°9675 - Set up crash - cannot get class from production (#968)
* N°9675 - Set up crash - cannot get class from production

* N°9675 - add some comments
2026-07-09 08:59:33 +02:00
Molkobain
fde6527057 N°3124 - Update PHPDoc 2026-07-08 21:48:42 +02:00
Molkobain
0de0592c18 N°3124 - Update PHPDoc 2026-07-08 21:37:47 +02:00
Vincent Dumas
c9d512cc31 N°9699 - Enable AddMeToContact without write access on Ticket (#949)
* N°9699 - Enable AddMeToContact without write access on Ticket
* exit loop as soon as Lnk found
Co-authored-by: Stephen Abello <stephen.abello@combodo.com>
2026-07-08 16:52:23 +02:00
Eric Espié
a3ef049063 N°9722 - Setup - extension dependencies must be computed with installation choice change (#965)
* WIP compileFrom

* WIP compileFrom

* WIP

* Refactor DataFeatureRemovalController to improve setup redirection and add logging for selected extensions and modules

* Refactor DataFeatureRemovalController to streamline parameter handling for extension management

* Refactor DataFeatureRemovalController and related classes for improved session management and cleanup processes

* N°9722 - replace GetMFModulesToCompile API by GetAdditionalMFModulesBeforeFinalDeltaToCompile + fix test

* N°9722 - Refacto

* N°9722 - remove extensions effectively

* N°9722 - After review

* N°9722 - After review

* N°9722 - Analyze installation before compilation in extension management

*  N°9722 - Refactor and unit tests

* N°9722 - 

* N°9722 - 

* N°9722 - cleanup + geptileia PR feedback

---------

Co-authored-by: odain <olivier.dain@combodo.com>
2026-07-08 16:41:25 +02:00
Benjamin DALSASS
87ec702c5e N°9333 - Logo selection in dashboard is broken
- test broken
2026-07-08 13:29:55 +02:00
Vincent Dumas
127be1933d N°9629 - New fields Tags and Owner on Query class (#963)
* N°9629 - Add Usages EnumSet and Owner on Query class

* N°9629 - Add Usages on structural Queries

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-07-08 10:37:00 +02:00
Timmy38
2c14030fc5 N°9681 Fix missing data-id 2026-07-08 09:50:35 +02:00
odain
7825c08069 N°9765 - Designer - can't upload extensions 2026-07-08 09:34:37 +02:00
Benjamin DALSASS
4ddf17233f N°9635 - Twig security issues CVE-2026-46633 and CVE-2026-46639 and CVE-2026-46640 2026-07-07 13:52:00 +02:00
Benjamin DALSASS
9493bb03d5 Merge remote-tracking branch 'origin/support/3.2' into develop
# Conflicts:
#	lib/composer/installed.php
2026-07-07 13:51:20 +02:00
Benjamin DALSASS
8f87c759b5 N°9635 - Twig security issues CVE-2026-46633 and CVE-2026-46639 and CVE-2026-46640 2026-07-07 13:47:15 +02:00
Benjamin DALSASS
348c90145d N°9635 - Twig security issues CVE-2026-46633 and CVE-2026-46639 and CVE-2026-46640 2026-07-07 13:43:51 +02:00
Eric Espié
c37143176a N°9753 - Extension management - Run setup display installation and not upgrade (#962)
* 🚧 Refactor installation mode parameter to unify naming convention

* Changed comments on wizard steps and example to clarify upgrade mode handling
2026-07-07 11:40:59 +02:00
Benjamin DALSASS
0c8229a68e N°9333 - Logo selection in dashboard is broken 2026-07-07 09:07:04 +02:00
Timmy38
fda5fe5ded N°9681 Create "Cannot be installed" badge 2026-07-06 14:58:53 +02:00
Eric Espié
6b396adeea N°9571 - Do not allow DB change or install when upgrading iTop (#958)
* N°9571 - Do not allow DB change or install when upgrading iTop

* N°9571 - Fix unit tests

* N°9711 - Removed step Install or Upgrade

* N°9711 - After revue
2026-07-06 10:31:43 +02:00
odain
c448f8411c Merge branch 'support/3.2' into develop 2026-07-03 11:52:36 +02:00
odain
4b4fe55060 N°9689 - Fix itop-portal-base dependancy 2026-07-03 11:49:47 +02:00
Eric Espie
dedcd4af19 N°9711 - Update WizStepSummary to conditionally display database parameters based on return_application parameter 2026-07-03 09:23:13 +02:00
Eric Espie
0556a03839 N°9711 - Clear setup parameters on menu node rendering in UI.php (default page display) 2026-07-03 09:10:11 +02:00
Molkobain
64df429715 Merge remote-tracking branch 'origin/support/3.2' into develop 2026-07-02 21:12:38 +02:00
Molkobain
9ae813db2b Merge remote-tracking branch 'origin/support/3.2.3' into support/3.2 2026-07-02 21:08:45 +02:00
Molkobain
768423a6aa N°7371 - Simplify initial approach by using common API, and revert modification of unnecessary js/utils.js API 2026-07-02 20:51:30 +02:00
odain-cbd
921e7c88fe N°9675 - Set up crash - cannot get class from production (#953)
* N°9675 - raise first exception encountered when starting metamodel

* N°9675 - enhance setup data consistency error feedback

* N°9675 - raise PHP CLI version issue as well

* N°9675 - geptile PR fixes + enhance regexp for cli php version

* cleanup

* N°9675 - remove maintenance mode before any setup compilation

* N°9675 - share php cli check in SetupUtils

* N°9675 - exit maintenance only before audit
2026-07-02 16:59:04 +02:00
Molkobain
d6ef4fb7bb N°9687 - Fix incorrect return type for the DBObjectSearch::ApplyDataFilter() function (#939)
* N°9687 - Fix incorrect return type for the DBObjectSearch::ApplyDataFilter() function

* N°9687 - Add unit test

* N°9687 - Improve unit test after code review

* N°9687 - Improve unit test after code review
2026-07-02 16:11:32 +02:00
Eric Espié
a335e1004b N°9711 - Block user from going back to the setup (#954)
* N°9711 - Store setup parameters in session

* N°9711 - Restrict database parameters display to administrators in setup summary
2026-07-02 12:00:22 +02:00
Molkobain
e882df96d9 📝 Remove duplicated table in PR template 2026-07-02 11:55:34 +02:00
Eric Espié
3a7439e970 N°9639 - Uninstallation Analysis result doesn't list all the object (#950)
* N°9639 - Uninstallation Analysis better count method

* N°9639 - Fix tests

* N°9639 - Refactor deletion plan handling with new entity classes for improved structure and clarity

* N°9639 - Refactor deletion plan methods to use class names instead of table names and add TotalCount method

* N°9639 - Add messages to tests

* N°9639 - Refactor data feature removal logic and update database queries for consistency

* N°9639 - Refactor SQL queries to use backticks for table and field names

* N°9639 - Enhance deletion logic and add circular reference handling in cleanup process

* N°9639 - Add filtering methods to DeletionPlan classes for improved data cleanup

* N°9639 - Add filtering methods to DeletionPlan classes for improved data cleanup

* N°9639 - Refactor DeletionPlanItem to remove unused queries and simplify constructor

* N°9639 - Refactor variable name for clarity in hierarchical key update process

* Update tests/php-unit-tests/unitary-tests/datamodels/2.x/combodo-data-feature-removal/simulate-audit-from-setup.php

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

* N°9639 - Clarify comment on deletion plan to indicate prevention of infinite loops

* N°9639 - Remove unused deletion plan from DataFeatureRemovalController

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-06-30 09:37:30 +02:00
jf-cbd
7fca6424ab N°9723 - IsActionAllowed should work with non instantiated users objects (#947)
* Replace references to user objects keys since objects can be non-instantiated (so no key available) and replace them by equivalent code

* Rename test + use self variable for profile

---------

Co-authored-by: jf-cbd <jf-cbd@users.noreply.github.com>
2026-06-25 17:45:43 +02:00
jf-cbd
f09a73c45a N°7060 - create ReadOnly profiles (#935) 2026-06-25 17:38:48 +02:00
Vincent Dumas
5a174dd8fa N°9658 - Fix Profiles retrieval in User sample data loading (#948) 2026-06-25 12:08:21 +02:00
v-dumas
01f32086ec Fix tests for CI with 3.0 sample data and for commit on dev 2026-06-24 11:57:58 +02:00
v-dumas
5c59fdebaf Fix tests for CI with 3.0 sample data and for commit on dev 2026-06-24 11:01:48 +02:00
Vincent Dumas
363d0767d5 N°8142 user request and incident menu label (#903)
* N°8142 - User Request, Incident and Change menu standardization
2026-06-24 09:11:17 +02:00
odain-cbd
5202adb902 N°9717 - Bring unattended error feedbacks back (#943)
* Enhance unattended CLI to log fatal error just like setup wizardinstead of silent failure

* 💚 change unattended output in case of painless FATAL

* 💚 capture FATALs only

* Update setup/unattended-install/unattended-install.php

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>

---------

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
2026-06-23 17:16:04 +02:00
Molkobain
1d9e7f9b55 Update test so it works on both ITIL and standard request management 2026-06-20 17:47:19 +02:00
442 changed files with 8830 additions and 3241 deletions

View File

@@ -9,11 +9,6 @@ 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 Normal file → Executable file
View File

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

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

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

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

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

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

View File

@@ -582,16 +582,26 @@ class UserRightsProfile extends UserRightsAddOnAPI
*/
public function ListProfiles($oUser)
{
$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');
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;
}
return $aRet;
}
public function GetSelectFilter($oUser, $sClass, $aSettings = [])
@@ -705,26 +715,23 @@ class UserRightsProfile extends UserRightsAddOnAPI
protected function GetUserActionGrant($oUser, $sClass, $iActionCode)
{
$this->LoadCache();
// 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;
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;
}
}
}
$sAction = self::$m_aActionCodes[$iActionCode];
$bStatus = null;
// Cache user's profiles
if (false === array_key_exists($iUser, $this->aUsersProfilesList)) {
$this->aUsersProfilesList[$iUser] = UserRights::ListProfiles($oUser);
}
$aProfileList = $this->GetProfileList($oUser);
// Call the API of UserRights because it caches the list for us
foreach ($this->aUsersProfilesList[$iUser] as $iProfile => $oProfile) {
foreach ($aProfileList as $iProfile => $oProfile) {
$bGrant = $this->GetProfileActionGrant($iProfile, $sClass, $sAction);
if (!is_null($bGrant)) {
if ($bGrant) {
@@ -742,7 +749,9 @@ class UserRightsProfile extends UserRightsAddOnAPI
$aRes = [
'permission' => $iPermission,
];
$this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode] = $aRes;
if (count($oUser->ListChanges()) === 0) {
$this->m_aObjectActionGrants[$oUser->GetKey()][$sClass][$iActionCode] = $aRes;
}
return $aRes;
}
@@ -824,18 +833,14 @@ class UserRightsProfile extends UserRightsAddOnAPI
{
$this->LoadCache();
// Note: this code is VERY close to the code of IsActionAllowed()
$iUser = $oUser->GetKey();
// Cache user's profiles
if (false === array_key_exists($iUser, $this->aUsersProfilesList)) {
$this->aUsersProfilesList[$iUser] = UserRights::ListProfiles($oUser);
}
$aProfileList = $this->GetProfileList($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 ($this->aUsersProfilesList[$iUser] as $iProfile => $oProfile) {
foreach ($aProfileList as $iProfile => $oProfile) {
$bGrant = $this->GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode);
if (!is_null($bGrant)) {
if ($bGrant) {
@@ -893,6 +898,25 @@ 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,17 +113,43 @@ 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', 'description']
['name', 'is_template', 'owner_id', 'usages', 'description']
); // Attributes to be displayed for the complete details
MetaModel::Init_SetZListItems('list', ['description']); // Attributes to be displayed for a list
MetaModel::Init_SetZListItems('list', ['description', 'usages']); // 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']
['name', 'description', 'is_template', 'owner_id', 'usages']
); // Criteria of the default search form
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
}
@@ -143,6 +169,15 @@ 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.
*
@@ -214,15 +249,15 @@ class QueryOQL extends Query
MetaModel::Init_SetZListItems(
'details',
[
'col:col1' => ['fieldset:Query:baseinfo' => ['name', 'is_template', 'description', 'oql', 'fields']],
'col:col1' => ['fieldset:Query:baseinfo' => ['name', 'is_template', 'owner_id', 'usages', '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']); // Attributes to be displayed for a list
MetaModel::Init_SetZListItems('list', ['description', 'usages']); // Attributes to be displayed for a list
// Search criteria
MetaModel::Init_SetZListItems(
'standard_search',
['name', 'description', 'is_template', 'fields', 'oql']
['name', 'description', 'is_template', 'owner_id', 'usages', 'oql']
); // Criteria of the std search form
}

View File

@@ -284,8 +284,7 @@ class UIExtKeyWidget
if ($bAddingValue) {
$aArguments = [];
foreach ($aAdditionalField as $sAdditionalField) {
$oAttrDef = MetaModel::GetAttributeDef(get_class($oObj), $sAdditionalField);
array_push($aArguments, $oAttrDef->GetValueLabel($oObj->Get($sAdditionalField)));
array_push($aArguments, $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": "1cca58a0e26794fb9c546a001f7f7de8",
"content-hash": "24e7507794b971955358df5f2b143ac4",
"packages": [
{
"name": "apereo/phpcas",
@@ -5570,16 +5570,16 @@
},
{
"name": "twig/twig",
"version": "v3.24.0",
"version": "v3.28.0",
"source": {
"type": "git",
"url": "https://github.com/twigphp/Twig.git",
"reference": "a6769aefb305efef849dc25c9fd1653358c148f0"
"reference": "597c12ed286fb9d1701a36684ce6e0cbe28ebc8b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/a6769aefb305efef849dc25c9fd1653358c148f0",
"reference": "a6769aefb305efef849dc25c9fd1653358c148f0",
"url": "https://api.github.com/repos/twigphp/Twig/zipball/597c12ed286fb9d1701a36684ce6e0cbe28ebc8b",
"reference": "597c12ed286fb9d1701a36684ce6e0cbe28ebc8b",
"shasum": ""
},
"require": {
@@ -5634,7 +5634,7 @@
],
"support": {
"issues": "https://github.com/twigphp/Twig/issues",
"source": "https://github.com/twigphp/Twig/tree/v3.24.0"
"source": "https://github.com/twigphp/Twig/tree/v3.28.0"
},
"funding": [
{
@@ -5646,7 +5646,7 @@
"type": "tidelift"
}
],
"time": "2026-03-17T21:31:11+00:00"
"time": "2026-07-03T20:44:34+00:00"
}
],
"packages-dev": [

View File

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

View File

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

View File

@@ -676,9 +676,8 @@ class DBUnionSearch extends DBSearch
/**
* @inheritDoc
* @return DBUnionSearch
*/
protected function ApplyDataFilters(): DBUnionSearch
protected function ApplyDataFilters(): DBSearch
{
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 since 3.3.0 Replaced by ormDocument::ResizeImageToFit
* @deprecated 3.3.0 Use ormDocument::ResizeImageToFit instead
*/
public static function ResizeImageToFit(ormDocument $oImage, &$aDimensions = null)
{

View File

@@ -614,6 +614,13 @@ 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,36 +5761,37 @@ abstract class MetaModel
self::$m_sEnvironment = $sEnvironment;
try {
if (!defined('MODULESROOT')) {
define('MODULESROOT', APPROOT.'env-'.self::$m_sEnvironment.'/');
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);
}
if ($bModelOnly) {
return;
}
// $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);
}
CMDBSource::SelectDB(self::$m_sDBName);
foreach (MetaModel::EnumPlugins('ModuleHandlerApiInterface') as $oPHPClass) {
$oPHPClass::OnMetaModelStarted();
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;
}
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', 'target_class'],
"complementary_name_attcode" => ['finalclass', 'complement'],
"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', 'target_class'],
"complementary_name_attcode" => ['finalclass', 'complement'],
"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', 'target_class'],
"complementary_name_attcode" => ['finalclass', 'complement'],
"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', 'target_class'],
"complementary_name_attcode" => ['finalclass', 'complement'],
"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', 'target_class'],
"complementary_name_attcode" => ['finalclass', 'complement'],
"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', 'target_class'],
"complementary_name_attcode" => ['finalclass', 'complement'],
"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', 'target_class'],
"complementary_name_attcode" => ['finalclass', 'complement'],
"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', 'target_class'],
"complementary_name_attcode" => ['finalclass', 'complement'],
"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', 'target_class'],
"complementary_name_attcode" => ['finalclass', 'complement'],
"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', 'target_class'],
"complementary_name_attcode" => ['finalclass', 'complement'],
"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', 'target_class'],
"complementary_name_attcode" => ['finalclass', 'complement'],
"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', 'target_class'],
"complementary_name_attcode" => ['finalclass', 'complement'],
"state_attcode" => "",
"reconc_keys" => ['description'],
"db_table" => "priv_trigger_threshold",

View File

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

View File

@@ -19,6 +19,8 @@ $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--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--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--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--menu--icon--max-height;
max-width: $ibo-input-select-icon--menu--icon--max-width;
padding-right: $ibo-input-select-icon--icon--padding-right;
max-height: $ibo-input-select-icon--max-height;
max-width: $ibo-input-select-icon--max-width;
padding-right: $ibo-input-select-icon--padding-right;
}
>span{
overflow: hidden;

View File

@@ -4,7 +4,7 @@
*/
/* SCSS variables */
$common-has-description--content: "\1F6C8" !default;
$common-has-description--content: "?" !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,6 +11,9 @@
*
* 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,32 +611,6 @@ 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,7 +8,6 @@
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;
@@ -18,7 +17,8 @@ use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalHelper;
use Combodo\iTop\DataFeatureRemoval\Helper\DataFeatureRemovalLog;
use Combodo\iTop\DataFeatureRemoval\Service\DataCleanupService;
use Combodo\iTop\DataFeatureRemoval\Service\DataFeatureRemoverExtensionService;
use Combodo\iTop\Setup\FeatureRemoval\DryRemovalRuntimeEnvironment;
use Combodo\iTop\DataFeatureRemoval\Service\StaticDeletionPlan;
use Combodo\iTop\Service\Session\SessionParameters;
use Combodo\iTop\Setup\FeatureRemoval\SetupAudit;
use ContextTag;
use CoreException;
@@ -37,15 +37,18 @@ 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;
@@ -124,9 +127,10 @@ class DataFeatureRemovalController extends Controller
$aRemovedExtensions = $this->aExtensionsToCheck['to_be_removed'];
$aHiddenInputs['removed_extensions'] = $this->ConvertIntoSetupFormat($aRemovedExtensions);
}
$aRemoveExtensionCodes = array_keys($aRemovedExtensions);
$aExtensionsNotUninstallable = $this->aExtensionsToCheck['extensions_not_uninstallable'];
$aHiddenInputs['extensions_not_uninstallable'] = $this->ConvertIntoSetupFormat($aExtensionsNotUninstallable);
}
$aParams['aAddedExtensions'] = $aAddedExtensions;
$aParams['aRemovedExtensions'] = $aRemovedExtensions;
@@ -139,9 +143,24 @@ class DataFeatureRemovalController extends Controller
$aParams['iColumnCount'] = $this->iColumnCount;
$aParams['aAvailableExtensions'] = $this->SplitArrayIntoColumns($this->GetExtensionsDiff($aAddedExtensions, $aRemovedExtensions), $this->iColumnCount);
$bForceCompilation = Session::Get('bForceCompilation', false);
//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);
}
try {
$this->Compile($aAddedExtensions, $aRemoveExtensionCodes, $bForceCompilation);
$this->Compile($aSelectedExtensions, array_keys($aRemovedExtensions), $aSelectedModules);
$aHiddenInputs['selected_modules'] = $this->ConvertIntoSetupFormat($aSelectedModules);
} catch (CoreException $e) {
$aParams['DataFeatureRemovalErrorMessage'] = $e->getHtmlDesc();
$this->DisplayPage($aParams, 'AnalysisResult');
@@ -152,19 +171,6 @@ 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]);
@@ -179,7 +185,7 @@ class DataFeatureRemovalController extends Controller
];
foreach ($aHiddenInputs as $sInputName => $sInputValue) {
$aParams['aSetupParams']["_params[$sInputName]"] = $sInputValue;
$aParams['aSetupParams'][$sInputName] = $sInputValue;
}
[$aParams['aDeletionPlanSummary'], $aParams['iQueryCount'], $aParams['bDeletionPossible']] = $this->GetDeletionPlanSummaryTable($aGetRemovedClasses);
@@ -188,6 +194,7 @@ class DataFeatureRemovalController extends Controller
Session::Set('aDeletionExecutionSummary', serialize($this->aDeletionExecutionSummary));
if (!$aParams['bDeletionNeeded']) {
// Erase session setup parameters
SetupUtils::CreateSetupToken();
}
@@ -205,14 +212,15 @@ class DataFeatureRemovalController extends Controller
}
/**
* @param array $aAddedExtensions
* @param array $aRemovedExtensions
* @param bool $bForceCompilation
* @return void
* @throws \ConfigException
* @throws \CoreException
* @param array $aSelectedExtensions
* @param array $aRemovedExtensions
* @param array $aSelectedModules
*
* @return void
* @throws \ConfigException
* @throws \CoreException
*/
private function Compile(array $aAddedExtensions, array $aRemovedExtensions, bool $bForceCompilation = true): void
private function Compile(array $aSelectedExtensions, array $aRemovedExtensions, array &$aSelectedModules): void
{
$sSourceEnv = MetaModel::GetEnvironment();
$sBuildDir = APPROOT."/env-$sSourceEnv-build";
@@ -220,27 +228,28 @@ 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->GetRuntimeEnvironment($aAddedExtensions, $aRemovedExtensions)->CompileFrom($sSourceEnv);
$this->oRuntimeEnvironment->DoCompile($aSelectedExtensions, $aRemovedExtensions, $aSelectedModules, MFCompiler::CanUseSymbolicLinks());
} else {
if (count($aSelectedModules) === 0) {
$aSelectedModules = $this->oRuntimeEnvironment->GetModulesToLoadFromChoices($oConfig, $aSelectedExtensions);
}
}
}
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';
@@ -272,7 +281,7 @@ class DataFeatureRemovalController extends Controller
private function GetDeletionPlanSummaryTable(array $aRemovedClasses): array
{
$sName = 'DeletionPlanSummary';
$oDataCleanupService = new DataCleanupService();
$oDataCleanupService = new StaticDeletionPlan();
$aDeletionPlanSummaryEntities = $oDataCleanupService->GetCleanupSummary($aRemovedClasses);
$aColumns = ['Class', 'Delete Count' , 'Update Count', 'Issue Count'];
$aRows = [];
@@ -338,6 +347,7 @@ class DataFeatureRemovalController extends Controller
'uninstallable' => $oExtension->CanBeUninstalled(),
'remote' => $oExtension->IsRemote(),
'missing' => $oExtension->bRemovedFromDisk,
'dependency_issue' => $oExtension->HasDependencyIssue(),
],
];
@@ -418,6 +428,7 @@ class DataFeatureRemovalController extends Controller
$this->aExtensionsToCheck = [
'to_be_installed' => [],
'to_be_removed' => [],
'extensions_not_uninstallable' => [],
];
foreach ($aAvailableExtensions as $sCode => &$aExtensionData) {
if (!isset($aSelectedExtensionsFromUI[$sCode])) {
@@ -431,6 +442,9 @@ 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

@@ -0,0 +1,37 @@
<?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

@@ -0,0 +1,36 @@
<?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,10 +134,6 @@ 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
@@ -152,6 +148,12 @@ 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

@@ -0,0 +1,221 @@
<?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,6 +8,8 @@ $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',
@@ -16,6 +18,7 @@ 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,6 +23,8 @@ 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',
@@ -31,6 +33,7 @@ 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+' => 'If checked, the deleted file will be automatically attached to the email when an email action is triggered~~',
'Class:TriggerOnAttachmentDelete/Attribute:file_in_email+' => 'Si coché, le fichier supprimé sera automatiquement joint à l\'email quand une action email sera lancée',
'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', 'target_class'],
"complementary_name_attcode" => ['finalclass', 'complement'],
"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', 'target_class'],
"complementary_name_attcode" => ['finalclass', 'complement'],
"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', 'target_class'],
"complementary_name_attcode" => ['finalclass', 'complement'],
"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+' => '',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:WaitingAcceptance' => 'Změny čekající na přijetí',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Změny čekající na schválení',
'Menu:WaitingApproval+' => '',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'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+' => '',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:WaitingAcceptance' => 'Changes, som afventer accept',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Changes, som afventer godkendelse',
'Menu:WaitingApproval+' => '',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'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' => 'Shortcuts',
'Menu:Change:Shortcuts+' => '',
'Menu:Change:Shortcuts' => 'Changes~~',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'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' => 'Shortcuts',
'Menu:Change:Shortcuts+' => '',
'Menu:Change:Shortcuts' => 'Changes',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes',
'Menu:WaitingAcceptance' => 'Changes awaiting acceptance',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Changes awaiting approval',
'Menu:WaitingApproval+' => '',
'Menu:WaitingApproval+' => 'Changes in planned status',
'Menu:Changes' => 'Open changes',
'Menu:Changes+' => 'All open changes',
'Menu:Changes+' => 'All changes which are not in closed status',
'Menu:MyChanges' => 'Changes assigned to me',
'Menu:MyChanges+' => 'Changes assigned to me (as Agent)',
'Menu:MyChanges+' => 'Non-closed changes assigned to me (as an 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' => 'Shortcuts',
'Menu:Change:Shortcuts+' => '',
'Menu:Change:Shortcuts' => 'Changes~~',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:WaitingAcceptance' => 'Changes awaiting acceptance',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Changes awaiting approval',
'Menu:WaitingApproval+' => '',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:Changes' => 'Open changes',
'Menu:Changes+' => 'All open changes',
'Menu:Changes+' => 'All changes which are not in closed status',
'Menu:MyChanges' => 'Changes assigned to me',
'Menu:MyChanges+' => 'Changes assigned to me (as Agent)',
'Menu:MyChanges+' => 'Non-closed changes assigned to me (as an 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' => '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',
'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é',
'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+' => '',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:WaitingAcceptance' => 'Modifiche in attesa di accettazione',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Modifiche in attesa di approvazione',
'Menu:WaitingApproval+' => '',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'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+' => '',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:WaitingAcceptance' => '受理待ちの変更',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => '承認待ちの変更',
'Menu:WaitingApproval+' => '',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:Changes' => 'オープン状態の変更',
'Menu:Changes+' => '',
'Menu:Changes+' => 'All changes which are not in closed status~~',
'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+' => '',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:WaitingAcceptance' => 'Changes die acceptatie vereisen',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Changes die goedkeuring vereisen',
'Menu:WaitingApproval+' => '',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'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+' => '',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:WaitingAcceptance' => 'Zmiany do akceptacji',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Zmiany do zatwierdzenia',
'Menu:WaitingApproval+' => '',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'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+' => '',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:WaitingAcceptance' => 'Mudanças aguardando aceitação',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Mudanças aguardando aprovação',
'Menu:WaitingApproval+' => '',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:Changes' => 'Mudanças abertas',
'Menu:Changes+' => '',
'Menu:Changes+' => 'All changes which are not in closed status~~',
'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+' => '~~',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:Changes' => 'Otvorené zmeny',
'Menu:Changes+' => 'All open changes~~',
'Menu:Changes+' => 'All changes which are not in closed status~~',
'Menu:MyChanges' => 'Zmeny pridelené mne',
'Menu:MyChanges+' => 'Changes assigned to me (as Agent)~~',
'Menu:MyChanges+' => 'Non-closed changes assigned to me (as an 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+' => '',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:WaitingAcceptance' => 'Kabul bekleyen değişiklik talepleri',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Onay bekleyen değişiklik talepleri',
'Menu:WaitingApproval+' => '',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:Changes' => 'Açık değişiklikler',
'Menu:Changes+' => '',
'Menu:Changes+' => 'All changes which are not in closed status~~',
'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+' => '',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:WaitingAcceptance' => '等待审核的变更',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => '等待批准的变更',
'Menu:WaitingApproval+' => '',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'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+' => '',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:WaitingAcceptance' => 'Změny čekající na přijetí',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Změny čekající na schválení',
'Menu:WaitingApproval+' => '',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'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+' => '',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:WaitingAcceptance' => 'Changes der afventer accept',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Changes der afventer godkendelse',
'Menu:WaitingApproval+' => '',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:Changes' => 'Åbne Changes',
'Menu:Changes+' => '',
'Menu:Changes+' => 'All changes which are not in closed status~~',
'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' => 'Shortcuts',
'Menu:Change:Shortcuts+' => '',
'Menu:Change:Shortcuts' => 'Changes~~',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'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' => 'Shortcuts',
'Menu:Change:Shortcuts+' => '',
'Menu:WaitingAcceptance' => 'Changes awaiting acceptance',
'Menu:Change:Shortcuts' => 'Changes',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes',
'Menu:WaitingAcceptance' => 'Awaiting acceptance',
'Menu:WaitingAcceptance+' => '',
'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)',
'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)',
'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' => 'Shortcuts',
'Menu:Change:Shortcuts+' => '',
'Menu:Change:Shortcuts' => 'Changes~~',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:WaitingAcceptance' => 'Changes awaiting acceptance',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Changes awaiting approval',
'Menu:WaitingApproval+' => '',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:Changes' => 'Open changes',
'Menu:Changes+' => 'All open changes',
'Menu:Changes+' => 'All changes which are not in closed status',
'Menu:MyChanges' => 'Changes assigned to me',
'Menu:MyChanges+' => 'Changes assigned to me (as Agent)',
'Menu:MyChanges+' => 'Non-closed changes assigned to me (as an 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' => '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',
'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é',
'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+' => '~~',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'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+' => '',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:WaitingAcceptance' => '受け付け待ちの変更',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => '承認待ちの変更',
'Menu:WaitingApproval+' => '',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:Changes' => 'オープンな変更',
'Menu:Changes+' => '',
'Menu:Changes+' => 'All changes which are not in closed status~~',
'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+' => '',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:WaitingAcceptance' => 'Changes die acceptatie vereisen',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Changes die goedkeuring vereisen',
'Menu:WaitingApproval+' => '',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'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+' => '',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:WaitingAcceptance' => 'Zmiany do akceptacji',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Zmiany do zatwierdzenia',
'Menu:WaitingApproval+' => '',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'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+' => '',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:WaitingAcceptance' => 'Mudanças aguardando aceitação',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => 'Mudanças aguardando aprovação',
'Menu:WaitingApproval+' => '',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'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+' => '~~',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:Changes' => 'Otvorené zmeny',
'Menu:Changes+' => 'All open changes~~',
'Menu:Changes+' => 'All changes which are not in closed status~~',
'Menu:MyChanges' => 'Zmeny pridelené mne',
'Menu:MyChanges+' => 'Changes assigned to me (as Agent)~~',
'Menu:MyChanges+' => 'Non-closed changes assigned to me (as an 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+' => '~~',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:Changes' => 'Açık değişiklikler',
'Menu:Changes+' => 'All open changes~~',
'Menu:Changes+' => 'All changes which are not in closed status~~',
'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+' => '',
'Menu:Change:Shortcuts+' => 'Shortcuts to predefined sets of Changes~~',
'Menu:WaitingAcceptance' => '等待审核的变更',
'Menu:WaitingAcceptance+' => '',
'Menu:WaitingApproval' => '等待批准的变更',
'Menu:WaitingApproval+' => '',
'Menu:WaitingApproval+' => 'Changes in planned status~~',
'Menu:Changes' => '所有打开的变更',
'Menu:Changes+' => '所有打开的变更',
'Menu:MyChanges' => '分配给我的变更',

View File

@@ -1,9 +0,0 @@
<?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,7 +32,6 @@ 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',
@@ -106,6 +105,7 @@ if (!class_exists('ConfigMgmtInstaller')) {
*/
public static function AfterDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
{
}
}
}

View File

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

View File

@@ -166,8 +166,6 @@ 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+' => '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:Problem:Shortcuts' => 'Odkazy',
'Menu:FAQCategory' => 'Kategorie FAQ',
'Menu:FAQCategory+' => '',
'Menu:FAQCategory+' => 'A typology to categorize frequently asked questions (FAQ)~~',
'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+' => '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:Problem:Shortcuts' => 'Genvej',
'Menu:FAQCategory' => 'FAQ-Kategorier',
'Menu:FAQCategory+' => '',
'Menu:FAQCategory+' => 'A typology to categorize frequently asked questions (FAQ)~~',
'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+' => '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:Problem:Shortcuts' => 'Shortcuts',
'Menu:FAQCategory' => 'FAQ-Kategorien',
'Menu:FAQCategory+' => '',
'Menu:FAQCategory+' => 'A typology to categorize frequently asked questions (FAQ)~~',
'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+' => '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:Problem:Shortcuts' => 'Shortcuts',
'Menu:FAQCategory' => 'FAQ categories',
'Menu:FAQCategory+' => 'All FAQ categories',
'Menu:FAQCategory+' => 'A typology to categorize frequently asked questions (FAQ)',
'Menu:FAQ' => 'FAQs',
'Menu:FAQ+' => 'All FAQs',
'Menu:FAQ+' => 'All Frequently Asked Questions',
'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+' => '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:Problem:Shortcuts' => 'Shortcuts',
'Menu:FAQCategory' => 'FAQ categories',
'Menu:FAQCategory+' => 'All FAQ categories',
'Menu:FAQCategory+' => 'A typology to categorize frequently asked questions (FAQ)',
'Menu:FAQ' => 'FAQs',
'Menu:FAQ+' => 'All FAQs',
'Menu:FAQ+' => 'All Frequently Asked Questions',
'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+' => 'GestAdministraciónió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: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+' => 'Typologie. Segmentation des Questions fréquement posées (FAQ)',
'Class:FAQCategory+' => 'Segmentation de la Foire Aux Questions (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+' => '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: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+' => '',
'Menu:ProblemManagement+' => 'An ITIL process that identifies root causes of incidents, documents Known Errors and FAQs, in order to reduce helpdesk workload~~',
'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+' => '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: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+' => '問題管理',
'Menu:ProblemManagement+' => 'An ITIL process that identifies root causes of incidents, documents Known Errors and FAQs, in order to reduce helpdesk workload~~',
'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+' => '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: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+' => '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: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+' => '',
'Menu:ProblemManagement+' => 'An ITIL process that identifies root causes of incidents, documents Known Errors and FAQs, in order to reduce helpdesk workload~~',
'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+' => 'Управление проблемами',
'Menu:ProblemManagement+' => 'An ITIL process that identifies root causes of incidents, documents Known Errors and FAQs, in order to reduce helpdesk workload~~',
'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+' => '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:Problem:Shortcuts' => 'Shortcuts~~',
'Menu:FAQCategory' => 'FAQ categories~~',
'Menu:FAQCategory+' => 'All FAQ categories~~',
'Menu:FAQCategory+' => 'A typology to categorize frequently asked questions (FAQ)~~',
'Menu:FAQ' => 'FAQs~~',
'Menu:FAQ+' => 'All FAQs~~',
'Menu:FAQ+' => 'All Frequently Asked Questions~~',
'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+' => '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: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+' => '问题管理',
'Menu:ProblemManagement+' => 'An ITIL process that identifies root causes of incidents, documents Known Errors and FAQs, in order to reduce helpdesk workload~~',
'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 (count($oExtension->aMissingDependencies) > 0) {
if ($oExtension->HasDependencyIssue()) {
$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,8 +133,7 @@ class HubController
throw new Exception('Sorry the installation of extensions is not allowed in demo mode');
}
$aSelectModules = $oRuntimeEnv->CompileFrom('production'); // WARNING symlinks does not seem to be compatible with manual Commit
$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,6 +1767,13 @@
<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,6 +25,8 @@ 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,10 +24,12 @@ 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+' => '',
'Menu:Incident:EscalatedIncidents+' => 'Incident which are under escalation, by status or hot flag~~',
'Menu:Incident:OpenIncidents' => 'Alle åbne Incidents',
'Menu:Incident:OpenIncidents+' => '',
'Menu:Incident:OpenIncidents+' => 'All incidents that are not closed~~',
'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,10 +20,12 @@ 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' => 'Shortcuts',
'Menu:Incident:Shortcuts' => 'Incidents',
'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,14 +31,16 @@ 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' => 'Shortcuts',
'Menu:Incident:Shortcuts' => 'Incidents',
'Menu:Incident:Shortcuts+' => '',
'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+' => '',
'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',
'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',
@@ -134,7 +136,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+' => '',
'Class:Incident/Attribute:escalation_flag+' => 'When set, the Ticket is added to the "Under escalation" menu',
'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,14 +31,16 @@ 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' => 'Shortcuts',
'Menu:Incident:Shortcuts' => 'Incidents',
'Menu:Incident:Shortcuts+' => '',
'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+' => '',
'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~~',
'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,6 +21,8 @@ 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,13 +19,15 @@ 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' => 'Raccourcis',
'Menu:Incident:Shortcuts' => 'Incidents',
'Menu:Incident:Shortcuts+' => '',
'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: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: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',
@@ -120,7 +122,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+' => '',
'Class:Incident/Attribute:escalation_flag+' => 'Ce Ticket sera ajouté au menu des incidents en cours d\'escalade',
'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,6 +23,8 @@ 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,6 +23,8 @@ 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