mirror of
https://github.com/Combodo/iTop.git
synced 2026-08-03 04:18:18 +02:00
Compare commits
106 Commits
feature/63
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5c8a98695 | ||
|
|
1403914572 | ||
|
|
b976471a0d | ||
|
|
47981f78e3 | ||
|
|
476ec75a2e | ||
|
|
10c000ddfe | ||
|
|
7e55b9ccfc | ||
|
|
5bb288ffca | ||
|
|
56d7e40f4c | ||
|
|
e0dc1fa571 | ||
|
|
d6466c0bd6 | ||
|
|
eb16e6cbc8 | ||
|
|
42007ffd95 | ||
|
|
6329c157e8 | ||
|
|
9ee0548767 | ||
|
|
620a6b9a51 | ||
|
|
968c56745a | ||
|
|
04a5e5463a | ||
|
|
006dd3d6c2 | ||
|
|
a808e89c30 | ||
|
|
c6e50a0ed7 | ||
|
|
d88687527e | ||
|
|
2cc071b07a | ||
|
|
76a410e00d | ||
|
|
c68887c2bc | ||
|
|
837b433622 | ||
|
|
52fca750b0 | ||
|
|
a5c14e4870 | ||
|
|
0e72b090ee | ||
|
|
d1aedee245 | ||
|
|
1b70b4bf70 | ||
|
|
41f51a2c0c | ||
|
|
73ede13443 | ||
|
|
40dd72ef82 | ||
|
|
c8aea56171 | ||
|
|
041437cbeb | ||
|
|
85d50f31bd | ||
|
|
5715e0484f | ||
|
|
109fdfa06b | ||
|
|
3c301affb3 | ||
|
|
147fae7f8c | ||
|
|
a5aa8c279f | ||
|
|
13fad9efc1 | ||
|
|
9fbc53cf00 | ||
|
|
04f91ab4a2 | ||
|
|
918f110dc9 | ||
|
|
8e0246601a | ||
|
|
bd9cc9c15e | ||
|
|
60ce21509f | ||
|
|
e6cdcd0a5a | ||
|
|
2ab3081926 | ||
|
|
5cabac63e7 | ||
|
|
3918dcf830 | ||
|
|
489300552a | ||
|
|
8507c606ba | ||
|
|
128989450b | ||
|
|
1bd404af6f | ||
|
|
6c770d3e16 | ||
|
|
a74dbb3a73 | ||
|
|
b365aa0971 | ||
|
|
56aa50c9b1 | ||
|
|
eacb7f3401 | ||
|
|
b14045af29 | ||
|
|
7321eeb23f | ||
|
|
05b8c529fe | ||
|
|
a68c017225 | ||
|
|
82b52b95a1 | ||
|
|
556f612f7e | ||
|
|
edc69bebba | ||
|
|
dce1994b85 | ||
|
|
fde6527057 | ||
|
|
0de0592c18 | ||
|
|
c9d512cc31 | ||
|
|
a3ef049063 | ||
|
|
87ec702c5e | ||
|
|
127be1933d | ||
|
|
2c14030fc5 | ||
|
|
7825c08069 | ||
|
|
4ddf17233f | ||
|
|
9493bb03d5 | ||
|
|
8f87c759b5 | ||
|
|
348c90145d | ||
|
|
c37143176a | ||
|
|
0c8229a68e | ||
|
|
fda5fe5ded | ||
|
|
6b396adeea | ||
|
|
c448f8411c | ||
|
|
4b4fe55060 | ||
|
|
dedcd4af19 | ||
|
|
0556a03839 | ||
|
|
64df429715 | ||
|
|
9ae813db2b | ||
|
|
768423a6aa | ||
|
|
921e7c88fe | ||
|
|
d6ef4fb7bb | ||
|
|
a335e1004b | ||
|
|
e882df96d9 | ||
|
|
3a7439e970 | ||
|
|
7fca6424ab | ||
|
|
f09a73c45a | ||
|
|
5a174dd8fa | ||
|
|
01f32086ec | ||
|
|
5c59fdebaf | ||
|
|
363d0767d5 | ||
|
|
5202adb902 | ||
|
|
1d9e7f9b55 |
@@ -2,13 +2,17 @@
|
||||
|
||||
```mermaid
|
||||
%%{init: { 'logLevel': 'debug', 'theme': 'base', 'themeVariables': {
|
||||
'git0': 'lawngreen',
|
||||
'git3': 'dodgerblue',
|
||||
'git4': 'grey',
|
||||
'git5': 'grey',
|
||||
'git6': 'grey',
|
||||
'git7': 'grey',
|
||||
'git8': 'grey'
|
||||
'git0': '#7ccf00',
|
||||
'git1': '#7ccf00',
|
||||
'git2': '#99a1af',
|
||||
'git3': '#99a1af',
|
||||
'git4': '#99a1af',
|
||||
'git5': '#99a1af',
|
||||
'git6': '#99a1af',
|
||||
'git7': '#99a1af',
|
||||
'git8': '#99a1af',
|
||||
'git9': '#99a1af',
|
||||
'git10': '#99a1af'
|
||||
}, 'gitGraph': {'showBranches': true,'mainBranchName': 'develop','rotateCommitLabel': true}} }%%
|
||||
gitGraph
|
||||
commit id: "2016-07-06" tag: "2.3.0" type: HIGHLIGHT
|
||||
@@ -106,6 +110,8 @@ gitGraph
|
||||
commit id: "2025-09-25" tag: "2.7.13"
|
||||
checkout support/3.2
|
||||
commit id: "2026-04-27 " tag: "3.2.3"
|
||||
checkout develop
|
||||
commit id: "2026-07-23" tag: "3.3.0-beta1"
|
||||
```
|
||||
|
||||
To learn more, check the [iTop community versions history on the official wiki](https://www.itophub.io/wiki/page?id=latest:release:start).
|
||||
|
||||
5
.github/pull_request_template.md
vendored
5
.github/pull_request_template.md
vendored
@@ -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
0
.make/license/gen-community-license.sh
Normal file → Executable file
0
.make/license/sortLicenceXml.php
Normal file → Executable file
0
.make/license/sortLicenceXml.php
Normal file → Executable file
0
.make/license/updateLicenses.php
Normal file → Executable file
0
.make/license/updateLicenses.php
Normal file → Executable file
0
.make/release/changelog.php
Normal file → Executable file
0
.make/release/changelog.php
Normal file → Executable file
0
.make/release/update-versions.php
Normal file → Executable file
0
.make/release/update-versions.php
Normal file → Executable file
0
.make/release/update-xml.php
Normal file → Executable file
0
.make/release/update-xml.php
Normal file → Executable file
0
.make/release/update.classes.inc.php
Normal file → Executable file
0
.make/release/update.classes.inc.php
Normal file → Executable file
@@ -582,16 +582,30 @@ 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 (!array_key_exists('profile_list', $oUser->ListChanges())) {
|
||||
// Profiles list is not modified on the $oUser object, we can use DBObjectSearch with `all data` capabilities
|
||||
// Note: This is the default behavior
|
||||
$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 {
|
||||
// Profiles list must be computed with memory changes.
|
||||
// Note: this is a bit tricky because the user object may have been modified in memory (e.g. a profile added or removed) and we need to take that into account
|
||||
$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 +719,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 +753,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 +837,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 +902,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');
|
||||
|
||||
@@ -1046,7 +1046,7 @@ HTML
|
||||
// Add extra data for markup generation
|
||||
// - Attribute code and AttributeDef. class
|
||||
$val['attcode'] = $sAttCode;
|
||||
$val['atttype'] = $oAttDef->GetType();
|
||||
$val['atttype'] = $oAttDef->GetTypeShortClassName();
|
||||
$val['attlabel'] = $sAttLabel;
|
||||
$val['attflags'] = ($bEditMode) ? $this->GetFormAttributeFlags($sAttCode) : OPT_ATT_READONLY;
|
||||
|
||||
@@ -4507,7 +4507,7 @@ HTML;
|
||||
|
||||
$oDivField = FieldUIBlockFactory::MakeLarge("");
|
||||
// UIContentBlockUIBlockFactory::MakeStandard(null,["field_container field_large"]);
|
||||
$oDivField->AddDataAttribute("attribute-type", $oAttDef->GetType());
|
||||
$oDivField->AddDataAttribute("attribute-type", $oAttDef->GetTypeShortClassName());
|
||||
$oDivField->AddDataAttribute("attribute-label", $sAttMetaDataLabel);
|
||||
$oDivField->AddDataAttribute("attribute-flag-hidden", false);
|
||||
$oDivField->AddDataAttribute("attribute-flag-read-only", false);
|
||||
|
||||
@@ -501,7 +501,7 @@ EOF
|
||||
*/
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = [], $bCanEdit = true)
|
||||
{
|
||||
$aExtraParams['dashboard_div_id'] = utils::Sanitize($aExtraParams['dashboard_div_id'] ?? null, $this->GetId(), utils::ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER);
|
||||
$aExtraParams['dashboard_div_id'] = utils::Sanitize($aExtraParams['dashboard_div_id'] ?? $this->GetId(), $this->GetId(), utils::ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER);
|
||||
|
||||
/** @var \DashboardLayoutMultiCol $oLayout */
|
||||
$oLayout = new $this->sLayoutClass();
|
||||
|
||||
@@ -25,11 +25,11 @@
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\Branding;
|
||||
use Combodo\iTop\Application\Helper\Session;
|
||||
use Combodo\iTop\Application\WebPage\ErrorPage;
|
||||
use Combodo\iTop\Application\WebPage\NiceWebPage;
|
||||
use Combodo\iTop\Service\Events\EventData;
|
||||
use Combodo\iTop\Service\Events\EventService;
|
||||
use Combodo\iTop\Service\Session\Session;
|
||||
|
||||
/**
|
||||
* Web page used for displaying the login form
|
||||
@@ -369,16 +369,7 @@ class LoginWebPage extends NiceWebPage
|
||||
public static function ResetSession()
|
||||
{
|
||||
// Unset all of the session variables.
|
||||
Session::Unset('auth_user');
|
||||
Session::Unset('login_state');
|
||||
Session::Unset('can_logoff');
|
||||
Session::Unset('archive_mode');
|
||||
Session::Unset('impersonate_user');
|
||||
Session::Unset('PluginProperties');
|
||||
Session::Unset('UrlMakerClass');
|
||||
Session::Unset('itop_env');
|
||||
Session::Unset('obj_messages');
|
||||
Session::Unset('profile_list');
|
||||
Session::UnsetAll();
|
||||
UserRights::_ResetSessionCache();
|
||||
// If it's desired to kill the session, also delete the session cookie.
|
||||
// Note: This will destroy the session, and not just the session data!
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
14
composer.lock
generated
14
composer.lock
generated
@@ -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": [
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -730,13 +730,8 @@ abstract class DBObject implements iDisplay
|
||||
public function SetTrim($sAttCode, $sValue)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
|
||||
$iMaxSize = $oAttDef->GetMaxSize();
|
||||
$sLength = mb_strlen($sValue);
|
||||
if ($iMaxSize && ($sLength > $iMaxSize)) {
|
||||
$sMessage = " -truncated ($sLength chars)";
|
||||
$sValue = mb_substr($sValue, 0, $iMaxSize - mb_strlen($sMessage)).$sMessage;
|
||||
}
|
||||
$this->Set($sAttCode, $sValue);
|
||||
|
||||
$this->Set($sAttCode, $oAttDef->TrimValue($sValue));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2038,7 +2033,7 @@ abstract class DBObject implements iDisplay
|
||||
}
|
||||
}
|
||||
if (!is_null($iMaxSize = $oAtt->GetMaxSize())) {
|
||||
$iLen = mb_strlen($toCheck);
|
||||
$iLen = $oAtt->GetSize($toCheck);
|
||||
if ($iLen > $iMaxSize) {
|
||||
return "String too long (found $iLen, limited to $iMaxSize)";
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
$ibo-user-rights--padding-x: $ibo-spacing-400 !default;
|
||||
$ibo-user-rights--padding-y: $ibo-spacing-200 !default;
|
||||
$ibo-user-rights--padding-y: $ibo-spacing-100 !default;
|
||||
$ibo-user-rights--border-radius: $ibo-border-radius-400 !default;
|
||||
|
||||
$ibo-user-rights--is-success--background-color: $ibo-color-success-100 !default;
|
||||
@@ -18,6 +18,8 @@ $ibo-user-rights--is-failure--border-color: $ibo-color-danger-500 !default;
|
||||
$ibo-user-rights--is-failure--border: 1px solid $ibo-user-rights--is-failure--border-color !default;
|
||||
|
||||
.ibo-user-rights {
|
||||
display: inline-flex;
|
||||
align-items: baseline;
|
||||
padding: $ibo-user-rights--padding-y $ibo-user-rights--padding-x;
|
||||
border-radius: $ibo-user-rights--border-radius;
|
||||
&.ibo-is-success {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
|
||||
@@ -8,70 +8,74 @@
|
||||
padding-bottom: 14px;
|
||||
}
|
||||
|
||||
.help-text{
|
||||
padding: 1px 5px;
|
||||
background-color: #d7e3f8;
|
||||
border: 1px solid #c6e7f5;
|
||||
border-radius: 5px;
|
||||
margin: 5px 0;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.form-error ul{
|
||||
padding: 1px 5px;
|
||||
background-color: #f8d7da;
|
||||
border: 1px solid #f5c6cb;
|
||||
border-radius: 5px;
|
||||
margin: 5px 0;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.subform{
|
||||
background-color: #efefef;
|
||||
border-radius: 5px;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.form-buttons{
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.form select{
|
||||
padding: 0;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.form select option{
|
||||
height: 30px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.turbo-refreshing{
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
.ibo-field legend{
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
collection-entry-element {
|
||||
margin-top: 8px;
|
||||
display: block;
|
||||
padding: 10px 10px;
|
||||
background-color: #f5f5f5;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.ts-control{
|
||||
height: auto;
|
||||
min-height: 30px;
|
||||
}
|
||||
|
||||
.ibo-form-actions > .ibo-button > span{
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.ibo-form textarea{
|
||||
resize: vertical;
|
||||
}
|
||||
|
||||
// WIP SDK Forms
|
||||
//form[is="itop-form-element"] {
|
||||
//
|
||||
// .help-text{
|
||||
// padding: 1px 5px;
|
||||
// background-color: #d7e3f8;
|
||||
// border: 1px solid #c6e7f5;
|
||||
// border-radius: 5px;
|
||||
// margin: 5px 0;
|
||||
// font-size: 0.9em;
|
||||
// }
|
||||
//
|
||||
// .form-error ul{
|
||||
// padding: 1px 5px;
|
||||
// background-color: #f8d7da;
|
||||
// border: 1px solid #f5c6cb;
|
||||
// border-radius: 5px;
|
||||
// margin: 5px 0;
|
||||
// font-size: 0.9em;
|
||||
// }
|
||||
//
|
||||
// .subform{
|
||||
// background-color: #efefef;
|
||||
// border-radius: 5px;
|
||||
// padding: 10px;
|
||||
// }
|
||||
//
|
||||
// .form-buttons{
|
||||
// margin: 20px 0;
|
||||
// }
|
||||
//
|
||||
// .form select{
|
||||
// padding: 0;
|
||||
// overflow-y: auto;
|
||||
// }
|
||||
//
|
||||
// .form select option{
|
||||
// height: 30px;
|
||||
// display: flex;
|
||||
// align-items: center;
|
||||
// }
|
||||
//
|
||||
// .turbo-refreshing{
|
||||
// opacity: .5;
|
||||
// }
|
||||
//
|
||||
// .ibo-field legend{
|
||||
// margin-top: 24px;
|
||||
// }
|
||||
//
|
||||
// collection-entry-element {
|
||||
// margin-top: 8px;
|
||||
// display: block;
|
||||
// padding: 10px 10px;
|
||||
// background-color: #f5f5f5;
|
||||
// border-radius: 5px;
|
||||
// }
|
||||
// .ts-control{
|
||||
// height: auto;
|
||||
// min-height: 30px;
|
||||
// }
|
||||
//
|
||||
// .ibo-form-actions > .ibo-button > span{
|
||||
// margin-right: 5px;
|
||||
// }
|
||||
//
|
||||
// .ibo-form textarea{
|
||||
// resize: vertical;
|
||||
// }
|
||||
//
|
||||
//}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -70,7 +70,7 @@ $ibo-vendors-ckeditor--ck-mentions--item--padding-y: $ibo-spacing-200 !default;
|
||||
}
|
||||
}
|
||||
|
||||
.ck-editor__editable_inline:not(.ck-comment__input *) {
|
||||
.ck-editor__editable_inline:not(.ck-comment__input *), .ck-source-editing-area {
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
@@ -84,11 +84,6 @@ $ibo-vendors-ckeditor--ck-mentions--item--padding-y: $ibo-spacing-200 !default;
|
||||
}
|
||||
}
|
||||
|
||||
// N°7552 Allow source editing area to be scrollable in full screen
|
||||
.ck-maximize_editor_main .ck-source-editing-area textarea{
|
||||
overflow: auto !important;
|
||||
}
|
||||
|
||||
/* Mentions */
|
||||
.ck-mentions {
|
||||
.ck-button {
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -20,6 +20,7 @@ Dict::Add('EN US', 'English', 'English', [
|
||||
|
||||
'DataFeatureRemoval:Features:Title' => 'Extensions',
|
||||
'DataFeatureRemoval:Result:Title' => 'Modification requested',
|
||||
'DataFeatureRemoval:NoResult:Title' => 'No modification requested',
|
||||
'DataFeatureRemoval:Execution:Title' => 'Deletion Executions',
|
||||
'DataFeatureRemoval:Analysis:Title' => 'Analysis result',
|
||||
'DataFeatureRemoval:Analysis:Subtitle' => 'Review all elements requiring attention',
|
||||
@@ -39,6 +40,14 @@ Dict::Add('EN US', 'English', 'English', [
|
||||
'DataFeatureRemoval:CleanupComplete:Title' => 'All clear.',
|
||||
'DataFeatureRemoval:CompilComplete' => 'Compilation successful. No Cleanup needed. You can proceed to setup.',
|
||||
|
||||
'DataFeatureRemoval:Compile:InProgress' => 'Compilation in progress...',
|
||||
'DataFeatureRemoval:Compile:Success' => 'Compilation successful',
|
||||
'DataFeatureRemoval:Compile:Error' => 'Compilation error',
|
||||
|
||||
'DataFeatureRemoval:RunAudit:InProgress' => 'Analysis in progress...',
|
||||
'DataFeatureRemoval:RunAudit:Success' => 'Analysis completed',
|
||||
'DataFeatureRemoval:RunAudit:Error' => 'Error during analysis',
|
||||
|
||||
'UI:Button:Analyze' => 'Analyze',
|
||||
'UI:Button:ModifyChoices' => 'Change my selection',
|
||||
'UI:Button:AnalyzeAndSetup' => 'Analyze and go to setup',
|
||||
|
||||
@@ -20,6 +20,7 @@ Dict::Add('FR FR', 'French', 'Français', [
|
||||
|
||||
'DataFeatureRemoval:Features:Title' => 'Extensions',
|
||||
'DataFeatureRemoval:Result:Title' => 'Modification demandée',
|
||||
'DataFeatureRemoval:NoResult:Title' => 'Aucune modification demandée',
|
||||
'DataFeatureRemoval:Execution:Title' => 'Suppressions',
|
||||
'DataFeatureRemoval:Analysis:Title' => 'Résultat de l’analyse',
|
||||
'DataFeatureRemoval:Analysis:Subtitle' => 'Vérifier les éléments à nettoyer',
|
||||
@@ -39,6 +40,14 @@ Dict::Add('FR FR', 'French', 'Français', [
|
||||
'DataFeatureRemoval:CleanupComplete:Title' => 'All clear.',
|
||||
'DataFeatureRemoval:CompilComplete' => 'Compilation successful. No Cleanup needed. You can proceed to setup.',
|
||||
|
||||
'DataFeatureRemoval:Compile:InProgress' => 'Compilation en cours...',
|
||||
'DataFeatureRemoval:Compile:Success' => 'Compilation terminée',
|
||||
'DataFeatureRemoval:Compile:Error' => 'Erreur lors de la compilation',
|
||||
|
||||
'DataFeatureRemoval:RunAudit:InProgress' => 'Analyse en cours...',
|
||||
'DataFeatureRemoval:RunAudit:Success' => 'Analyse terminée',
|
||||
'DataFeatureRemoval:RunAudit:Error' => 'Erreur lors de l\'analyse',
|
||||
|
||||
'UI:Button:Analyze' => 'Analyser',
|
||||
'UI:Button:ModifyChoices' => 'Modifier la sélection',
|
||||
'UI:Button:AnalyzeAndSetup' => 'Analyser et ouvrir l’assistant de configuration',
|
||||
|
||||
@@ -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,22 @@ 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();
|
||||
$oParameters = new SessionParameters(SetupUtils::SESSION_PARAMETERS_NAME);
|
||||
$oParameters->Erase();
|
||||
Session::Unset('aDeletionExecutionSummary');
|
||||
Session::Set('bForceCompilation', true);
|
||||
$oParameters->SetParameter('return_application', 'DataFeatureRemoval');
|
||||
|
||||
$this->AddAnalyzeParams();
|
||||
$aParams['sTransactionId'] = utils::GetNewTransactionId();
|
||||
$aParams['iColumnCount'] = $this->iColumnCount;
|
||||
@@ -57,7 +64,6 @@ class DataFeatureRemovalController extends Controller
|
||||
$aParams['sSetupUrl'] = utils::GetAbsoluteUrlAppRoot().'setup';
|
||||
$aParams['iCount'] = $this->iCount;
|
||||
|
||||
Session::Set('bForceCompilation', true);
|
||||
$this->AddLinkedStylesheet(utils::GetAbsoluteUrlModulesRoot().DataFeatureRemovalHelper::MODULE_NAME.'/assets/css/DataFeatureRemoval.css');
|
||||
$this->AddLinkedScript(utils::GetAbsoluteUrlModulesRoot().DataFeatureRemovalHelper::MODULE_NAME.'/assets/js/DataFeatureRemoval.js');
|
||||
$this->DisplayPage($aParams);
|
||||
@@ -91,7 +97,7 @@ class DataFeatureRemovalController extends Controller
|
||||
}
|
||||
|
||||
// Display changed extensions
|
||||
$aHiddenInputNames = [
|
||||
$aSetupParameterNames = [
|
||||
'selected_extensions' => '[]',
|
||||
'selected_modules' => '[]',
|
||||
'display_choices' => '',
|
||||
@@ -105,91 +111,38 @@ class DataFeatureRemovalController extends Controller
|
||||
'target_env' => ITOP_DEFAULT_ENV,
|
||||
];
|
||||
|
||||
$aHiddenInputs = [];
|
||||
foreach ($aHiddenInputNames as $sInputName => $defaultValue) {
|
||||
$aHiddenInputs[$sInputName] = utils::ReadPostedParam($sInputName, $defaultValue, utils::ENUM_SANITIZATION_FILTER_RAW_DATA);
|
||||
$oParameters = new SessionParameters(SetupUtils::SESSION_PARAMETERS_NAME);
|
||||
foreach ($aSetupParameterNames as $sInputName => $defaultValue) {
|
||||
$oParameters->SetParameter($sInputName, $oParameters->GetParameter($sInputName, $defaultValue));
|
||||
}
|
||||
$aParams['aHiddenInputs'] = $aHiddenInputs;
|
||||
|
||||
$aAddedExtensions = json_decode($aHiddenInputs['added_extensions'], true);
|
||||
|
||||
$aRemovedExtensions = json_decode($aHiddenInputs['removed_extensions'], true);
|
||||
if ("[]" === $aHiddenInputs['selected_modules']) {
|
||||
$aAddedExtensions = json_decode($oParameters->GetParameter('added_extensions', '[]'), true);
|
||||
$aRemovedExtensions = json_decode($oParameters->GetParameter('removed_extensions', '[]'), true);
|
||||
if ('[]' === $oParameters->GetParameter('selected_modules', '[]')) {
|
||||
//it does not come from setup
|
||||
// we get extensions from 1st screen uiblocks
|
||||
$this->ReadExtensionsDiff();
|
||||
$aHiddenInputs['force-uninstall'] = $this->bForcedUninstallation ? 'on' : '';
|
||||
$oParameters->SetParameter('force-uninstall', $this->bForcedUninstallation ? 'on' : '');
|
||||
$aAddedExtensions = $this->aExtensionsToCheck['to_be_installed'];
|
||||
$aHiddenInputs['added_extensions'] = $this->ConvertIntoSetupFormat($aAddedExtensions);
|
||||
$oParameters->SetParameter('added_extensions', $this->ConvertIntoSetupFormat($aAddedExtensions));
|
||||
|
||||
$aRemovedExtensions = $this->aExtensionsToCheck['to_be_removed'];
|
||||
$aHiddenInputs['removed_extensions'] = $this->ConvertIntoSetupFormat($aRemovedExtensions);
|
||||
$oParameters->SetParameter('removed_extensions', $this->ConvertIntoSetupFormat($aRemovedExtensions));
|
||||
|
||||
$aExtensionsNotUninstallable = $this->aExtensionsToCheck['extensions_not_uninstallable'];
|
||||
$oParameters->SetParameter('extensions_not_uninstallable', $this->ConvertIntoSetupFormat($aExtensionsNotUninstallable));
|
||||
}
|
||||
|
||||
$aRemoveExtensionCodes = array_keys($aRemovedExtensions);
|
||||
|
||||
$aParams['aAddedExtensions'] = $aAddedExtensions;
|
||||
$aParams['aRemovedExtensions'] = $aRemovedExtensions;
|
||||
|
||||
DataFeatureRemovalLog::Debug(__METHOD__.' Extensions given in parameter', null, [
|
||||
'added_extensions' => $aAddedExtensions,
|
||||
'removed_extensions' => $aRemovedExtensions]);
|
||||
|
||||
$aParams['sTransactionId'] = utils::GetNewTransactionId();
|
||||
$aParams['iColumnCount'] = $this->iColumnCount;
|
||||
$aParams['aAvailableExtensions'] = $this->SplitArrayIntoColumns($this->GetExtensionsDiff($aAddedExtensions, $aRemovedExtensions), $this->iColumnCount);
|
||||
|
||||
$bForceCompilation = Session::Get('bForceCompilation', false);
|
||||
try {
|
||||
$this->Compile($aAddedExtensions, $aRemoveExtensionCodes, $bForceCompilation);
|
||||
} catch (CoreException $e) {
|
||||
$aParams['DataFeatureRemovalErrorMessage'] = $e->getHtmlDesc();
|
||||
$this->DisplayPage($aParams, 'AnalysisResult');
|
||||
return;
|
||||
} catch (Exception $e) {
|
||||
$aParams['DataFeatureRemovalErrorMessage'] = $e->getMessage();
|
||||
$this->DisplayPage($aParams, 'AnalysisResult');
|
||||
return;
|
||||
}
|
||||
|
||||
if ("[]" === $aHiddenInputs['selected_modules']) {
|
||||
//to make setup redirection work, we need to pass complex data structures to setup wizards (ie extension/module lists)
|
||||
$oConfig = MetaModel::GetConfig();
|
||||
$aSelectedExtensions = DataFeatureRemoverExtensionService::GetInstance()->GetExtensionMap()->GetSelectedExtensions($oConfig, 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]);
|
||||
|
||||
$aParams['aClasses'] = $aGetRemovedClasses;
|
||||
|
||||
new ContextTag(ContextTag::TAG_SETUP);
|
||||
$aParams['sLaunchSetupUrl'] = utils::GetAbsoluteUrlAppRoot().'setup/wizard.php';
|
||||
$aParams['aSetupParams'] = [
|
||||
"_class" => "WizStepLandingBeforeAudit",
|
||||
"operation" => "next",
|
||||
];
|
||||
|
||||
foreach ($aHiddenInputs as $sInputName => $sInputValue) {
|
||||
$aParams['aSetupParams']["_params[$sInputName]"] = $sInputValue;
|
||||
}
|
||||
|
||||
[$aParams['aDeletionPlanSummary'], $aParams['iQueryCount'], $aParams['bDeletionPossible']] = $this->GetDeletionPlanSummaryTable($aGetRemovedClasses);
|
||||
[$aParams['aDeletionExecutionSummary'], $aParams['bHasDeletionExecution']] = $this->GetExecutionSummaryTable();
|
||||
$aParams['bDeletionNeeded'] = ($aParams['iQueryCount'] > 0);
|
||||
Session::Set('aDeletionExecutionSummary', serialize($this->aDeletionExecutionSummary));
|
||||
|
||||
if (!$aParams['bDeletionNeeded']) {
|
||||
SetupUtils::CreateSetupToken();
|
||||
}
|
||||
$aAvailableExtensions = $this->GetExtensionsDiff($aAddedExtensions, $aRemovedExtensions);
|
||||
$aParams['aAvailableExtensionsCount'] = count($aAvailableExtensions);
|
||||
$aParams['aAvailableExtensions'] = $this->SplitArrayIntoColumns($aAvailableExtensions, $this->iColumnCount);
|
||||
$aParams['sAjaxURL'] = utils::GetAbsoluteUrlModulePage(DataFeatureRemovalHelper::MODULE_NAME, 'index.php');
|
||||
|
||||
$this->DisplayPage($aParams, 'AnalysisResult');
|
||||
}
|
||||
@@ -197,53 +150,124 @@ class DataFeatureRemovalController extends Controller
|
||||
private function ConvertIntoSetupFormat(array $aData): string
|
||||
{
|
||||
$aNewData = [];
|
||||
foreach ($aData as $k => $sVal) {
|
||||
$aNewData[] = sprintf('"%s":"%s"', $k, $sVal);
|
||||
foreach ($aData as $sCode => $sLabel) {
|
||||
$aNewData[] = sprintf('"%s":"%s"', $sCode, $sLabel);
|
||||
}
|
||||
|
||||
return "{".implode(',', $aNewData)."}";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aAddedExtensions
|
||||
* @param array $aRemovedExtensions
|
||||
* @param bool $bForceCompilation
|
||||
* @return void
|
||||
* @throws \ConfigException
|
||||
* @throws \CoreException
|
||||
* @return void
|
||||
* @throws \ConfigException
|
||||
* @throws \CoreException
|
||||
*/
|
||||
private function Compile(array $aAddedExtensions, array $aRemovedExtensions, bool $bForceCompilation = true): void
|
||||
public function OperationAjaxCompile(): void
|
||||
{
|
||||
$aParams = [];
|
||||
//to make setup redirection work, we need to pass complex data structures to setup wizards (ie extension/module lists)
|
||||
$sSourceEnv = MetaModel::GetEnvironment();
|
||||
$sBuildDir = APPROOT."/env-$sSourceEnv-build";
|
||||
if (! is_dir($sBuildDir)) {
|
||||
SetupUtils::builddir($sBuildDir);
|
||||
}
|
||||
$bIsDirEmpty = count(scandir($sBuildDir)) === 2;
|
||||
$oRuntimeEnvironment = new RunTimeEnvironment($sSourceEnv, false);
|
||||
|
||||
if ($bIsDirEmpty || $bForceCompilation) {
|
||||
DataFeatureRemovalLog::Debug(
|
||||
__METHOD__,
|
||||
null,
|
||||
['sSourceEnv' => $sSourceEnv, 'sBuildDir' => $sBuildDir, 'bIsDirEmpty' => $bIsDirEmpty, glob("$sBuildDir/*")]
|
||||
);
|
||||
$this->GetRuntimeEnvironment($aAddedExtensions, $aRemovedExtensions)->CompileFrom($sSourceEnv);
|
||||
$oParameters = new SessionParameters(SetupUtils::SESSION_PARAMETERS_NAME);
|
||||
$aSelectedModules = json_decode($oParameters->GetParameter('selected_modules', '[]'), true);
|
||||
$aSelectedExtensions = json_decode($oParameters->GetParameter('selected_extensions', '[]'), true);
|
||||
$aAddedExtensions = json_decode($oParameters->GetParameter('added_extensions', '[]'), true);
|
||||
$aRemovedExtensions = json_decode($oParameters->GetParameter('removed_extensions', '[]'), true);
|
||||
|
||||
try {
|
||||
$this->ValidateTransactionId();
|
||||
|
||||
$oConfig = MetaModel::GetConfig();
|
||||
if (count($aSelectedModules) === 0) {
|
||||
$aSelectedExtensions = DataFeatureRemoverExtensionService::GetInstance()->GetExtensionMap()->GetSelectedExtensions($oConfig, array_keys($aAddedExtensions), array_keys($aRemovedExtensions));
|
||||
$oParameters->SetParameter('selected_extensions', $this->ConvertIntoSetupFormat($aSelectedExtensions));
|
||||
}
|
||||
|
||||
$sBuildDir = APPROOT."/env-$sSourceEnv-build";
|
||||
if (! is_dir($sBuildDir)) {
|
||||
SetupUtils::builddir($sBuildDir);
|
||||
}
|
||||
$bIsDirEmpty = count(scandir($sBuildDir)) === 2;
|
||||
$bForceCompilation = Session::Get('bForceCompilation', false);
|
||||
if ($bIsDirEmpty || $bForceCompilation) {
|
||||
$oRuntimeEnvironment->CopySetupFiles();
|
||||
if (count($aSelectedModules) === 0) {
|
||||
$aSelectedModules = $oRuntimeEnvironment->GetModulesToLoadFromChoices($oConfig, $aSelectedExtensions);
|
||||
}
|
||||
|
||||
DataFeatureRemovalLog::Debug(
|
||||
__METHOD__,
|
||||
null,
|
||||
['sSourceEnv' => $sSourceEnv, 'sBuildDir' => $sBuildDir, 'bIsDirEmpty' => $bIsDirEmpty, glob("$sBuildDir/*")]
|
||||
);
|
||||
$oRuntimeEnvironment->DoCompile($aSelectedExtensions, $aRemovedExtensions, $aSelectedModules, MFCompiler::CanUseSymbolicLinks());
|
||||
Session::Unset('bForceCompilation');
|
||||
} else {
|
||||
if (count($aSelectedModules) === 0) {
|
||||
$aSelectedModules = $oRuntimeEnvironment->GetModulesToLoadFromChoices($oConfig, $aSelectedExtensions);
|
||||
}
|
||||
}
|
||||
} catch (CoreException $e) {
|
||||
$aParams['error_message'] = $e->getHtmlDesc();
|
||||
} catch (Exception $e) {
|
||||
$aParams['error_message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
$aParams['success_message'] = Dict::S('DataFeatureRemoval:Compile:Success');
|
||||
$aParams['transaction_id'] = utils::GetNewTransactionId();
|
||||
|
||||
$oParameters->SetParameter('selected_modules', json_encode($aSelectedModules));
|
||||
$this->DisplayJSONPage($aParams);
|
||||
}
|
||||
|
||||
private function GetRuntimeEnvironment(array $aAddedExtensions, array $aRemovedExtensions): RunTimeEnvironment
|
||||
public function OperationAjaxRunAudit(): void
|
||||
{
|
||||
if (is_null($this->oRuntimeEnvironment)) {
|
||||
$oParameters = new SessionParameters(SetupUtils::SESSION_PARAMETERS_NAME);
|
||||
$aParams = [];
|
||||
$aPageParams = [];
|
||||
try {
|
||||
$this->ValidateTransactionId();
|
||||
|
||||
$sSourceEnv = MetaModel::GetEnvironment();
|
||||
$this->oRuntimeEnvironment = new DryRemovalRuntimeEnvironment($sSourceEnv, $aAddedExtensions, $aRemovedExtensions);
|
||||
$oSetupAudit = new SetupAudit($sSourceEnv);
|
||||
$aRemovedClasses = array_keys($oSetupAudit->RunDataAudit());
|
||||
$oParameters->SetParameter('classes', $aRemovedClasses);
|
||||
|
||||
new ContextTag(ContextTag::TAG_SETUP);
|
||||
$aPageParams['sLaunchSetupUrl'] = utils::GetAbsoluteUrlAppRoot().'setup/wizard.php';
|
||||
$aPageParams['aSetupParams'] = [
|
||||
"_class" => "WizStepLandingBeforeAudit",
|
||||
"operation" => "next",
|
||||
];
|
||||
$aPageParams['sTransactionId'] = utils::GetNewTransactionId();
|
||||
|
||||
$aDeletionPlanSummaryEntities = $this->GetDeletionPlanSummaryEntities($aRemovedClasses);
|
||||
[$aPageParams['aDeletionPlanSummary'], $aPageParams['iQueryCount'], $aPageParams['bDeletionPossible']] = $this->GetDeletionPlanSummaryTable($aDeletionPlanSummaryEntities);
|
||||
[$aPageParams['aDeletionExecutionSummary'], $aPageParams['bHasDeletionExecution']] = $this->GetExecutionSummaryTable();
|
||||
$aPageParams['bDeletionNeeded'] = ($aPageParams['iQueryCount'] > 0);
|
||||
|
||||
if (!$aPageParams['bDeletionNeeded']) {
|
||||
// Erase session setup parameters
|
||||
SetupUtils::CreateSetupToken();
|
||||
}
|
||||
|
||||
$this->DisplayAjaxPage($aPageParams, 'AjaxRunAudit');
|
||||
return;
|
||||
} catch (CoreException $e) {
|
||||
$aParams['error_message'] = $e->getHtmlDesc();
|
||||
} catch (Exception $e) {
|
||||
$aParams['error_message'] = $e->getMessage();
|
||||
}
|
||||
|
||||
return $this->oRuntimeEnvironment;
|
||||
$this->DisplayJSONPage($aParams);
|
||||
}
|
||||
|
||||
private function GetExecutionSummaryTable(): array
|
||||
{
|
||||
$sName = 'ExcutionSummary';
|
||||
$sName = 'ExecutionSummary';
|
||||
|
||||
$this->aDeletionExecutionSummary = unserialize(Session::Get('aDeletionExecutionSummary') ?? serialize([]));
|
||||
|
||||
$aTableData = [];
|
||||
if (count($this->aDeletionExecutionSummary) === 0) {
|
||||
@@ -269,11 +293,15 @@ class DataFeatureRemovalController extends Controller
|
||||
|
||||
}
|
||||
|
||||
private function GetDeletionPlanSummaryTable(array $aRemovedClasses): array
|
||||
private function GetDeletionPlanSummaryEntities(array $aRemovedClasses): array
|
||||
{
|
||||
$oDataCleanupService = new StaticDeletionPlan();
|
||||
return $oDataCleanupService->GetCleanupSummary($aRemovedClasses);
|
||||
}
|
||||
|
||||
private function GetDeletionPlanSummaryTable(array $aDeletionPlanSummaryEntities): array
|
||||
{
|
||||
$sName = 'DeletionPlanSummary';
|
||||
$oDataCleanupService = new DataCleanupService();
|
||||
$aDeletionPlanSummaryEntities = $oDataCleanupService->GetCleanupSummary($aRemovedClasses);
|
||||
$aColumns = ['Class', 'Delete Count' , 'Update Count', 'Issue Count'];
|
||||
$aRows = [];
|
||||
$iQueryCount = 0;
|
||||
@@ -296,9 +324,10 @@ class DataFeatureRemovalController extends Controller
|
||||
{
|
||||
$this->ValidateTransactionId();
|
||||
|
||||
$this->aDeletionExecutionSummary = unserialize(Session::Get('aDeletionExecutionSummary'));
|
||||
$this->aDeletionExecutionSummary = unserialize(Session::Get('aDeletionExecutionSummary') ?? serialize([]));
|
||||
Session::Unset('aDeletionExecutionSummary');
|
||||
$aClasses = utils::ReadPostedParam('classes', null, utils::ENUM_SANITIZATION_FILTER_CLASS);
|
||||
$oParameters = new SessionParameters(SetupUtils::SESSION_PARAMETERS_NAME);
|
||||
$aClasses = $oParameters->GetParameter('classes', []);
|
||||
|
||||
$oDataCleanupService = new DataCleanupService();
|
||||
$aDeletionExecutionSummary = $oDataCleanupService->ExecuteCleanup($aClasses);
|
||||
@@ -313,6 +342,7 @@ class DataFeatureRemovalController extends Controller
|
||||
$oSummary->iTotalUpdateCount += $oExecutionSummary->iUpdateCount;
|
||||
}
|
||||
|
||||
Session::Set('aDeletionExecutionSummary', serialize($this->aDeletionExecutionSummary));
|
||||
$this->OperationAnalysisResult();
|
||||
}
|
||||
|
||||
@@ -338,6 +368,7 @@ class DataFeatureRemovalController extends Controller
|
||||
'uninstallable' => $oExtension->CanBeUninstalled(),
|
||||
'remote' => $oExtension->IsRemote(),
|
||||
'missing' => $oExtension->bRemovedFromDisk,
|
||||
'dependency_issue' => $oExtension->HasDependencyIssue(),
|
||||
],
|
||||
|
||||
];
|
||||
@@ -405,12 +436,11 @@ class DataFeatureRemovalController extends Controller
|
||||
|
||||
/**
|
||||
* Read extensions selected from posted parameters
|
||||
* @return int Number of extensions to be added or removed
|
||||
*/
|
||||
public function ReadExtensionsDiff(): int
|
||||
public function ReadExtensionsDiff(): void
|
||||
{
|
||||
if (!is_null($this->aExtensionsToCheck)) {
|
||||
return count($this->aExtensionsToCheck['to_be_installed']) + count($this->aExtensionsToCheck['to_be_removed']);
|
||||
return;
|
||||
}
|
||||
|
||||
$aAvailableExtensions = $this->GetAvailableExtensions();
|
||||
@@ -418,6 +448,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,13 +462,15 @@ 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'];
|
||||
$this->aExtensionsToCheck['to_be_installed'][$sCode] = $sLabel;
|
||||
}
|
||||
}
|
||||
return count($this->aExtensionsToCheck['to_be_installed']) + count($this->aExtensionsToCheck['to_be_removed']);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
{# @copyright Copyright (C) 2010-2026 Combodo SARL #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
|
||||
{% if bDeletionNeeded %}
|
||||
{% UIFieldSet Standard {sLegend:'DataFeatureRemoval:DeletionPlan:Title'|dict_s} %}
|
||||
{% UIDataTable ForForm { sRef:'aDeletionPlanSummary', aColumns:aDeletionPlanSummary.Columns, aData:aDeletionPlanSummary.Data} %}{% EndUIDataTable %}
|
||||
{% EndUIFieldSet %}
|
||||
{% if bDeletionPossible %}
|
||||
{% UIForm Standard {} %}
|
||||
{% UIInput ForHidden { sName:'transaction_id', sValue:sTransactionId} %}
|
||||
{% UIInput ForHidden { sName:'operation', sValue:'DoDeletion'} %}
|
||||
{% UIToolbar ForButton {} %}
|
||||
{% UIButton ForPrimaryAction {sLabel:'UI:Button:DoDeletion'|dict_s, sName:'btn_deletion', sId:'btn_deletion', bIsSubmit:true} %}
|
||||
{% EndUIToolbar %}
|
||||
{% EndUIForm %}
|
||||
{% else %}
|
||||
{% UIAlert ForFailure { sTitle: '', sContent: 'DataFeatureRemoval:DeletionPlan:Error:Issues'|dict_s } %}{% EndUIAlert %}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% UIAlert ForSuccess { sTitle:'DataFeatureRemoval:CleanupComplete:Title'|dict_s, sContent:'DataFeatureRemoval:CompilComplete'|dict_s } %}{% EndUIAlert %}
|
||||
|
||||
{% UIForm Standard {sId:'launch-setup-form', Action:sLaunchSetupUrl, EncType: 'application/x-www-form-urlencoded'} %}
|
||||
{% for sKey, sValue in aSetupParams %}
|
||||
{% UIInput ForHidden { sName:sKey, sValue:sValue } %}
|
||||
{% endfor %}
|
||||
{% UIButton ForPrimaryAction {sLabel:'UI:Button:Setup'|dict_s, sName:'btn_setup', sId:'btn_setup', bIsSubmit:true} %}
|
||||
{% EndUIForm %}
|
||||
{% endif %}
|
||||
|
||||
{% if bHasDeletionExecution %}
|
||||
{% UIFieldSet Standard {sLegend:'DataFeatureRemoval:Execution:Title'|dict_s} %}
|
||||
{% UIDataTable ForForm { sRef:'aDeletionExecutionSummary', aColumns:aDeletionExecutionSummary.Columns, aData:aDeletionExecutionSummary.Data} %}{% EndUIDataTable %}
|
||||
{% EndUIFieldSet %}
|
||||
{% endif %}
|
||||
@@ -1,15 +1,31 @@
|
||||
{# @copyright Copyright (C) 2010-2026 Combodo SARL #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
|
||||
|
||||
|
||||
{% UIPanel ForInformation { sTitle:'DataFeatureRemoval:Analysis:Title'|dict_s, sSubTitle: 'DataFeatureRemoval:Analysis:Subtitle'|dict_s} %}
|
||||
{% if null != DataFeatureRemovalErrorMessage %}
|
||||
<div id="feature_removal_error_msg_div" style="display:block">
|
||||
{% UIAlert ForFailure { sTitle:'DataFeatureRemoval:Failure:Title'|dict_s, sId: 'feature_removal_error_msg', sContent:DataFeatureRemovalErrorMessage } %}
|
||||
{% EndUIAlert %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% UIAlert ForInformation { sTitle: '', sId: 'ajax_compile_in_progress_msg', AddCSSClasses: ['ibo-is-hidden', 'ibo-is-html-content'] } %}
|
||||
{{ 'DataFeatureRemoval:Compile:InProgress'|dict_s }}
|
||||
{% UISpinner Standard { } %}
|
||||
{% EndUIAlert %}
|
||||
{% UIAlert ForSuccess { sTitle:'success', sId: 'ajax_compile_success_msg', AddCSSClasses: ['ibo-is-hidden', 'ibo-is-html-content'] } %}{% EndUIAlert %}
|
||||
{% UIAlert ForFailure { sTitle:'error', sId: 'ajax_compile_error_msg', AddCSSClasses: ['ibo-is-hidden', 'ibo-is-html-content'] } %}{% EndUIAlert %}
|
||||
|
||||
{% UIAlert ForInformation { sTitle: '', sId: 'ajax_run_audit_in_progress_msg', AddCSSClasses: ['ibo-is-hidden', 'ibo-is-html-content'] } %}
|
||||
{{ 'DataFeatureRemoval:RunAudit:InProgress'|dict_s }}
|
||||
{% UISpinner Standard { } %}
|
||||
{% EndUIAlert %}
|
||||
{% UIAlert ForSuccess { sTitle:'DataFeatureRemoval:RunAudit:Success'|dict_s, sId: 'ajax_run_audit_success_msg', AddCSSClasses: ['ibo-is-hidden', 'ibo-is-html-content'] } %}{% EndUIAlert %}
|
||||
{% UIAlert ForFailure { sTitle:'error', sId: 'ajax_run_audit_error_msg', AddCSSClasses: ['ibo-is-hidden', 'ibo-is-html-content'] } %}{% EndUIAlert %}
|
||||
|
||||
{% if aAvailableExtensionsCount == 0 %}
|
||||
{% UITitle Neutral { sTitle:'DataFeatureRemoval:NoResult:Title'|dict_s, iLevel:2 } %}{% EndUITitle %}
|
||||
{% else %}
|
||||
{% UIPanel Neutral { sTitle:'DataFeatureRemoval:Result:Title'|dict_s, sSubTitle: '' } %}
|
||||
{% UIMultiColumn Standard {} %}
|
||||
{% for iColumnIndex in 0..iColumnCount-1 %}
|
||||
@@ -25,68 +41,10 @@
|
||||
{% endfor %}
|
||||
{% EndUIMultiColumn %}
|
||||
{% EndUIPanel %}
|
||||
{% else %}
|
||||
{% UIPanel Neutral { sTitle:'DataFeatureRemoval:Result:Title'|dict_s, sSubTitle: '' } %}
|
||||
{% UIMultiColumn Standard {} %}
|
||||
{% for iColumnIndex in 0..iColumnCount-1 %}
|
||||
{% UIColumn Standard {} %}
|
||||
{% for aExtension in aAvailableExtensions[iColumnIndex] %}
|
||||
{% if aExtension['installed'] %}
|
||||
{% UIExtensionDetails Installed { sCode : aExtension['code'], sLabel : aExtension['label'], sDescription : aExtension['description'], aMetaData : [aExtension['version'], aExtension['source']], aExtraFlags : aExtension['extra_flags']} %}{% EndUIExtensionDetails %}
|
||||
{% else %}
|
||||
{% UIExtensionDetails NotInstalled { sCode : aExtension['code'], sLabel : aExtension['label'], sDescription : aExtension['description'], aMetaData : [aExtension['version'], aExtension['source']], aExtraFlags : aExtension['extra_flags']} %}{% EndUIExtensionDetails %}
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% EndUIColumn %}
|
||||
{% endfor %}
|
||||
{% EndUIMultiColumn %}
|
||||
{% EndUIPanel %}
|
||||
|
||||
{% if bDeletionNeeded %}
|
||||
{% UIFieldSet Standard {sLegend:'DataFeatureRemoval:DeletionPlan:Title'|dict_s} %}
|
||||
{% UIDataTable ForForm { sRef:'aDeletionPlanSummary', aColumns:aDeletionPlanSummary.Columns, aData:aDeletionPlanSummary.Data} %}{% EndUIDataTable %}
|
||||
{% EndUIFieldSet %}
|
||||
{% if bDeletionPossible %}
|
||||
{% UIForm Standard {} %}
|
||||
{% UIInput ForHidden { sName:'transaction_id', sValue:sTransactionId} %}
|
||||
{% UIInput ForHidden { sName:'operation', sValue:'DoDeletion'} %}
|
||||
{% for sKey, sClass in aClasses %}
|
||||
{% UIInput ForHidden { sName:"classes[" ~ sKey ~ "]", sValue:sClass } %}
|
||||
{% endfor %}
|
||||
{% for sCode, sLabel in aAddedExtensions %}
|
||||
{% UIInput ForHidden { sName:"aAddedExtensions[" ~ sCode ~ "]", sValue:sLabel } %}
|
||||
{% endfor %}
|
||||
{% for sCode, sLabel in aRemovedExtensions %}
|
||||
{% UIInput ForHidden { sName:"aRemovedExtensions[" ~ sCode ~ "]", sValue:sLabel } %}
|
||||
{% endfor %}
|
||||
{% for sInputName, sValue in aHiddenInputs %}
|
||||
{% UIInput ForHidden { sName:sInputName, sValue:sValue } %}
|
||||
{% endfor %}
|
||||
{% UIToolbar ForButton {} %}
|
||||
{% UIButton ForPrimaryAction {sLabel:'UI:Button:DoDeletion'|dict_s, sName:'btn_deletion', sId:'btn_deletion', bIsSubmit:true} %}
|
||||
{% EndUIToolbar %}
|
||||
{% EndUIForm %}
|
||||
{% else %}
|
||||
{% UIAlert ForFailure { sContent: 'DataFeatureRemoval:DeletionPlan:Error:Issues'|dict_s } %}{% EndUIAlert %}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% UIAlert ForSuccess { sTitle:'DataFeatureRemoval:CleanupComplete:Title'|dict_s, sContent:'DataFeatureRemoval:CompilComplete'|dict_s, sId:value } %}{% EndUIAlert %}
|
||||
|
||||
{% UIForm Standard {'sId':'launch-setup-form', Action:sLaunchSetupUrl, 'EncType': 'application/x-www-form-urlencoded'} %}
|
||||
{% for sKey, sValue in aSetupParams %}
|
||||
{% UIInput ForHidden { sName:sKey, sValue:sValue } %}
|
||||
{% endfor %}
|
||||
{% UIButton ForPrimaryAction {sLabel:'UI:Button:Setup'|dict_s, sName:'btn_setup', sId:'btn_setup', bIsSubmit:true} %}
|
||||
{% EndUIForm %}
|
||||
{% endif %}
|
||||
|
||||
{% if bHasDeletionExecution %}
|
||||
{% UIFieldSet Standard {sLegend:'DataFeatureRemoval:Execution:Title'|dict_s} %}
|
||||
{% UIDataTable ForForm { sRef:'aDeletionExecutionSummary', aColumns:aDeletionExecutionSummary.Columns, aData:aDeletionExecutionSummary.Data} %}{% EndUIDataTable %}
|
||||
{% EndUIFieldSet %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
<div id="ajax_run_audit" class="ibo-block"></div>
|
||||
|
||||
{% UIForm Standard {} %}
|
||||
{% UIInput ForHidden { sName:'transaction_id', sValue:sTransactionId} %}
|
||||
{% UIInput ForHidden { sName:'operation', sValue:'Main'} %}
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
{# @copyright Copyright (C) 2010-2026 Combodo SARL #}
|
||||
{# @license http://opensource.org/licenses/AGPL-3.0 #}
|
||||
|
||||
function ajax_run_audit(sTransactionId) {
|
||||
$('#ajax_run_audit_in_progress_msg').removeClass('ibo-is-hidden');
|
||||
$.post(
|
||||
'{{ sAjaxURL|raw }}',
|
||||
{ operation: 'ajax_run_audit', transaction_id: sTransactionId },
|
||||
function (data) {
|
||||
$('#ajax_run_audit_in_progress_msg').addClass('ibo-is-hidden');
|
||||
|
||||
if (data.error_message) {
|
||||
$('#ajax_run_audit_error_msg .ibo-alert--title').html(data.error_message);
|
||||
$('#ajax_run_audit_error_msg').removeClass('ibo-is-hidden');
|
||||
} else {
|
||||
$('#ajax_run_audit_success_msg').removeClass('ibo-is-hidden');
|
||||
$('#ajax_run_audit').html(data);
|
||||
}
|
||||
}
|
||||
)
|
||||
.fail(function() {
|
||||
$('#ajax_run_audit_in_progress_msg').addClass('ibo-is-hidden');
|
||||
$('#ajax_run_audit_error_msg .ibo-alert--title').html('{{ 'DataFeatureRemoval:RunAudit:Error'|dict_s }}');
|
||||
$('#ajax_run_audit_error_msg').removeClass('ibo-is-hidden');
|
||||
});
|
||||
}
|
||||
|
||||
function ajax_compile() {
|
||||
$('#ajax_compile_in_progress_msg').removeClass('ibo-is-hidden');
|
||||
|
||||
$.post(
|
||||
'{{ sAjaxURL|raw }}',
|
||||
{ operation: 'ajax_compile', transaction_id: '{{ sTransactionId }}' },
|
||||
function (data) {
|
||||
$('#ajax_compile_in_progress_msg').addClass('ibo-is-hidden');
|
||||
|
||||
if (data.error_message) {
|
||||
$('#ajax_compile_error_msg .ibo-alert--title').html(data.error_message);
|
||||
$('#ajax_compile_error_msg').removeClass('ibo-is-hidden');
|
||||
} else {
|
||||
$('#ajax_compile_success_msg .ibo-alert--title').html(data.success_message);
|
||||
$('#ajax_compile_success_msg').removeClass('ibo-is-hidden');
|
||||
|
||||
ajax_run_audit(data.transaction_id);
|
||||
}
|
||||
},
|
||||
'json'
|
||||
)
|
||||
.fail(function() {
|
||||
$('#ajax_compile_in_progress_msg').addClass('ibo-is-hidden');
|
||||
$('#ajax_compile_error_msg .ibo-alert--title').html('{{ 'DataFeatureRemoval:Compile:Error'|dict_s }}');
|
||||
$('#ajax_compile_error_msg').removeClass('ibo-is-hidden');
|
||||
});
|
||||
}
|
||||
|
||||
ajax_compile();
|
||||
@@ -5,7 +5,6 @@
|
||||
{% UIForm Standard {} %}
|
||||
{% UIInput ForHidden {sName:'operation', sValue:'AnalysisResult'} %}
|
||||
{% UIInput ForHidden {sName:'transaction_id', sValue:sTransactionId} %}
|
||||
{% UIInput ForHidden {sName:'return_application', sValue:'itop'} %}
|
||||
|
||||
{% UIPanel Neutral { sTitle:'DataFeatureRemoval:Features:Title'|dict_s, sSubTitle: '' } %}
|
||||
{% UIMultiColumn Standard {} %}
|
||||
|
||||
@@ -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',
|
||||
);
|
||||
|
||||
@@ -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',
|
||||
);
|
||||
|
||||
@@ -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',
|
||||
]);
|
||||
|
||||
@@ -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ě',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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日間のカテゴリ別の変更',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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í',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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' => '分配给我的变更',
|
||||
|
||||
@@ -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ě',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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日間のカテゴリ別の変更',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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í',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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' => '分配给我的变更',
|
||||
|
||||
@@ -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>
|
||||
@@ -16,7 +16,7 @@
|
||||
<end_of_warranty></end_of_warranty>
|
||||
<rack_id>0</rack_id>
|
||||
<enclosure_id>0</enclosure_id>
|
||||
<nb_u></nb_u>
|
||||
<nb_u>2</nb_u>
|
||||
<managementip></managementip>
|
||||
<powerA_id>0</powerA_id>
|
||||
<powerB_id>0</powerB_id>
|
||||
@@ -40,9 +40,9 @@
|
||||
<asset_number></asset_number>
|
||||
<purchase_date></purchase_date>
|
||||
<end_of_warranty></end_of_warranty>
|
||||
<rack_id>0</rack_id>
|
||||
<rack_id></rack_id>
|
||||
<enclosure_id>0</enclosure_id>
|
||||
<nb_u></nb_u>
|
||||
<nb_u>1</nb_u>
|
||||
<managementip></managementip>
|
||||
<powerA_id>0</powerA_id>
|
||||
<powerB_id>0</powerB_id>
|
||||
@@ -59,16 +59,16 @@
|
||||
<business_criticity>low</business_criticity>
|
||||
<move2production></move2production>
|
||||
<serialnumber></serialnumber>
|
||||
<location_id>0</location_id>
|
||||
<location_id>2</location_id>
|
||||
<status>production</status>
|
||||
<brand_id>1</brand_id>
|
||||
<model_id>4</model_id>
|
||||
<asset_number></asset_number>
|
||||
<purchase_date></purchase_date>
|
||||
<end_of_warranty></end_of_warranty>
|
||||
<rack_id>0</rack_id>
|
||||
<rack_id></rack_id>
|
||||
<enclosure_id>0</enclosure_id>
|
||||
<nb_u></nb_u>
|
||||
<nb_u>2</nb_u>
|
||||
<managementip></managementip>
|
||||
<powerA_id>0</powerA_id>
|
||||
<powerB_id>0</powerB_id>
|
||||
@@ -85,16 +85,16 @@
|
||||
<business_criticity>low</business_criticity>
|
||||
<move2production></move2production>
|
||||
<serialnumber>US3215687014</serialnumber>
|
||||
<location_id>0</location_id>
|
||||
<location_id>2</location_id>
|
||||
<status>production</status>
|
||||
<brand_id>1</brand_id>
|
||||
<model_id>4</model_id>
|
||||
<asset_number></asset_number>
|
||||
<purchase_date>2021-07-30</purchase_date>
|
||||
<end_of_warranty>2025-07-29</end_of_warranty>
|
||||
<rack_id>0</rack_id>
|
||||
<rack_id></rack_id>
|
||||
<enclosure_id>0</enclosure_id>
|
||||
<nb_u></nb_u>
|
||||
<nb_u>2</nb_u>
|
||||
<managementip>10.10.24.2</managementip>
|
||||
<powerA_id>0</powerA_id>
|
||||
<powerB_id>0</powerB_id>
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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/');
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Set>
|
||||
<Rack alias="Rack" id="1">
|
||||
<Rack alias="Rack" id="15">
|
||||
<name>Rack1</name>
|
||||
<description></description>
|
||||
<org_id>2</org_id>
|
||||
@@ -14,6 +14,6 @@
|
||||
<asset_number></asset_number>
|
||||
<purchase_date></purchase_date>
|
||||
<end_of_warranty></end_of_warranty>
|
||||
<nb_u></nb_u>
|
||||
<nb_u>12</nb_u>
|
||||
</Rack>
|
||||
</Set>
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Set>
|
||||
<TagSetFieldDataFor_FAQ__domains id="1">
|
||||
<code>software</code>
|
||||
<label>Software 💾</label>
|
||||
</TagSetFieldDataFor_FAQ__domains>
|
||||
<TagSetFieldDataFor_FAQ__domains id="2">
|
||||
<code>hardware</code>
|
||||
<label>Hardware 💻</label>
|
||||
</TagSetFieldDataFor_FAQ__domains>
|
||||
<TagSetFieldDataFor_FAQ__domains id="3">
|
||||
<code>server</code>
|
||||
<label>Server 🏢</label>
|
||||
</TagSetFieldDataFor_FAQ__domains>
|
||||
<TagSetFieldDataFor_FAQ__domains id="4">
|
||||
<code>mobile</code>
|
||||
<label>Mobile 📱</label>
|
||||
</TagSetFieldDataFor_FAQ__domains>
|
||||
<TagSetFieldDataFor_FAQ__domains id="5">
|
||||
<code>network</code>
|
||||
<label>Network ☁️</label>
|
||||
</TagSetFieldDataFor_FAQ__domains>
|
||||
</Set>
|
||||
82
datamodels/2.x/itop-faq-light/data/data.sample.faq.de_de.xml
Normal file
82
datamodels/2.x/itop-faq-light/data/data.sample.faq.de_de.xml
Normal file
@@ -0,0 +1,82 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Set>
|
||||
<FAQ alias="FAQ" id="6">
|
||||
<title>💻 Anfrage für IT-Ausrüstung</title>
|
||||
<summary>So beantragen Sie IT-Ausrüstung</summary>
|
||||
<description><h4><strong>📌 Zweck</strong></h4><p>Dieser Ablauf beschreibt die Schritte zur Beantragung von IT-Ausrüstung wie Laptops, Monitore, Peripheriegeräte oder Softwarelizenzen. Alle Anfragen müssen über die freigegebenen Kanäle eingereicht werden, damit Nachverfolgung, Genehmigung und Bereitstellung sichergestellt sind.</p><hr><h4><strong>👥 Geltungsbereich</strong></h4><p>Gilt für alle Mitarbeitenden, externen Kräfte und Abteilungen, die IT-Ausrüstung für ihre Arbeit benötigen.</p><hr><h4><strong>✅ Schritt 1: Bedarf klären</strong></h4><ul><li>Prüfen Sie, ob die Ausrüstung für Rolle oder Projekt erforderlich ist.</li><li>Prüfen Sie die Verfügbarkeit im IT-Bestand.</li><li>Stellen Sie sicher, dass die Anfrage den IT-Richtlinien entspricht.</li></ul><hr><h4><strong>📝 Schritt 2: Anfrage einreichen</strong></h4><ol><li>Öffnen Sie das IT-Anfrageportal und füllen Sie das Formular vollständig aus.</li><li>Geben Sie Name, Abteilung, Gerätetyp, Menge, Begründung und gewünschtes Lieferdatum an.</li><li>Alternativ senden Sie eine E-Mail an it-requests@[yourorganization].com.</li></ol><hr><h4><strong>🔍 Schritt 3: Genehmigung</strong></h4><p>Die Führungskraft prüft geschäftlichen Bedarf und Budget. Danach validiert das IT-Team Kompatibilität, Verfügbarkeit und Sicherheitsvorgaben. Bei hohen Kosten kann zusätzlich eine Finanzfreigabe erforderlich sein.</p><hr><h4><strong>📦 Schritt 4: Bereitstellung</strong></h4><p>Lagerware wird nach Freigabe zeitnah ausgeliefert. Bei Sonderbestellungen informiert die IT über die Lieferzeit und übernimmt bei Bedarf die Ersteinrichtung.</p><hr><h4><strong>🔄 Rückgabe und Ersatz</strong></h4><p>Defekte oder nicht mehr benötigte Geräte werden über eine Rückgabeanfrage an die IT gemeldet und zurückgeführt.</p></description>
|
||||
<category_id>7</category_id>
|
||||
<error_code></error_code>
|
||||
<key_words>PC, Phone, Laptop, Desktop</key_words>
|
||||
<domains><Set>
|
||||
<Tag>hardware</Tag><Tag>process</Tag></Set>
|
||||
</domains>
|
||||
</FAQ>
|
||||
<FAQ alias="FAQ" id="8">
|
||||
<title>📌 Urlaubsverwaltung</title>
|
||||
<summary></summary>
|
||||
<description><h4><strong>❓ Wie beantrage ich Urlaub?</strong></h4><p>Sie können Urlaub über das interne HR-Portal oder per E-Mail an Ihre Führungskraft und HR beantragen. Geben Sie Name, Zeitraum und Urlaubsart an.</p><hr><h4><strong>⏳ Welche Fristen gelten?</strong></h4><ul><li>Regulärer Urlaub möglichst frühzeitig, idealerweise mindestens 15 Tage vorher.</li><li>Sonderurlaub so schnell wie möglich ankündigen.</li><li>Krankheit oder Unfall am selben Tag melden.</li></ul><hr><h4><strong>📅 Wie viele Urlaubstage habe ich?</strong></h4><p>Der Anspruch richtet sich nach Vertrag und lokaler Gesetzgebung. Ihr aktueller Saldo ist im HR-Portal sichtbar.</p><hr><h4><strong>🔄 Kann ich Urlaub ändern oder stornieren?</strong></h4><p>Ja, je nach Unternehmensrichtlinie und mit Zustimmung der Führungskraft. Änderungen sollten frühzeitig gemeldet werden.</p><hr><h4><strong>🆘 An wen wende ich mich bei Problemen?</strong></h4><p>Bei technischen Problemen kontaktieren Sie den IT-Support, bei Fragen zu Rechten und Saldo das HR-Team.</p></description>
|
||||
<category_id>4</category_id>
|
||||
<error_code></error_code>
|
||||
<key_words>Leave</key_words>
|
||||
<domains><Set>
|
||||
<Tag>process</Tag></Set>
|
||||
</domains>
|
||||
</FAQ>
|
||||
<FAQ alias="FAQ" id="1">
|
||||
<title>🖨️ Fehlerdiagnose bei Druckern</title>
|
||||
<summary>Fragenkatalog zur Analyse von Druckproblemen</summary>
|
||||
<description><h2>❓ Fragen zur Fehlersuche</h2><p><strong>Druckermarke bekannt?</strong> HP, IBM, Epson oder andere.</p><hr><p><strong>Ist der Drucker mit Strom versorgt?</strong> Ja oder Nein.</p><hr><p><strong>Ist der Drucker eingeschaltet?</strong> Ja oder Nein.</p><hr><p><strong>Ist Papier eingelegt?</strong> Ja oder Nein.</p><hr><p><strong>Gibt es Meldungen zum Tintenstand oder andere Warnungen?</strong> Falls ja, welche?</p><hr><p><strong>Wurde bereits ein Neustart versucht?</strong> Ja oder Nein.</p></description>
|
||||
<category_id>3</category_id>
|
||||
<error_code></error_code>
|
||||
<key_words>printer</key_words>
|
||||
<domains><Set>
|
||||
<Tag>printer</Tag><Tag>process</Tag></Set>
|
||||
</domains>
|
||||
</FAQ>
|
||||
<FAQ alias="FAQ" id="4">
|
||||
<title>📶 Fehlerdiagnose für WLAN-Verbindung</title>
|
||||
<summary>Fragenkatalog zur Analyse von WLAN-Problemen</summary>
|
||||
<description><h2>🔍 Grundprüfungen</h2><p>Ist WLAN am Gerät aktiviert, ist das Symbol sichtbar und funktionieren andere Geräte im selben Netzwerk?</p><hr><h2>🌐 Netzwerkspezifische Prüfungen</h2><p>Ist der Router eingeschaltet, sind die LEDs normal, ist die SSID sichtbar und wurde das richtige Passwort verwendet?</p><hr><h2>💻 Gerätespezifische Prüfungen</h2><p>Wurde das Gerät neu gestartet, das WLAN neu verbunden und die Entfernung zum Router geprüft?</p><hr><h2>🛠️ Erweiterte Schritte</h2><p>Treiber aktualisieren, Störquellen prüfen, Routerkanal anpassen und bei Bedarf Router zurücksetzen.</p></description>
|
||||
<category_id>6</category_id>
|
||||
<error_code></error_code>
|
||||
<key_words></key_words>
|
||||
<domains><Set>
|
||||
<Tag>network</Tag></Set>
|
||||
</domains>
|
||||
</FAQ>
|
||||
<FAQ alias="FAQ" id="2">
|
||||
<title>🖥️ Fehlerdiagnose für Windows-Verbindung</title>
|
||||
<summary>Fragenkatalog zur Analyse von Windows-Verbindungsproblemen</summary>
|
||||
<description><h2>🔍 Allgemeine Prüfungen</h2><p>Besteht eine Internetverbindung, ist das WLAN- oder Ethernet-Symbol sichtbar und funktionieren andere Geräte im selben Netzwerk?</p><hr><h2>🌐 Netzwerkspezifische Prüfungen</h2><p>Prüfen Sie Flugmodus, Router-Neustart, korrektes Passwort und ggf. den Einfluss eines VPN.</p><hr><h2>🔗 Windows-spezifische Prüfungen</h2><p>Computer neu starten, Windows-Updates prüfen, Netzwerktreiber aktualisieren und die integrierte Problembehandlung ausführen.</p><hr><h2>🛠️ Erweiterte Schritte</h2><p>Netzwerk zurücksetzen, Sicherheitssoftware prüfen und testweise ein anderes Netzwerk verwenden.</p></description>
|
||||
<category_id>5</category_id>
|
||||
<error_code></error_code>
|
||||
<key_words>windows connection</key_words>
|
||||
<domains><Set>
|
||||
<Tag>software</Tag></Set>
|
||||
</domains>
|
||||
</FAQ>
|
||||
<FAQ alias="FAQ" id="7">
|
||||
<title>🖨️🔄 Drucker-Firmware aktualisieren</title>
|
||||
<summary></summary>
|
||||
<description><h2>📌 Vorbereitung</h2><p>Benötigt werden ein Computer im selben Netzwerk, die passende Firmware-Datei und eine stabile Verbindung. Der Drucker darf während des Updates nicht ausgeschaltet werden.</p><hr><h2>🔍 Modell und Version ermitteln</h2><p>Prüfen Sie das exakte Modell und notieren Sie die aktuell installierte Firmware-Version.</p><hr><h2>📥 Firmware herunterladen</h2><p>Laden Sie die aktuelle Version von der offiziellen Herstellerseite und prüfen Sie die Kompatibilität für Modell und Region.</p><hr><h2>🔄 Update durchführen</h2><p>Das Update kann über Hersteller-Software, Druckermenü oder per USB erfolgen. Folgen Sie den Schritten des Herstellers und unterbrechen Sie den Vorgang nicht.</p><hr><h2>✅ Nachkontrolle</h2><p>Drucker neu starten, Testseite drucken und Funktionen wie Drucken, Scannen und Netzwerk prüfen.</p><hr><h2>🚨 Fehlerbehebung</h2><p>Bei Fehlern Verbindung prüfen, neu starten und bei Bedarf den Herstellersupport kontaktieren.</p></description>
|
||||
<category_id>3</category_id>
|
||||
<category_id_friendlyname>Printer</category_id_friendlyname>
|
||||
<category_name>Printer</category_name>
|
||||
<error_code></error_code>
|
||||
<key_words>printer, firmware</key_words>
|
||||
<domains><Set>
|
||||
<Tag>printer</Tag></Set>
|
||||
</domains>
|
||||
</FAQ>
|
||||
<FAQ alias="FAQ" id="5">
|
||||
<title>💙💻 Fehlerdiagnose bei Windows-Bluescreen</title>
|
||||
<summary>Fragenkatalog zur Analyse von Windows-Bluescreen-Problemen</summary>
|
||||
<description><h2>🔍 Erste Prüfungen</h2><p>Tritt der Bluescreen wiederholt auf, bei einem bestimmten Schritt oder zufällig? Notieren Sie den angezeigten Fehlercode.</p><hr><h2>🛠️ Basismaßnahmen</h2><p>Neustart durchführen, Windows aktualisieren, externe Geräte trennen und einen Malware-Scan starten.</p><hr><h2>🖥️ Erweiterte Prüfungen</h2><p>Ereignisanzeige prüfen, Treiber aktualisieren sowie Systemprüfungen wie SFC, DISM, RAM- und Datenträgertests ausführen.</p><hr><h2>🔄 Wiederherstellungsoptionen</h2><p>Abgesicherten Modus testen, Systemwiederherstellung verwenden und falls nötig Windows zurücksetzen oder neu installieren.</p></description>
|
||||
<category_id>5</category_id>
|
||||
<error_code></error_code>
|
||||
<key_words>Blue Screen, Windows</key_words>
|
||||
<domains><Set>
|
||||
</Set>
|
||||
</domains>
|
||||
</FAQ>
|
||||
</Set>
|
||||
82
datamodels/2.x/itop-faq-light/data/data.sample.faq.en_us.xml
Normal file
82
datamodels/2.x/itop-faq-light/data/data.sample.faq.en_us.xml
Normal file
File diff suppressed because one or more lines are too long
82
datamodels/2.x/itop-faq-light/data/data.sample.faq.fr_fr.xml
Normal file
82
datamodels/2.x/itop-faq-light/data/data.sample.faq.fr_fr.xml
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1,25 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Set>
|
||||
<FAQCategory alias="FAQCategory" id="1">
|
||||
<name>Konfiguration</name>
|
||||
</FAQCategory>
|
||||
<FAQCategory alias="FAQCategory" id="2">
|
||||
<name>Datenbank</name>
|
||||
</FAQCategory>
|
||||
<FAQCategory alias="FAQCategory" id="4">
|
||||
<name>Personalwesen</name>
|
||||
</FAQCategory>
|
||||
<FAQCategory alias="FAQCategory" id="6">
|
||||
<name>Netzwerk</name>
|
||||
</FAQCategory>
|
||||
<FAQCategory alias="FAQCategory" id="7">
|
||||
<name>PC</name>
|
||||
</FAQCategory>
|
||||
<FAQCategory alias="FAQCategory" id="3">
|
||||
<name>Drucker</name>
|
||||
</FAQCategory>
|
||||
<FAQCategory alias="FAQCategory" id="5">
|
||||
<name>Windows</name>
|
||||
</FAQCategory>
|
||||
</Set>
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Set>
|
||||
<FAQCategory alias="FAQCategory" id="1">
|
||||
<name>Configuration</name>
|
||||
</FAQCategory>
|
||||
<FAQCategory alias="FAQCategory" id="2">
|
||||
<name>Database</name>
|
||||
</FAQCategory>
|
||||
<FAQCategory alias="FAQCategory" id="4">
|
||||
<name>Human resources</name>
|
||||
</FAQCategory>
|
||||
<FAQCategory alias="FAQCategory" id="6">
|
||||
<name>Network</name>
|
||||
</FAQCategory>
|
||||
<FAQCategory alias="FAQCategory" id="7">
|
||||
<name>PC</name>
|
||||
</FAQCategory>
|
||||
<FAQCategory alias="FAQCategory" id="3">
|
||||
<name>Printer</name>
|
||||
</FAQCategory>
|
||||
<FAQCategory alias="FAQCategory" id="5">
|
||||
<name>Windows</name>
|
||||
</FAQCategory>
|
||||
</Set>
|
||||
@@ -0,0 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Set>
|
||||
<FAQCategory alias="FAQCategory" id="1">
|
||||
<name>Configuration</name>
|
||||
</FAQCategory>
|
||||
<FAQCategory alias="FAQCategory" id="2">
|
||||
<name>Base de données</name>
|
||||
</FAQCategory>
|
||||
<FAQCategory alias="FAQCategory" id="4">
|
||||
<name>Ressources humaines</name>
|
||||
</FAQCategory>
|
||||
<FAQCategory alias="FAQCategory" id="6">
|
||||
<name>Réseau</name>
|
||||
</FAQCategory>
|
||||
<FAQCategory alias="FAQCategory" id="7">
|
||||
<name>PC</name>
|
||||
</FAQCategory>
|
||||
<FAQCategory alias="FAQCategory" id="3">
|
||||
<name>Imprimante</name>
|
||||
</FAQCategory>
|
||||
<FAQCategory alias="FAQCategory" id="5">
|
||||
<name>Windows</name>
|
||||
</FAQCategory>
|
||||
</Set>
|
||||
@@ -0,0 +1,39 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Set>
|
||||
<TagSetFieldDataFor_FAQ__domains alias="TagSetFieldDataFor_FAQ__domains" id="2">
|
||||
<code>hardware</code>
|
||||
<label>Hardware 💻</label>
|
||||
<description></description>
|
||||
</TagSetFieldDataFor_FAQ__domains>
|
||||
<TagSetFieldDataFor_FAQ__domains alias="TagSetFieldDataFor_FAQ__domains" id="4">
|
||||
<code>mobile</code>
|
||||
<label>Mobil 📱</label>
|
||||
<description></description>
|
||||
</TagSetFieldDataFor_FAQ__domains>
|
||||
<TagSetFieldDataFor_FAQ__domains alias="TagSetFieldDataFor_FAQ__domains" id="5">
|
||||
<code>network</code>
|
||||
<label>Netzwerk ☁️</label>
|
||||
<description></description>
|
||||
</TagSetFieldDataFor_FAQ__domains>
|
||||
<TagSetFieldDataFor_FAQ__domains alias="TagSetFieldDataFor_FAQ__domains" id="6">
|
||||
<code>printer</code>
|
||||
<label>Drucker 🖨️</label>
|
||||
<description></description>
|
||||
</TagSetFieldDataFor_FAQ__domains>
|
||||
<TagSetFieldDataFor_FAQ__domains alias="TagSetFieldDataFor_FAQ__domains" id="7">
|
||||
<code>process</code>
|
||||
<label>Prozess ⚙️</label>
|
||||
<description></description>
|
||||
</TagSetFieldDataFor_FAQ__domains>
|
||||
<TagSetFieldDataFor_FAQ__domains alias="TagSetFieldDataFor_FAQ__domains" id="3">
|
||||
<code>server</code>
|
||||
<label>Server 🏢</label>
|
||||
<description></description>
|
||||
</TagSetFieldDataFor_FAQ__domains>
|
||||
<TagSetFieldDataFor_FAQ__domains alias="TagSetFieldDataFor_FAQ__domains" id="1">
|
||||
<code>software</code>
|
||||
<label>Software 💾</label>
|
||||
<description></description>
|
||||
</TagSetFieldDataFor_FAQ__domains>
|
||||
</Set>
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Set>
|
||||
<TagSetFieldDataFor_FAQ__domains alias="TagSetFieldDataFor_FAQ__domains" id="2">
|
||||
<code>hardware</code>
|
||||
<label>Hardware 💻</label>
|
||||
<description></description>
|
||||
</TagSetFieldDataFor_FAQ__domains>
|
||||
<TagSetFieldDataFor_FAQ__domains alias="TagSetFieldDataFor_FAQ__domains" id="4">
|
||||
<code>mobile</code>
|
||||
<label>Mobile 📱</label>
|
||||
<description></description>
|
||||
</TagSetFieldDataFor_FAQ__domains>
|
||||
<TagSetFieldDataFor_FAQ__domains alias="TagSetFieldDataFor_FAQ__domains" id="5">
|
||||
<code>network</code>
|
||||
<label>Network ☁️</label>
|
||||
<description></description>
|
||||
</TagSetFieldDataFor_FAQ__domains>
|
||||
<TagSetFieldDataFor_FAQ__domains alias="TagSetFieldDataFor_FAQ__domains" id="6">
|
||||
<code>printer</code>
|
||||
<label>Printer 🖨️</label>
|
||||
<description></description>
|
||||
</TagSetFieldDataFor_FAQ__domains>
|
||||
<TagSetFieldDataFor_FAQ__domains alias="TagSetFieldDataFor_FAQ__domains" id="7">
|
||||
<code>process</code>
|
||||
<label>Process ⚙️</label>
|
||||
<description></description>
|
||||
</TagSetFieldDataFor_FAQ__domains>
|
||||
<TagSetFieldDataFor_FAQ__domains alias="TagSetFieldDataFor_FAQ__domains" id="3">
|
||||
<code>server</code>
|
||||
<label>Server 🏢</label>
|
||||
<description></description>
|
||||
</TagSetFieldDataFor_FAQ__domains>
|
||||
<TagSetFieldDataFor_FAQ__domains alias="TagSetFieldDataFor_FAQ__domains" id="1">
|
||||
<code>software</code>
|
||||
<label>Software 💾</label>
|
||||
<description></description>
|
||||
</TagSetFieldDataFor_FAQ__domains>
|
||||
</Set>
|
||||
@@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Set>
|
||||
<TagSetFieldDataFor_FAQ__domains alias="TagSetFieldDataFor_FAQ__domains" id="2">
|
||||
<code>hardware</code>
|
||||
<label>Matériel 💻</label>
|
||||
<description></description>
|
||||
</TagSetFieldDataFor_FAQ__domains>
|
||||
<TagSetFieldDataFor_FAQ__domains alias="TagSetFieldDataFor_FAQ__domains" id="4">
|
||||
<code>mobile</code>
|
||||
<label>Mobile 📱</label>
|
||||
<description></description>
|
||||
</TagSetFieldDataFor_FAQ__domains>
|
||||
<TagSetFieldDataFor_FAQ__domains alias="TagSetFieldDataFor_FAQ__domains" id="5">
|
||||
<code>network</code>
|
||||
<label>Réseau ☁️</label>
|
||||
<description></description>
|
||||
</TagSetFieldDataFor_FAQ__domains>
|
||||
<TagSetFieldDataFor_FAQ__domains alias="TagSetFieldDataFor_FAQ__domains" id="6">
|
||||
<code>printer</code>
|
||||
<label>Imprimante 🖨️</label>
|
||||
<description></description>
|
||||
</TagSetFieldDataFor_FAQ__domains>
|
||||
<TagSetFieldDataFor_FAQ__domains alias="TagSetFieldDataFor_FAQ__domains" id="7">
|
||||
<code>process</code>
|
||||
<label>Processus ⚙️</label>
|
||||
<description></description>
|
||||
</TagSetFieldDataFor_FAQ__domains>
|
||||
<TagSetFieldDataFor_FAQ__domains alias="TagSetFieldDataFor_FAQ__domains" id="3">
|
||||
<code>server</code>
|
||||
<label>Serveur 🏢</label>
|
||||
<description></description>
|
||||
</TagSetFieldDataFor_FAQ__domains>
|
||||
<TagSetFieldDataFor_FAQ__domains alias="TagSetFieldDataFor_FAQ__domains" id="1">
|
||||
<code>software</code>
|
||||
<label>Logiciel 💾</label>
|
||||
<description></description>
|
||||
</TagSetFieldDataFor_FAQ__domains>
|
||||
</Set>
|
||||
@@ -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',
|
||||
|
||||
@@ -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~~',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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>',
|
||||
|
||||
@@ -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>',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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',
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user