mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-16 08:54:12 +01:00
Compare commits
171 Commits
support/2.
...
support/1.
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62510e2b04 | ||
|
|
f33c821306 | ||
|
|
11d0e9f52b | ||
|
|
3330fd79d0 | ||
|
|
02e0a61dcf | ||
|
|
2bb8028d4d | ||
|
|
891b22909a | ||
|
|
463748b6da | ||
|
|
fc2878b6d1 | ||
|
|
17919f5389 | ||
|
|
e54b1d2ff4 | ||
|
|
523fb8bd25 | ||
|
|
fad77fb9fa | ||
|
|
8da92c9251 | ||
|
|
977d616ef2 | ||
|
|
29faa739c1 | ||
|
|
b986f63a67 | ||
|
|
8fa3a6d47d | ||
|
|
0e6876b068 | ||
|
|
8d962f4bdb | ||
|
|
3b8f945c44 | ||
|
|
9600c89a1f | ||
|
|
d01202ba33 | ||
|
|
1bc1a0a1b2 | ||
|
|
37ea4cb5e3 | ||
|
|
c4a003f620 | ||
|
|
7a8ee0353a | ||
|
|
6b526ba455 | ||
|
|
9d9b923b7e | ||
|
|
fcaad0cd07 | ||
|
|
da875dd945 | ||
|
|
2a71bf5008 | ||
|
|
9b36ebc106 | ||
|
|
1a507b7aa4 | ||
|
|
178ee28596 | ||
|
|
e44a5d2980 | ||
|
|
828c02db0b | ||
|
|
d1e4e2109f | ||
|
|
b7a9b340b8 | ||
|
|
3731cf6dc1 | ||
|
|
0e7fc5e5c4 | ||
|
|
bc62c06894 | ||
|
|
4ed85c23de | ||
|
|
b6c1347f27 | ||
|
|
237eefcbc6 | ||
|
|
5ee3c69898 | ||
|
|
53b3ae8016 | ||
|
|
26b6bfaf7f | ||
|
|
1a659cc4d0 | ||
|
|
b000900d6c | ||
|
|
f68ec1cef1 | ||
|
|
3fb867d393 | ||
|
|
fe559eb492 | ||
|
|
0041afd6d0 | ||
|
|
dc1b5b0d4c | ||
|
|
10a930b7b2 | ||
|
|
72b6089db8 | ||
|
|
0cfb1c3a83 | ||
|
|
36a73535a5 | ||
|
|
9382b89277 | ||
|
|
6d14da15cf | ||
|
|
3113205f88 | ||
|
|
09bd8052d7 | ||
|
|
85f0b79203 | ||
|
|
81145d7b1c | ||
|
|
7e6d1c2ce4 | ||
|
|
364259daa5 | ||
|
|
7b270294f6 | ||
|
|
c7aa00e81a | ||
|
|
f9e7446e7b | ||
|
|
493ab80965 | ||
|
|
e623467782 | ||
|
|
32208fcbfc | ||
|
|
dcbff406f7 | ||
|
|
017dfe641c | ||
|
|
fad258cd2d | ||
|
|
3470ce18e8 | ||
|
|
af710c549f | ||
|
|
ee938d674d | ||
|
|
423de35cf5 | ||
|
|
6a7af8ad73 | ||
|
|
89732d6e52 | ||
|
|
cddeab2c90 | ||
|
|
d9d84703ae | ||
|
|
c3de9ecf10 | ||
|
|
cf37a50b3d | ||
|
|
4db30648c2 | ||
|
|
8de84d5ec7 | ||
|
|
459a271d11 | ||
|
|
9da00b83b2 | ||
|
|
0c8ef6a690 | ||
|
|
cdefd7a4c6 | ||
|
|
4f057ac29f | ||
|
|
ab16588f87 | ||
|
|
07d8da9d99 | ||
|
|
c539f19ce9 | ||
|
|
3635e60850 | ||
|
|
b278b84f46 | ||
|
|
04647970a8 | ||
|
|
fe58f6bd19 | ||
|
|
0d6cd529a1 | ||
|
|
2a155fe8ee | ||
|
|
3f381a3530 | ||
|
|
7fadb5e08b | ||
|
|
5d4476f48b | ||
|
|
2fbb37cc2f | ||
|
|
6801ecb266 | ||
|
|
fa821d3a9b | ||
|
|
00f9deeaa5 | ||
|
|
58cfc1d51b | ||
|
|
af8b3b972d | ||
|
|
07671f40fd | ||
|
|
3da5c65fe4 | ||
|
|
489be44b90 | ||
|
|
912088d017 | ||
|
|
06620133b6 | ||
|
|
95d7a24630 | ||
|
|
cb0e1d8ef3 | ||
|
|
d321ebc8e4 | ||
|
|
c149ec8e2c | ||
|
|
281adfb043 | ||
|
|
4244029087 | ||
|
|
78e173d5fb | ||
|
|
6b8abce03a | ||
|
|
33a7005069 | ||
|
|
006a6037d1 | ||
|
|
e2f8be1745 | ||
|
|
ebae45f6a5 | ||
|
|
0685835d49 | ||
|
|
1b1e88f9a4 | ||
|
|
b90f443e75 | ||
|
|
4da64a64b1 | ||
|
|
6673e171dc | ||
|
|
afee7297cc | ||
|
|
3cc8b5b88a | ||
|
|
b2e6981b24 | ||
|
|
c0a79fa573 | ||
|
|
02ad6d19fe | ||
|
|
d16308ab62 | ||
|
|
4598959bc2 | ||
|
|
65a3755f81 | ||
|
|
dc46c65499 | ||
|
|
9d691c8e56 | ||
|
|
99f897bff7 | ||
|
|
8d83447222 | ||
|
|
dcc8ad08a4 | ||
|
|
c1b0b73b51 | ||
|
|
81173decca | ||
|
|
9aca062bf5 | ||
|
|
09aba95d0a | ||
|
|
1683ca2dd6 | ||
|
|
9e732d6045 | ||
|
|
69df343bd2 | ||
|
|
eb8f49ebfe | ||
|
|
398e294604 | ||
|
|
d04c6bccd5 | ||
|
|
f00c7c6bc2 | ||
|
|
d30e8c359f | ||
|
|
2bd4a61c00 | ||
|
|
e35c8323df | ||
|
|
e4e814281d | ||
|
|
635cb424a2 | ||
|
|
e95aa6cc69 | ||
|
|
c58fd17fc9 | ||
|
|
efdec7a343 | ||
|
|
2352c05d36 | ||
|
|
23634964a5 | ||
|
|
619252db99 | ||
|
|
ca4dbd833c | ||
|
|
f62a3b22a3 | ||
|
|
88416bca5d |
@@ -47,6 +47,28 @@ class UserRightsBaseClassGUI extends cmdbAbstractObject
|
||||
}
|
||||
}
|
||||
|
||||
class UserRightsBaseClass extends DBObject
|
||||
{
|
||||
// Whenever something changes, reload the privileges
|
||||
|
||||
protected function AfterInsert()
|
||||
{
|
||||
UserRights::FlushPrivileges();
|
||||
}
|
||||
|
||||
protected function AfterUpdate()
|
||||
{
|
||||
UserRights::FlushPrivileges();
|
||||
}
|
||||
|
||||
protected function AfterDelete()
|
||||
{
|
||||
UserRights::FlushPrivileges();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
class URP_Profiles extends UserRightsBaseClassGUI
|
||||
{
|
||||
@@ -79,9 +101,27 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
|
||||
protected $m_bCheckReservedNames = true;
|
||||
protected function DisableCheckOnReservedNames()
|
||||
{
|
||||
$this->m_bCheckReservedNames = false;
|
||||
}
|
||||
|
||||
|
||||
protected static $m_aActions = array(
|
||||
UR_ACTION_READ => 'Read',
|
||||
UR_ACTION_MODIFY => 'Modify',
|
||||
UR_ACTION_DELETE => 'Delete',
|
||||
UR_ACTION_BULK_READ => 'Bulk Read',
|
||||
UR_ACTION_BULK_MODIFY => 'Bulk Modify',
|
||||
UR_ACTION_BULK_DELETE => 'Bulk Delete',
|
||||
);
|
||||
|
||||
protected static $m_aCacheActionGrants = null;
|
||||
protected static $m_aCacheStimulusGrants = null;
|
||||
protected static $m_aCacheProfiles = null;
|
||||
|
||||
public static function DoCreateProfile($sName, $sDescription)
|
||||
public static function DoCreateProfile($sName, $sDescription, $bReservedName = false)
|
||||
{
|
||||
if (is_null(self::$m_aCacheProfiles))
|
||||
{
|
||||
@@ -102,19 +142,118 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
$oNewObj = MetaModel::NewObject("URP_Profiles");
|
||||
$oNewObj->Set('name', $sName);
|
||||
$oNewObj->Set('description', $sDescription);
|
||||
if ($bReservedName)
|
||||
{
|
||||
$oNewObj->DisableCheckOnReservedNames();
|
||||
}
|
||||
$iId = $oNewObj->DBInsertNoReload();
|
||||
self::$m_aCacheProfiles[$sCacheKey] = $iId;
|
||||
return $iId;
|
||||
}
|
||||
|
||||
public static function DoCreateActionGrant($iProfile, $iAction, $sClass, $bPermission = true)
|
||||
{
|
||||
$sAction = self::$m_aActions[$iAction];
|
||||
|
||||
if (is_null(self::$m_aCacheActionGrants))
|
||||
{
|
||||
self::$m_aCacheActionGrants = array();
|
||||
$oFilterAll = new DBObjectSearch('URP_ActionGrant');
|
||||
$oSet = new DBObjectSet($oFilterAll);
|
||||
while ($oGrant = $oSet->Fetch())
|
||||
{
|
||||
self::$m_aCacheActionGrants[$oGrant->Get('profileid').'-'.$oGrant->Get('action').'-'.$oGrant->Get('class')] = $oGrant->GetKey();
|
||||
}
|
||||
}
|
||||
|
||||
$sCacheKey = "$iProfile-$sAction-$sClass";
|
||||
if (isset(self::$m_aCacheActionGrants[$sCacheKey]))
|
||||
{
|
||||
return self::$m_aCacheActionGrants[$sCacheKey];
|
||||
}
|
||||
|
||||
$oNewObj = MetaModel::NewObject("URP_ActionGrant");
|
||||
$oNewObj->Set('profileid', $iProfile);
|
||||
$oNewObj->Set('permission', $bPermission ? 'yes' : 'no');
|
||||
$oNewObj->Set('class', $sClass);
|
||||
$oNewObj->Set('action', $sAction);
|
||||
$iId = $oNewObj->DBInsertNoReload();
|
||||
self::$m_aCacheActionGrants[$sCacheKey] = $iId;
|
||||
return $iId;
|
||||
}
|
||||
|
||||
public static function DoCreateStimulusGrant($iProfile, $sStimulusCode, $sClass)
|
||||
{
|
||||
if (is_null(self::$m_aCacheStimulusGrants))
|
||||
{
|
||||
self::$m_aCacheStimulusGrants = array();
|
||||
$oFilterAll = new DBObjectSearch('URP_StimulusGrant');
|
||||
$oSet = new DBObjectSet($oFilterAll);
|
||||
while ($oGrant = $oSet->Fetch())
|
||||
{
|
||||
self::$m_aCacheStimulusGrants[$oGrant->Get('profileid').'-'.$oGrant->Get('stimulus').'-'.$oGrant->Get('class')] = $oGrant->GetKey();
|
||||
}
|
||||
}
|
||||
|
||||
$sCacheKey = "$iProfile-$sStimulusCode-$sClass";
|
||||
if (isset(self::$m_aCacheStimulusGrants[$sCacheKey]))
|
||||
{
|
||||
return self::$m_aCacheStimulusGrants[$sCacheKey];
|
||||
}
|
||||
$oNewObj = MetaModel::NewObject("URP_StimulusGrant");
|
||||
$oNewObj->Set('profileid', $iProfile);
|
||||
$oNewObj->Set('permission', 'yes');
|
||||
$oNewObj->Set('class', $sClass);
|
||||
$oNewObj->Set('stimulus', $sStimulusCode);
|
||||
$iId = $oNewObj->DBInsertNoReload();
|
||||
self::$m_aCacheStimulusGrants[$sCacheKey] = $iId;
|
||||
return $iId;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the built-in Administrator profile with its reserved name
|
||||
*/
|
||||
public static function DoCreateAdminProfile()
|
||||
{
|
||||
self::DoCreateProfile(ADMIN_PROFILE_NAME, 'Has the rights on everything (bypassing any control)', true /* reserved name */);
|
||||
}
|
||||
|
||||
/*
|
||||
* Overload the standard behavior to preserve reserved names
|
||||
*/
|
||||
public function DoCheckToWrite()
|
||||
{
|
||||
parent::DoCheckToWrite();
|
||||
|
||||
if ($this->m_bCheckReservedNames)
|
||||
{
|
||||
$aChanges = $this->ListChanges();
|
||||
if (array_key_exists('name', $aChanges))
|
||||
{
|
||||
if ($this->GetOriginal('name') == ADMIN_PROFILE_NAME)
|
||||
{
|
||||
$this->m_aCheckIssues[] = "The name of the Administrator profile must not be changed";
|
||||
}
|
||||
elseif ($this->Get('name') == ADMIN_PROFILE_NAME)
|
||||
{
|
||||
$this->m_aCheckIssues[] = ADMIN_PROFILE_NAME." is a reserved to the built-in Administrator profile";
|
||||
}
|
||||
elseif ($this->GetOriginal('name') == PORTAL_PROFILE_NAME)
|
||||
{
|
||||
$this->m_aCheckIssues[] = "The name of the User Portal profile must not be changed";
|
||||
}
|
||||
elseif ($this->Get('name') == PORTAL_PROFILE_NAME)
|
||||
{
|
||||
$this->m_aCheckIssues[] = PORTAL_PROFILE_NAME." is a reserved to the built-in User Portal profile";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function GetGrantAsHtml($oUserRights, $sClass, $sAction)
|
||||
{
|
||||
$bGrant = $oUserRights->GetProfileActionGrant($this->GetKey(), $sClass, $sAction);
|
||||
if (is_null($bGrant))
|
||||
{
|
||||
return '<span style="background-color: #ffdddd;">'.Dict::S('UI:UserManagement:ActionAllowed:No').'</span>';
|
||||
}
|
||||
elseif ($bGrant)
|
||||
$iGrant = $oUserRights->GetProfileActionGrant($this->GetKey(), $sClass, $sAction);
|
||||
if (!is_null($iGrant))
|
||||
{
|
||||
return '<span style="background-color: #ddffdd;">'.Dict::S('UI:UserManagement:ActionAllowed:Yes').'</span>';
|
||||
}
|
||||
@@ -145,8 +284,8 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
$aStimuli = array();
|
||||
foreach (MetaModel::EnumStimuli($sClass) as $sStimulusCode => $oStimulus)
|
||||
{
|
||||
$bGrant = $oUserRights->GetClassStimulusGrant($this->GetKey(), $sClass, $sStimulusCode);
|
||||
if ($bGrant === true)
|
||||
$oGrant = $oUserRights->GetClassStimulusGrant($this->GetKey(), $sClass, $sStimulusCode);
|
||||
if (is_object($oGrant) && ($oGrant->Get('permission') == 'yes'))
|
||||
{
|
||||
$aStimuli[] = '<span title="'.$sStimulusCode.': '.htmlentities($oStimulus->GetDescription(), ENT_QUOTES, 'UTF-8').'">'.htmlentities($oStimulus->GetLabel(), ENT_QUOTES, 'UTF-8').'</span>';
|
||||
}
|
||||
@@ -155,12 +294,12 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
|
||||
$aDisplayData[] = array(
|
||||
'class' => MetaModel::GetName($sClass),
|
||||
'read' => $this->GetGrantAsHtml($oUserRights, $sClass, 'r'),
|
||||
'bulkread' => $this->GetGrantAsHtml($oUserRights, $sClass, 'br'),
|
||||
'write' => $this->GetGrantAsHtml($oUserRights, $sClass, 'w'),
|
||||
'bulkwrite' => $this->GetGrantAsHtml($oUserRights, $sClass, 'bw'),
|
||||
'delete' => $this->GetGrantAsHtml($oUserRights, $sClass, 'd'),
|
||||
'bulkdelete' => $this->GetGrantAsHtml($oUserRights, $sClass, 'bd'),
|
||||
'read' => $this->GetGrantAsHtml($oUserRights, $sClass, 'Read'),
|
||||
'bulkread' => $this->GetGrantAsHtml($oUserRights, $sClass, 'Bulk Read'),
|
||||
'write' => $this->GetGrantAsHtml($oUserRights, $sClass, 'Modify'),
|
||||
'bulkwrite' => $this->GetGrantAsHtml($oUserRights, $sClass, 'Bulk Modify'),
|
||||
'delete' => $this->GetGrantAsHtml($oUserRights, $sClass, 'Delete'),
|
||||
'bulkdelete' => $this->GetGrantAsHtml($oUserRights, $sClass, 'Bulk Delete'),
|
||||
'stimuli' => $sStimuli,
|
||||
);
|
||||
}
|
||||
@@ -186,30 +325,6 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
$this->DoShowGrantSumary($oPage);
|
||||
}
|
||||
}
|
||||
|
||||
public static function GetReadOnlyAttributes()
|
||||
{
|
||||
return array('name', 'description');
|
||||
}
|
||||
|
||||
|
||||
// returns an array of id => array of column => php value(so-called "real value")
|
||||
public static function GetPredefinedObjects()
|
||||
{
|
||||
return ProfilesConfig::GetProfilesValues();
|
||||
}
|
||||
|
||||
// Before deleting a profile,
|
||||
// preserve DB integrity by deleting links to users
|
||||
protected function OnDelete()
|
||||
{
|
||||
// Note: this may break the rule that says: "a user must have at least ONE profile" !
|
||||
$oLnkSet = $this->Get('user_list');
|
||||
while($oLnk = $oLnkSet->Fetch())
|
||||
{
|
||||
$oLnk->DBDelete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -295,17 +410,123 @@ class URP_UserOrg extends UserRightsBaseClassGUI
|
||||
}
|
||||
|
||||
|
||||
class URP_ActionGrant extends UserRightsBaseClass
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "addon/userrights",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "profileid",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_urp_grant_actions",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
|
||||
// Common to all grant classes (could be factorized by class inheritence, but this has to be benchmarked)
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("profileid", array("targetclass"=>"URP_Profiles", "jointype"=> "", "allowed_values"=>null, "sql"=>"profileid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("profile", array("allowed_values"=>null, "extkey_attcode"=> 'profileid', "target_attcode"=>"name")));
|
||||
MetaModel::Init_AddAttribute(new AttributeClass("class", array("class_category"=>"", "more_values"=>"", "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeString("action", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('profileid', 'class', 'permission', 'action')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('class', 'permission', 'action')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('profileid', 'class', 'permission', 'action')); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('advanced_search', array('profileid', 'class', 'permission', 'action')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class URP_StimulusGrant extends UserRightsBaseClass
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "addon/userrights",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "profileid",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_urp_grant_stimulus",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
|
||||
// Common to all grant classes (could be factorized by class inheritence, but this has to be benchmarked)
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("profileid", array("targetclass"=>"URP_Profiles", "jointype"=> "", "allowed_values"=>null, "sql"=>"profileid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalField("profile", array("allowed_values"=>null, "extkey_attcode"=> 'profileid', "target_attcode"=>"name")));
|
||||
MetaModel::Init_AddAttribute(new AttributeClass("class", array("class_category"=>"", "more_values"=>"", "sql"=>"class", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("permission", array("allowed_values"=>new ValueSetEnum('yes,no'), "sql"=>"permission", "default_value"=>"yes", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeString("stimulus", array("allowed_values"=>null, "sql"=>"action", "default_value"=>"", "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('profileid', 'class', 'permission', 'stimulus')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('class', 'permission', 'stimulus')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('profileid', 'class', 'permission', 'stimulus')); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('advanced_search', array('profileid', 'class', 'permission', 'stimulus')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class URP_AttributeGrant extends UserRightsBaseClass
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "addon/userrights",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "actiongrantid",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_urp_grant_attributes",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
//MetaModel::Init_InheritAttributes();
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("actiongrantid", array("targetclass"=>"URP_ActionGrant", "jointype"=> "", "allowed_values"=>null, "sql"=>"actiongrantid", "is_null_allowed"=>false, "on_target_delete"=>DEL_MANUAL, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("attcode", array("allowed_values"=>null, "sql"=>"attcode", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('actiongrantid', 'attcode')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('attcode')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('actiongrantid', 'attcode')); // Criteria of the std search form
|
||||
MetaModel::Init_SetZListItems('advanced_search', array('actiongrantid', 'attcode')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
class UserRightsProfile extends UserRightsAddOnAPI
|
||||
{
|
||||
static public $m_aActionCodes = array(
|
||||
UR_ACTION_READ => 'r',
|
||||
UR_ACTION_MODIFY => 'w',
|
||||
UR_ACTION_DELETE => 'd',
|
||||
UR_ACTION_BULK_READ => 'br',
|
||||
UR_ACTION_BULK_MODIFY => 'bw',
|
||||
UR_ACTION_BULK_DELETE => 'bd',
|
||||
UR_ACTION_READ => 'read',
|
||||
UR_ACTION_MODIFY => 'modify',
|
||||
UR_ACTION_DELETE => 'delete',
|
||||
UR_ACTION_BULK_READ => 'bulk read',
|
||||
UR_ACTION_BULK_MODIFY => 'bulk modify',
|
||||
UR_ACTION_BULK_DELETE => 'bulk delete',
|
||||
);
|
||||
|
||||
// Installation: create the very first user
|
||||
@@ -383,6 +604,10 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
protected $m_aUserProfiles = array(); // userid,profileid -> object
|
||||
protected $m_aUserOrgs = array(); // userid -> array of orgid
|
||||
|
||||
// Those arrays could be completed on demand (inheriting parent permissions)
|
||||
protected $m_aClassActionGrants = null; // profile, class, action -> actiongrantid (or false if NO, or null/missing if undefined)
|
||||
protected $m_aClassStimulusGrants = array(); // profile, class, stimulus -> permission
|
||||
|
||||
// Built on demand, could be optimized if necessary (doing a query for each attribute that needs to be read)
|
||||
protected $m_aObjectActionGrants = array();
|
||||
|
||||
@@ -461,10 +686,32 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
$this->m_aAdmins = array();
|
||||
$this->m_aPortalUsers = array();
|
||||
|
||||
// Cache
|
||||
// Loaded on demand (time consuming as compared to the others)
|
||||
$this->m_aClassActionGrants = null;
|
||||
$this->m_aClassStimulusGrants = null;
|
||||
|
||||
$this->m_aObjectActionGrants = array();
|
||||
}
|
||||
|
||||
// Separate load: this cache is much more time consuming while loading
|
||||
// Thus it is loaded iif required
|
||||
// Could be improved by specifying the profile id
|
||||
public function LoadActionGrantCache()
|
||||
{
|
||||
if (!is_null($this->m_aClassActionGrants)) return;
|
||||
|
||||
$oKPI = new ExecutionKPI();
|
||||
|
||||
$oFilter = DBObjectSearch::FromOQL_AllData("SELECT URP_ActionGrant AS p WHERE p.permission = 'yes'");
|
||||
$aGrants = $oFilter->ToDataArray();
|
||||
foreach($aGrants as $aGrant)
|
||||
{
|
||||
$this->m_aClassActionGrants[$aGrant['profileid']][$aGrant['class']][strtolower($aGrant['action'])] = $aGrant['id'];
|
||||
}
|
||||
|
||||
$oKPI->ComputeAndReport('Load of action grants');
|
||||
}
|
||||
|
||||
public function LoadCache()
|
||||
{
|
||||
if (!is_null($this->m_aProfiles)) return;
|
||||
@@ -484,6 +731,14 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
$this->m_aProfiles[$oProfile->GetKey()] = $oProfile;
|
||||
}
|
||||
|
||||
$this->m_aClassStimulusGrants = array();
|
||||
$oStimGrantSet = new DBObjectSet(DBObjectSearch::FromOQL_AllData("SELECT URP_StimulusGrant"));
|
||||
$this->m_aStimGrants = array();
|
||||
while ($oStimGrant = $oStimGrantSet->Fetch())
|
||||
{
|
||||
$this->m_aClassStimulusGrants[$oStimGrant->Get('profileid')][$oStimGrant->Get('class')][$oStimGrant->Get('stimulus')] = $oStimGrant;
|
||||
}
|
||||
|
||||
$oKPI->ComputeAndReport('Load of user management cache (excepted Action Grants)');
|
||||
|
||||
/*
|
||||
@@ -491,6 +746,8 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
print_r($this->m_aProfiles);
|
||||
print_r($this->m_aUserProfiles);
|
||||
print_r($this->m_aUserOrgs);
|
||||
print_r($this->m_aClassActionGrants);
|
||||
print_r($this->m_aClassStimulusGrants);
|
||||
echo "</pre>\n";
|
||||
exit;
|
||||
*/
|
||||
@@ -634,10 +891,29 @@ exit;
|
||||
// This verb has been made public to allow the development of an accurate feedback for the current configuration
|
||||
public function GetProfileActionGrant($iProfile, $sClass, $sAction)
|
||||
{
|
||||
$this->LoadActionGrantCache();
|
||||
|
||||
// Note: action is forced lowercase to be more flexible (historical bug)
|
||||
$sAction = strtolower($sAction);
|
||||
if (isset($this->m_aClassActionGrants[$iProfile][$sClass][$sAction]))
|
||||
{
|
||||
return $this->m_aClassActionGrants[$iProfile][$sClass][$sAction];
|
||||
}
|
||||
|
||||
return ProfilesConfig::GetProfileActionGrant($iProfile, $sClass, $sAction);
|
||||
// Recursively look for the grant record in the class hierarchy
|
||||
$sParentClass = MetaModel::GetParentPersistentClass($sClass);
|
||||
if (empty($sParentClass))
|
||||
{
|
||||
$iGrant = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Recursively look for the grant record in the class hierarchy
|
||||
$iGrant = $this->GetProfileActionGrant($iProfile, $sParentClass, $sAction);
|
||||
}
|
||||
|
||||
$this->m_aClassActionGrants[$iProfile][$sClass][$sAction] = $iGrant;
|
||||
return $iGrant;
|
||||
}
|
||||
|
||||
protected function GetUserActionGrant($oUser, $sClass, $iActionCode)
|
||||
@@ -652,32 +928,39 @@ exit;
|
||||
|
||||
$sAction = self::$m_aActionCodes[$iActionCode];
|
||||
|
||||
$bStatus = null;
|
||||
$iPermission = UR_ALLOWED_NO;
|
||||
$aAttributes = array();
|
||||
foreach($this->GetUserProfiles($iUser) as $iProfile => $oProfile)
|
||||
{
|
||||
$bGrant = $this->GetProfileActionGrant($iProfile, $sClass, $sAction);
|
||||
if (!is_null($bGrant))
|
||||
{
|
||||
if ($bGrant)
|
||||
$iGrant = $this->GetProfileActionGrant($iProfile, $sClass, $sAction);
|
||||
if (is_null($iGrant) || !$iGrant)
|
||||
{
|
||||
if (is_null($bStatus))
|
||||
{
|
||||
$bStatus = true;
|
||||
}
|
||||
continue; // loop to the next profile
|
||||
}
|
||||
else
|
||||
{
|
||||
$bStatus = false;
|
||||
$iPermission = UR_ALLOWED_YES;
|
||||
|
||||
// update the list of attributes with those allowed for this profile
|
||||
//
|
||||
$oSearch = DBObjectSearch::FromOQL_AllData("SELECT URP_AttributeGrant WHERE actiongrantid = :actiongrantid");
|
||||
$oSet = new DBObjectSet($oSearch, array(), array('actiongrantid' => $iGrant));
|
||||
$aProfileAttributes = $oSet->GetColumnAsArray('attcode', false);
|
||||
if (count($aProfileAttributes) == 0)
|
||||
{
|
||||
$aAllAttributes = array_keys(MetaModel::ListAttributeDefs($sClass));
|
||||
$aAttributes = array_merge($aAttributes, $aAllAttributes);
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAttributes = array_merge($aAttributes, $aProfileAttributes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$iPermission = $bStatus ? UR_ALLOWED_YES : UR_ALLOWED_NO;
|
||||
|
||||
$aRes = array(
|
||||
'permission' => $iPermission,
|
||||
// 'attributes' => $aAttributes,
|
||||
'attributes' => $aAttributes,
|
||||
);
|
||||
$this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode] = $aRes;
|
||||
return $aRes;
|
||||
@@ -766,13 +1049,30 @@ exit;
|
||||
// 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
|
||||
$aObjectPermissions = $this->GetUserActionGrant($oUser, $sClass, $iActionCode);
|
||||
return $aObjectPermissions['permission'];
|
||||
$aAttributes = $aObjectPermissions['attributes'];
|
||||
if (in_array($sAttCode, $aAttributes))
|
||||
{
|
||||
return $aObjectPermissions['permission'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return UR_ALLOWED_NO;
|
||||
}
|
||||
}
|
||||
|
||||
// This verb has been made public to allow the development of an accurate feedback for the current configuration
|
||||
public function GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode)
|
||||
{
|
||||
return ProfilesConfig::GetProfileStimulusGrant($iProfile, $sClass, $sStimulusCode);
|
||||
$this->LoadCache();
|
||||
|
||||
if (isset($this->m_aClassStimulusGrants[$iProfile][$sClass][$sStimulusCode]))
|
||||
{
|
||||
return $this->m_aClassStimulusGrants[$iProfile][$sClass][$sStimulusCode];
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public function IsStimulusAllowed($oUser, $sClass, $sStimulusCode, $oInstanceSet = null)
|
||||
@@ -783,27 +1083,16 @@ exit;
|
||||
|
||||
// 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;
|
||||
$iPermission = UR_ALLOWED_NO;
|
||||
foreach($this->GetUserProfiles($iUser) as $iProfile => $oProfile)
|
||||
{
|
||||
$bGrant = $this->GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode);
|
||||
if (!is_null($bGrant))
|
||||
{
|
||||
if ($bGrant)
|
||||
$oGrantRecord = $this->GetClassStimulusGrant($iProfile, $sClass, $sStimulusCode);
|
||||
if (!is_null($oGrantRecord))
|
||||
{
|
||||
if (is_null($bStatus))
|
||||
{
|
||||
$bStatus = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$bStatus = false;
|
||||
// no need to fetch the record, we've requested the records having permission = 'yes'
|
||||
$iPermission = UR_ALLOWED_YES;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$iPermission = $bStatus ? UR_ALLOWED_YES : UR_ALLOWED_NO;
|
||||
return $iPermission;
|
||||
}
|
||||
|
||||
|
||||
@@ -117,38 +117,31 @@ class ajax_page extends WebPage
|
||||
<<<EOF
|
||||
// The "tab widgets" to handle.
|
||||
var tabs = $('div[id^=tabbedContent]');
|
||||
|
||||
if ($.bbq)
|
||||
|
||||
// This selector will be reused when selecting actual tab widget A elements.
|
||||
var tab_a_selector = 'ul.ui-tabs-nav a';
|
||||
|
||||
// Enable tabs on all tab widgets. The `event` property must be overridden so
|
||||
// that the tabs aren't changed on click, and any custom event name can be
|
||||
// specified. Note that if you define a callback for the 'select' event, it
|
||||
// will be executed for the selected tab whenever the hash changes.
|
||||
tabs.tabs({ event: 'change' });
|
||||
|
||||
// Define our own click handler for the tabs, overriding the default.
|
||||
tabs.find( tab_a_selector ).click(function()
|
||||
{
|
||||
// This selector will be reused when selecting actual tab widget A elements.
|
||||
var tab_a_selector = 'ul.ui-tabs-nav a';
|
||||
var state = {};
|
||||
|
||||
// Get the id of this tab widget.
|
||||
var id = $(this).closest( 'div[id^=tabbedContent]' ).attr( 'id' );
|
||||
|
||||
// Enable tabs on all tab widgets. The `event` property must be overridden so
|
||||
// that the tabs aren't changed on click, and any custom event name can be
|
||||
// specified. Note that if you define a callback for the 'select' event, it
|
||||
// will be executed for the selected tab whenever the hash changes.
|
||||
tabs.tabs({ event: 'change' });
|
||||
|
||||
// Define our own click handler for the tabs, overriding the default.
|
||||
tabs.find( tab_a_selector ).click(function()
|
||||
{
|
||||
var state = {};
|
||||
|
||||
// Get the id of this tab widget.
|
||||
var id = $(this).closest( 'div[id^=tabbedContent]' ).attr( 'id' );
|
||||
|
||||
// Get the index of this tab.
|
||||
var idx = $(this).parent().prevAll().length;
|
||||
|
||||
// Set the state!
|
||||
state[ id ] = idx;
|
||||
$.bbq.pushState( state );
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
tabs.tabs();
|
||||
}
|
||||
// Get the index of this tab.
|
||||
var idx = $(this).parent().prevAll().length;
|
||||
|
||||
// Set the state!
|
||||
state[ id ] = idx;
|
||||
$.bbq.pushState( state );
|
||||
});
|
||||
EOF
|
||||
);
|
||||
}
|
||||
@@ -161,7 +154,7 @@ EOF
|
||||
$container_index = 0;
|
||||
if (count($m_aTabs) > 0)
|
||||
{
|
||||
$sTabs = "<!-- tabs -->\n<div id=\"tabbedContent_{$sPrefix}{$sTabContainerName}\" class=\"light\">\n";
|
||||
$sTabs = "<!-- tabs -->\n<div id=\"tabbedContent_{$sPrefix}{$container_index}\" class=\"light\">\n";
|
||||
$sTabs .= "<ul>\n";
|
||||
// Display the unordered list that will be rendered as the tabs
|
||||
$i = 0;
|
||||
@@ -307,7 +300,7 @@ EOF
|
||||
*/
|
||||
public function add_ready_script($sScript)
|
||||
{
|
||||
$this->m_sReadyScript .= $sScript."\n";
|
||||
$this->m_sReadyScript .= $sScript;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -98,7 +98,7 @@ class ApplicationContext
|
||||
if (!isset(self::$aDefaultValues))
|
||||
{
|
||||
self::$aDefaultValues = array();
|
||||
$aContext = utils::ReadParam('c', array(), false, 'context_param');
|
||||
$aContext = utils::ReadParam('c', array());
|
||||
foreach($this->aNames as $sName)
|
||||
{
|
||||
$sValue = isset($aContext[$sName]) ? $aContext[$sName] : '';
|
||||
@@ -221,17 +221,17 @@ class ApplicationContext
|
||||
if (is_callable($aCallSpec))
|
||||
{
|
||||
$sAttCode = call_user_func($aCallSpec, $key); // Returns null when there is no mapping for this parameter
|
||||
}
|
||||
|
||||
if (MetaModel::IsValidAttCode($sClass, $sAttCode))
|
||||
if (MetaModel::IsValidAttCode($sClass, $sAttCode))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
if ($oAttDef->IsWritable())
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
if ($oAttDef->IsWritable())
|
||||
$value = $this->GetCurrentValue($key, null);
|
||||
if (!is_null($value))
|
||||
{
|
||||
$value = $this->GetCurrentValue($key, null);
|
||||
if (!is_null($value))
|
||||
{
|
||||
$oObj->Set($sAttCode, $value);
|
||||
}
|
||||
$oObj->Set($sAttCode, $value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
@@ -48,146 +48,4 @@ interface iApplicationObjectExtension
|
||||
public function OnDBDelete($oObject, $oChange = null);
|
||||
}
|
||||
|
||||
/**
|
||||
* New extension to add menu items in the "popup" menus inside iTop. Provides a greater flexibility than
|
||||
* iApplicationUIExtension::EnumAllowedActions.
|
||||
*
|
||||
* To add some menus into iTop, declare a class that implements this interface, it will be called automatically
|
||||
* by the application, as long as the class definition is included somewhere in the code
|
||||
*/
|
||||
interface iPopupMenuExtension
|
||||
{
|
||||
// Possible types of menu into which new items can be added
|
||||
const MENU_OBJLIST_ACTIONS = 1; // $param is a DBObjectSet containing the list of objects
|
||||
const MENU_OBJLIST_TOOLKIT = 2; // $param is a DBObjectSet containing the list of objects
|
||||
const MENU_OBJDETAILS_ACTIONS = 3; // $param is a DBObject instance: the object currently displayed
|
||||
const MENU_DASHBOARD_ACTIONS = 4; // $param is a Dashboard instance: the dashboard currently displayed
|
||||
const MENU_USER_ACTIONS = 5; // $param is a null ??
|
||||
|
||||
/**
|
||||
* Get the list of items to be added to a menu. The items will be inserted in the menu in the order of the returned array
|
||||
* @param int $iMenuId The identifier of the type of menu, as listed by the constants MENU_xxx above
|
||||
* @param mixed $param Depends on $iMenuId, see the constants defined above
|
||||
* @return Array An array of ApplicationPopupMenuItem or an empty array if no action is to be added to the menu
|
||||
*/
|
||||
public static function EnumItems($iMenuId, $param);
|
||||
}
|
||||
|
||||
/**
|
||||
* Each menu items is defined by an instance of an object derived from the class
|
||||
* ApplicationPopupMenu below
|
||||
*
|
||||
*/
|
||||
abstract class ApplicationPopupMenuItem
|
||||
{
|
||||
protected $sUID;
|
||||
protected $sLabel;
|
||||
|
||||
public function __construct($sUID, $sLabel)
|
||||
{
|
||||
$this->sUID = $sUID;
|
||||
$this->sLabel = $sLabel;
|
||||
}
|
||||
|
||||
public function GetUID()
|
||||
{
|
||||
return $this->sUID;
|
||||
}
|
||||
|
||||
public function GetLabel()
|
||||
{
|
||||
return $this->sLabel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the components to create a popup menu item in HTML
|
||||
* @return Hash A hash array: array('label' => , 'url' => , 'target' => , 'onclick' => )
|
||||
*/
|
||||
abstract public function GetMenuItem();
|
||||
|
||||
public function GetLinkedScripts()
|
||||
{
|
||||
return array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for adding an item into a popup menu that browses to the given URL
|
||||
*/
|
||||
class URLPopupMenuItem extends ApplicationPopupMenuItem
|
||||
{
|
||||
protected $sURL;
|
||||
protected $sTarget;
|
||||
|
||||
/**
|
||||
* Class for adding an item that browses to the given URL
|
||||
* @param string $sUID The unique identifier of this menu in iTop... make sure you pass something unique enough
|
||||
* @param string $sLabel The display label of the menu (must be localized)
|
||||
* @param string $sURL If the menu is an hyperlink, provide the absolute hyperlink here
|
||||
* @param string $sTarget In case the menu is an hyperlink and a specific target is needed (_blank for example), pass it here
|
||||
*/
|
||||
public function __construct($sUID, $sLabel, $sURL, $sTarget = '_top')
|
||||
{
|
||||
parent::__construct($sUID, $sLabel);
|
||||
$this->sURL = $sURL;
|
||||
$this->sTarget = $sTarget;
|
||||
}
|
||||
|
||||
public function GetMenuItem()
|
||||
{
|
||||
return array ('label' => $this->GetLabel(), 'url' => $this->sURL, 'target' => $this->sTarget);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for adding an item into a popup menu that triggers some Javascript code
|
||||
*/
|
||||
class JSPopupMenuItem extends ApplicationPopupMenuItem
|
||||
{
|
||||
protected $sJSCode;
|
||||
protected $aIncludeJSFiles;
|
||||
|
||||
/**
|
||||
* Class for adding an item that triggers some Javascript code
|
||||
* @param string $sUID The unique identifier of this menu in iTop... make sure you pass something unique enough
|
||||
* @param string $sLabel The display label of the menu (must be localized)
|
||||
* @param string $sJSCode In case the menu consists in executing some havascript code inside the page, pass it here. If supplied $sURL ans $sTarget will be ignored
|
||||
* @param array $aIncludeJSFiles An array of file URLs to be included (once) to provide some JS libraries for the page.
|
||||
*/
|
||||
public function __construct($sUID, $sLabel, $sJSCode, $aIncludeJSFiles = array())
|
||||
{
|
||||
parent::__construct($sUID, $sLabel);
|
||||
$this->sJSCode = $sJSCode;
|
||||
$this->aIncludeJSFiles = $aIncludeJSFiles;
|
||||
}
|
||||
|
||||
public function GetMenuItem()
|
||||
{
|
||||
return array ('label' => $this->GetLabel(), 'onclick' => $this->sJSCode, 'url' => '#');
|
||||
}
|
||||
|
||||
public function GetLinkedScripts()
|
||||
{
|
||||
return $this->aIncludeJSFiles;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class for adding a separator (horizontal line, not selectable) the output
|
||||
* will automatically reduce several consecutive separators to just one
|
||||
*/
|
||||
class SeparatorPopupMenuItem extends ApplicationPopupMenuItem
|
||||
{
|
||||
/**
|
||||
* Class for inserting a separator into a popup menu
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('', '');
|
||||
}
|
||||
|
||||
public function GetMenuItem()
|
||||
{
|
||||
return array ('label' => '<hr class="menu-separator">', 'url' => '');
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
|
||||
require_once(APPROOT."/application/webpage.class.inc.php");
|
||||
|
||||
class CLIPage implements Page
|
||||
class CLIPage
|
||||
{
|
||||
function __construct($s_title)
|
||||
{
|
||||
|
||||
@@ -39,7 +39,6 @@ require_once(APPROOT.'/application/ui.linkswidget.class.inc.php');
|
||||
require_once(APPROOT.'/application/ui.passwordwidget.class.inc.php');
|
||||
require_once(APPROOT.'/application/ui.extkeywidget.class.inc.php');
|
||||
require_once(APPROOT.'/application/ui.htmleditorwidget.class.inc.php');
|
||||
require_once(APPROOT.'/application/datatable.class.inc.php');
|
||||
|
||||
/**
|
||||
* All objects to be displayed in the application (either as a list or as details)
|
||||
@@ -99,7 +98,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
// action menu
|
||||
$oSingletonFilter = new DBObjectSearch(get_class($this));
|
||||
$oSingletonFilter->AddCondition('id', $this->GetKey(), '=');
|
||||
$oBlock = new MenuBlock($oSingletonFilter, 'details', false);
|
||||
$oBlock = new MenuBlock($oSingletonFilter, 'popup', false);
|
||||
$oBlock->Display($oPage, -1);
|
||||
|
||||
// Master data sources
|
||||
@@ -245,8 +244,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
// Display mode
|
||||
if (!$oAttDef->IsLinkset()) continue; // Process only linkset attributes...
|
||||
|
||||
// $oSet = new DBObjectSet($this->Get($sAttCode)->GetFilter()); // Why do something so useless ?
|
||||
$oSet = $this->Get($sAttCode);
|
||||
$oSet = new DBObjectSet($this->Get($sAttCode)->GetFilter());
|
||||
$iCount = $oSet->Count();
|
||||
$sCount = '';
|
||||
if ($iCount != 0)
|
||||
@@ -296,8 +294,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
'object_id' => $this->GetKey(),
|
||||
'menu' => true,
|
||||
'default' => $aDefaults,
|
||||
'table_id' => $sClass.'_'.$sAttCode,
|
||||
);
|
||||
);
|
||||
|
||||
$oBlock = new DisplayBlock($oFilter, 'list', false);
|
||||
$oBlock->Display($oPage, $sInputId, $aParams);
|
||||
@@ -312,7 +309,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
$oPage->p(MetaModel::GetClassIcon($sTargetClass)." ".$oAttDef->GetDescription().'<span id="busy_'.$sInputId.'"></span>');
|
||||
|
||||
$sValue = $this->Get($sAttCode);
|
||||
$sDisplayValue = ''; // not used
|
||||
$sDisplayValue = $this->GetEditValue($sAttCode);
|
||||
$aArgs = array('this' => $this);
|
||||
$sHTMLValue = "<span id=\"field_{$sInputId}\">".self::GetFormElementForField($oPage, $sClass, $sAttCode, $oAttDef, $sValue, $sDisplayValue, $sInputId, '', $iFlags, $aArgs).'</span>';
|
||||
$aFieldsMap[$sAttCode] = $sInputId;
|
||||
@@ -342,8 +339,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
'object_id' => $this->GetKey(),
|
||||
'menu' => false,
|
||||
'default' => $aDefaults,
|
||||
'table_id' => $sClass.'_'.$sAttCode,
|
||||
);
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -359,7 +355,6 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
'view_link' => false,
|
||||
'menu' => false,
|
||||
'display_limit' => true, // By default limit the list to speed up the initial load & display
|
||||
'table_id' => $sClass.'_'.$sAttCode,
|
||||
);
|
||||
}
|
||||
$oPage->p(MetaModel::GetClassIcon($sTargetClass)." ".$oAttDef->GetDescription());
|
||||
@@ -684,6 +679,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
$sHtml = '';
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sClassName = $oSet->GetFilter()->GetClass();
|
||||
$aAttribs = array();
|
||||
$sZListName = isset($aExtraParams['zlist']) ? ($aExtraParams['zlist']) : 'list';
|
||||
if ($sZListName !== false)
|
||||
{
|
||||
@@ -706,6 +702,9 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
}
|
||||
}
|
||||
|
||||
// Load only the requested columns
|
||||
$sClassAlias = $oSet->GetFilter()->GetClassAlias();
|
||||
$oSet->OptimizeColumnLoad(array($sClassAlias => $aList));
|
||||
|
||||
if (!empty($sLinkageAttribute))
|
||||
{
|
||||
@@ -741,45 +740,220 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
// Then display all the attributes linked to the other end of the relationship
|
||||
$aList = $aDisplayList;
|
||||
}
|
||||
|
||||
$sSelectMode = 'none';
|
||||
if ($bSelectMode)
|
||||
{
|
||||
$sSelectMode = $bSingleSelectMode ? 'single' : 'multiple';
|
||||
if (!$bSingleSelectMode)
|
||||
{
|
||||
$aAttribs['form::select'] = array('label' => "<input type=\"checkbox\" onClick=\"CheckAll('.selectList{$iListId}:not(:disabled)', this.checked);\" class=\"checkAll\"></input>", 'description' => Dict::S('UI:SelectAllToggle+'));
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAttribs['form::select'] = array('label' => "", 'description' => '');
|
||||
}
|
||||
}
|
||||
|
||||
$sClassAlias = $oSet->GetClassAlias();
|
||||
$bDisplayLimit = isset($aExtraParams['display_limit']) ? $aExtraParams['display_limit'] : true;
|
||||
|
||||
// Load only the requested columns
|
||||
$oSet->OptimizeColumnLoad(array($sClassAlias => $aList));
|
||||
|
||||
$sTableId = isset($aExtraParams['table_id']) ? $aExtraParams['table_id'] : null;
|
||||
$aClassAliases = array( $sClassAlias => $sClassName);
|
||||
$oDataTable = new DataTable($iListId, $oSet, $aClassAliases, $sTableId);
|
||||
$oSettings = DataTableSettings::GetDataModelSettings($aClassAliases, $bViewLink, array($sClassAlias => $aList));
|
||||
|
||||
if ($bDisplayLimit)
|
||||
if ($bViewLink)
|
||||
{
|
||||
$iDefaultPageSize = appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit());
|
||||
$oSettings->iDefaultPageSize = $iDefaultPageSize;
|
||||
$aAttribs['key'] = array('label' => MetaModel::GetName($sClassName), 'description' => '');
|
||||
}
|
||||
foreach($aList as $sAttCode)
|
||||
{
|
||||
$aAttribs[$sAttCode] = array('label' => MetaModel::GetLabel($sClassName, $sAttCode), 'description' => MetaModel::GetDescription($sClassName, $sAttCode));
|
||||
}
|
||||
$aValues = array();
|
||||
$bDisplayLimit = isset($aExtraParams['display_limit']) ? $aExtraParams['display_limit'] : true;
|
||||
$iMaxObjects = -1;
|
||||
//if ($bDisplayLimit && $bTruncated)
|
||||
//{
|
||||
if ($bDisplayLimit && ($oSet->Count() > MetaModel::GetConfig()->GetMaxDisplayLimit()))
|
||||
{
|
||||
$iMaxObjects = MetaModel::GetConfig()->GetMinDisplayLimit();
|
||||
$oSet->SetLimit($iMaxObjects);
|
||||
}
|
||||
//}
|
||||
$oSet->Seek(0);
|
||||
while (($oObj = $oSet->Fetch()) && ($iMaxObjects != 0))
|
||||
{
|
||||
$aRow = array();
|
||||
$sHilightClass = $oObj->GetHilightClass();
|
||||
if ($sHilightClass != '')
|
||||
{
|
||||
$aRow['@class'] = $sHilightClass;
|
||||
}
|
||||
if ($bViewLink)
|
||||
{
|
||||
$aRow['key'] = $oObj->GetHyperLink();
|
||||
}
|
||||
if ($bSelectMode)
|
||||
{
|
||||
if (array_key_exists('selection_enabled', $aExtraParams) && isset($aExtraParams['selection_enabled'][$oObj->GetKey()]))
|
||||
{
|
||||
$sDisabled = ($aExtraParams['selection_enabled'][$oObj->GetKey()]) ? '' : ' disabled="disabled"';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sDisabled = '';
|
||||
}
|
||||
if ($bSingleSelectMode)
|
||||
{
|
||||
$aRow['form::select'] = "<input type=\"radio\" $sDisabled class=\"selectList{$iListId}\" name=\"selectObject\" value=\"".$oObj->GetKey()."\"></input>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$aRow['form::select'] = "<input type=\"checkBox\" $sDisabled class=\"selectList{$iListId}\" name=\"selectObject[]\" value=\"".$oObj->GetKey()."\"></input>";
|
||||
}
|
||||
}
|
||||
foreach($aList as $sAttCode)
|
||||
{
|
||||
$aRow[$sAttCode] = $oObj->GetAsHTML($sAttCode);
|
||||
}
|
||||
$aValues[] = $aRow;
|
||||
$iMaxObjects--;
|
||||
}
|
||||
$sHtml .= '<table class="listContainer">';
|
||||
$sColspan = '';
|
||||
// if (isset($aExtraParams['block_id']))
|
||||
// {
|
||||
// $divId = $aExtraParams['block_id'];
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// $divId = 'missingblockid';
|
||||
// }
|
||||
$sFilter = $oSet->GetFilter()->serialize();
|
||||
$iMinDisplayLimit = MetaModel::GetConfig()->GetMinDisplayLimit();
|
||||
$sCollapsedLabel = Dict::Format('UI:TruncatedResults', $iMinDisplayLimit, $oSet->Count());
|
||||
$sLinkLabel = Dict::S('UI:DisplayAll');
|
||||
foreach($oSet->GetFilter()->GetInternalParams() as $sName => $sValue)
|
||||
{
|
||||
$aExtraParams['query_params'][$sName] = $sValue;
|
||||
}
|
||||
|
||||
if ($bDisplayMenu)
|
||||
{
|
||||
$oMenuBlock = new MenuBlock($oSet->GetFilter());
|
||||
$sColspan = 'colspan="2"';
|
||||
$aMenuExtraParams = $aExtraParams;
|
||||
if (!empty($sLinkageAttribute))
|
||||
{
|
||||
//$aMenuExtraParams['linkage'] = $sLinkageAttribute;
|
||||
$aMenuExtraParams = $aExtraParams;
|
||||
}
|
||||
$sHtml .= $oMenuBlock->GetRenderContent($oPage, $aMenuExtraParams, $iListId);
|
||||
$sHtml .= '</td></tr>';
|
||||
}
|
||||
$sHtml .= "<tr><td $sColspan>";
|
||||
$sHtml .= $oPage->GetTable($aAttribs, $aValues);
|
||||
$sHtml .= '</td></tr>';
|
||||
$sHtml .= '</table>';
|
||||
$iCount = $oSet->Count();
|
||||
if ($bSelectMode)
|
||||
{
|
||||
$sHeader = Dict::Format('UI:Pagination:HeaderSelection', '<span id="total">'.$iCount.'</span>', '<span class="selectedCount">0</span>');
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHeader = Dict::Format('UI:Pagination:HeaderNoSelection', '<span id="total">'.$iCount.'</span>');
|
||||
}
|
||||
if ($bDisplayLimit && ($oSet->Count() > MetaModel::GetConfig()->GetMaxDisplayLimit()))
|
||||
{
|
||||
$sCombo = '<select class="pagesize">';
|
||||
for($iPage = 1; $iPage < 5; $iPage++)
|
||||
{
|
||||
$sSelected = '';
|
||||
if ($iPage == 1)
|
||||
{
|
||||
$sSelected = 'selected="selected"';
|
||||
}
|
||||
$iNbItems = $iPage * MetaModel::GetConfig()->GetMinDisplayLimit();
|
||||
$sCombo .= "<option $sSelected value=\"$iNbItems\">$iNbItems</option>";
|
||||
}
|
||||
$sCombo .= "<option $sSelected value=\"-1\">".Dict::S('UI:Pagination:All')."</option>";
|
||||
$sCombo .= '</select>';
|
||||
$sPages = Dict::S('UI:Pagination:PagesLabel');
|
||||
$sPageSizeCombo = Dict::Format('UI:Pagination:PageSize', $sCombo);
|
||||
$sHtml =
|
||||
<<<EOF
|
||||
<div id="pager{$iListId}" class="pager">
|
||||
<p>$sHeader</p>
|
||||
<p><table class="pagination"><tr><td>$sPages</td><td><img src="../images/first.png" class="first"/></td>
|
||||
<td><img src="../images/prev.png" class="prev"/></td>
|
||||
<td><span id="index"></span></td>
|
||||
<td><img src="../images/next.png" class="next"/></td>
|
||||
<td><img src="../images/last.png" class="last"/></td>
|
||||
<td>$sPageSizeCombo</td>
|
||||
<td><span id="loading"> </span></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
$oSettings->aSortOrder = MetaModel::GetOrderByDefault($sClassName);
|
||||
|
||||
return $oDataTable->Display($oPage, $oSettings, $bDisplayMenu, $sSelectMode, $bViewLink, $aExtraParams);
|
||||
<input type="hidden" name="selectionMode" value="positive"></input>
|
||||
</div>
|
||||
EOF
|
||||
.$sHtml;
|
||||
$aArgs = $oSet->GetArgs();
|
||||
$sExtraParams = addslashes(str_replace('"', "'", json_encode(array_merge($aExtraParams, $aArgs)))); // JSON encode, change the style of the quotes and escape them
|
||||
$sSelectMode = '';
|
||||
$sHeaders = '';
|
||||
if ($bSelectMode)
|
||||
{
|
||||
$sSelectMode = $bSingleSelectMode ? 'single' : 'multiple';
|
||||
$sHeaders = 'headers: { 0: {sorter: false}},';
|
||||
}
|
||||
$sDisplayKey = ($bViewLink) ? 'true' : 'false';
|
||||
$sDisplayList = json_encode($aList);
|
||||
$sCssCount = isset($aExtraParams['cssCount']) ? ", cssCount: '{$aExtraParams['cssCount']}'" : '';
|
||||
$iPageSize = MetaModel::GetConfig()->GetMinDisplayLimit();
|
||||
$oSet->ApplyParameters();
|
||||
$sOQL = addslashes($oSet->GetFilter()->serialize());
|
||||
$oPage->add_ready_script("$('#{$iListId} table.listResults').tablesorter( { $sHeaders widgets: ['myZebra', 'truncatedList']} ).tablesorterPager({container: $('#pager{$iListId}'), totalRows:$iCount, size: $iPageSize, filter: '$sOQL', extra_params: '$sExtraParams', select_mode: '$sSelectMode', displayKey: $sDisplayKey, displayList: $sDisplayList $sCssCount});\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHtml =
|
||||
<<<EOF
|
||||
<div id="pager{$iListId}" class="pager">
|
||||
<p>$sHeader</p>
|
||||
</div>
|
||||
EOF
|
||||
.$sHtml;
|
||||
$sHeaders = '';
|
||||
if ($bSelectMode)
|
||||
{
|
||||
$sHeaders = 'headers: { 0: {sorter: false}},';
|
||||
}
|
||||
$oPage->add_ready_script("$('#{$iListId} table.listResults').tableHover().tablesorter( { $sHeaders widgets: ['myZebra', 'truncatedList']} );\n");
|
||||
// Manage how we update the 'Ok/Add' buttons that depend on the number of selected items
|
||||
if (isset($aExtraParams['cssCount']))
|
||||
{
|
||||
$sCssCount = $aExtraParams['cssCount'];
|
||||
if ($bSingleSelectMode)
|
||||
{
|
||||
$sSelectSelector = ":radio[name^=selectObj]";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSelectSelector = ":checkbox[name^=selectObj]";
|
||||
}
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('#{$iListId} table.listResults $sSelectSelector').change(function() {
|
||||
var c = $('{$sCssCount}');
|
||||
var v = $('#{$iListId} table.listResults $sSelectSelector:checked').length;
|
||||
c.val(v);
|
||||
$('#{$iListId} .selectedCount').text(v);
|
||||
c.trigger('change');
|
||||
});
|
||||
EOF
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
public static function GetDisplayExtendedSet(WebPage $oPage, CMDBObjectSet $oSet, $aExtraParams = array())
|
||||
{
|
||||
if (empty($aExtraParams['currentId']))
|
||||
{
|
||||
$iListId = $oPage->GetUniqueId(); // Works only if not in an Ajax page !!
|
||||
}
|
||||
else
|
||||
{
|
||||
$iListId = $aExtraParams['currentId'];
|
||||
}
|
||||
static $iListId = 0;
|
||||
$iListId++;
|
||||
$aList = array();
|
||||
|
||||
// Initialize and check the parameters
|
||||
@@ -822,7 +996,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
}
|
||||
}
|
||||
$aAttribs = array();
|
||||
foreach($aAuthorizedClasses as $sAlias => $sClassName)
|
||||
foreach($aAuthorizedClasses as $sAlias => $sClassName) // TO DO: check if the user has enough rights to view the classes of the list...
|
||||
{
|
||||
if (array_key_exists($sAlias, $aExtraFields))
|
||||
{
|
||||
@@ -848,7 +1022,15 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
// Removed from the display list
|
||||
unset($aList[$sAlias][$index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($bViewLink)
|
||||
{
|
||||
$aAttribs['key_'.$sAlias] = array('label' => MetaModel::GetName($sClassName), 'description' => '');
|
||||
}
|
||||
foreach($aList[$sAlias] as $sAttCode)
|
||||
{
|
||||
$aAttribs[$sAttCode.'_'.$sAlias] = array('label' => MetaModel::GetLabel($sClassName, $sAttCode), 'description' => MetaModel::GetDescription($sClassName, $sAttCode));
|
||||
}
|
||||
}
|
||||
// Load only the requested columns
|
||||
$aAttToLoad = array(); // attributes to load
|
||||
@@ -861,23 +1043,83 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
}
|
||||
$oSet->OptimizeColumnLoad($aAttToLoad);
|
||||
|
||||
$sSelectMode = 'none';
|
||||
|
||||
$sClassAlias = $oSet->GetClassAlias();
|
||||
$oDataTable = new DataTable($iListId, $oSet, $aAuthorizedClasses);
|
||||
|
||||
$oSettings = DataTableSettings::GetDataModelSettings($aAuthorizedClasses, $bViewLink, $aList);
|
||||
|
||||
$aValues = array();
|
||||
$oSet->Seek(0);
|
||||
$bDisplayLimit = isset($aExtraParams['display_limit']) ? $aExtraParams['display_limit'] : true;
|
||||
$iMaxObjects = -1;
|
||||
if ($bDisplayLimit)
|
||||
{
|
||||
$iDefaultPageSize = appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit());
|
||||
$oSettings->iDefaultPageSize = $iDefaultPageSize;
|
||||
if ($oSet->Count() > MetaModel::GetConfig()->GetMaxDisplayLimit())
|
||||
{
|
||||
$iMaxObjects = MetaModel::GetConfig()->GetMinDisplayLimit();
|
||||
}
|
||||
}
|
||||
|
||||
$oSettings->aSortOrder = MetaModel::GetOrderByDefault($sClassName);
|
||||
|
||||
return $oDataTable->Display($oPage, $oSettings, $bDisplayMenu, $sSelectMode, $bViewLink, $aExtraParams);
|
||||
while (($aObjects = $oSet->FetchAssoc()) && ($iMaxObjects != 0))
|
||||
{
|
||||
$aRow = array();
|
||||
foreach($aAuthorizedClasses as $sAlias => $sClassName) // TO DO: check if the user has enough rights to view the classes of the list...
|
||||
{
|
||||
if ($bViewLink)
|
||||
{
|
||||
if (is_null($aObjects[$sAlias]))
|
||||
{
|
||||
$aRow['key_'.$sAlias] = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$aRow['key_'.$sAlias] = $aObjects[$sAlias]->GetHyperLink();
|
||||
}
|
||||
}
|
||||
foreach($aList[$sAlias] as $sAttCode)
|
||||
{
|
||||
if (is_null($aObjects[$sAlias]))
|
||||
{
|
||||
$aRow[$sAttCode.'_'.$sAlias] = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$aRow[$sAttCode.'_'.$sAlias] = $aObjects[$sAlias]->GetAsHTML($sAttCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
$aValues[] = $aRow;
|
||||
$iMaxObjects--;
|
||||
}
|
||||
$sHtml .= '<table class="listContainer">';
|
||||
$sColspan = '';
|
||||
if ($bDisplayMenu)
|
||||
{
|
||||
$oMenuBlock = new MenuBlock($oSet->GetFilter());
|
||||
$sColspan = 'colspan="2"';
|
||||
$aMenuExtraParams = $aExtraParams;
|
||||
if (!empty($sLinkageAttribute))
|
||||
{
|
||||
$aMenuExtraParams = $aExtraParams;
|
||||
}
|
||||
if ($bDisplayLimit && ($oSet->Count() > MetaModel::GetConfig()->GetMaxDisplayLimit()))
|
||||
{
|
||||
// list truncated
|
||||
$divId = $aExtraParams['block_id'];
|
||||
$sFilter = $oSet->GetFilter()->serialize();
|
||||
$aExtraParams['display_limit'] = false; // To expand the full list
|
||||
$sExtraParams = addslashes(str_replace('"', "'", json_encode($aExtraParams))); // JSON encode, change the style of the quotes and escape them
|
||||
$sHtml .= '<tr class="containerHeader"><td>'.Dict::Format('UI:TruncatedResults', MetaModel::GetConfig()->GetMinDisplayLimit(), $oSet->Count()).' <span style=\"cursor:pointer;\" onClick="Javascript:ReloadTruncatedList(\''.$divId.'\', \''.$sFilter.'\', \''.$sExtraParams.'\');">'.Dict::S('UI:DisplayAll').'</span></td><td>';
|
||||
$oPage->add_ready_script("$('#{$divId} table.listResults').addClass('truncated');");
|
||||
$oPage->add_ready_script("$('#{$divId} table.listResults tr:last td').addClass('truncated');");
|
||||
}
|
||||
else
|
||||
{
|
||||
// Full list
|
||||
$sHtml .= '<tr class="containerHeader"><td> '.Dict::Format('UI:CountOfResults', $oSet->Count()).'</td><td>';
|
||||
}
|
||||
$sHtml .= $oMenuBlock->GetRenderContent($oPage, $aMenuExtraParams, $aMenuExtraParams['currentId']);
|
||||
$sHtml .= '</td></tr>';
|
||||
}
|
||||
$sHtml .= "<tr><td $sColspan>";
|
||||
$sHtml .= $oPage->GetTable($aAttribs, $aValues);
|
||||
$sHtml .= '</td></tr>';
|
||||
$sHtml .= '</table>';
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
static function DisplaySetAsCSV(WebPage $oPage, CMDBObjectSet $oSet, $aParams = array())
|
||||
@@ -1112,7 +1354,6 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
{
|
||||
$oObj = $aObjects[$sAlias];
|
||||
foreach($aList[$sAlias] as $sAttCode => $oAttDef)
|
||||
|
||||
{
|
||||
if (is_null($oObj))
|
||||
{
|
||||
@@ -1187,11 +1428,8 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
{
|
||||
if ($oAttDef->IsWritable())
|
||||
{
|
||||
if (!$oAttDef->IsLinkSet())
|
||||
{
|
||||
$sValue = $oObj->GetAsXML($sAttCode);
|
||||
$oPage->add("<$sAttCode>$sValue</$sAttCode>\n");
|
||||
}
|
||||
$sValue = $oObj->GetAsXML($sAttCode);
|
||||
$oPage->add("<$sAttCode>$sValue</$sAttCode>\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1368,12 +1606,6 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
}
|
||||
$sHtml .= "</p>\n";
|
||||
$sHtml .= "<p align=\"right\"><input type=\"submit\" value=\"".Dict::S('UI:Button:Search')."\"></p>\n";
|
||||
if (isset($aExtraParams['table_id']))
|
||||
{
|
||||
// Rename to avoid collisions...
|
||||
$aExtraParams['_table_id_'] = $aExtraParams['table_id'];
|
||||
unset($aExtraParams['table_id']);
|
||||
}
|
||||
foreach($aExtraParams as $sName => $sValue)
|
||||
{
|
||||
$sHtml .= "<input type=\"hidden\" name=\"$sName\" value=\"$sValue\" />\n";
|
||||
@@ -1424,10 +1656,6 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
$sFieldPrefix = '';
|
||||
$sFormPrefix = isset($aArgs['formPrefix']) ? $aArgs['formPrefix'] : '';
|
||||
$sFieldPrefix = isset($aArgs['prefix']) ? $sFormPrefix.$aArgs['prefix'] : $sFormPrefix;
|
||||
if ($sDisplayValue == '')
|
||||
{
|
||||
$sDisplayValue = $value;
|
||||
}
|
||||
|
||||
if (isset($aArgs[$sAttCode]) && empty($value))
|
||||
{
|
||||
@@ -1460,14 +1688,14 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
$aEventsList[] ='validate';
|
||||
$aEventsList[] ='keyup';
|
||||
$aEventsList[] ='change';
|
||||
$sHTMLValue = "<input title=\"$sHelpText\" class=\"date-pick\" type=\"text\" size=\"12\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" value=\"".htmlentities($sDisplayValue, ENT_QUOTES, 'UTF-8')."\" id=\"$iId\"/> {$sValidationField}";
|
||||
$sHTMLValue = "<input title=\"$sHelpText\" class=\"date-pick\" type=\"text\" size=\"12\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" value=\"".htmlentities($value, ENT_QUOTES, 'UTF-8')."\" id=\"$iId\"/> {$sValidationField}";
|
||||
break;
|
||||
|
||||
case 'DateTime':
|
||||
$aEventsList[] ='validate';
|
||||
$aEventsList[] ='keyup';
|
||||
$aEventsList[] ='change';
|
||||
$sHTMLValue = "<input title=\"$sHelpText\" class=\"datetime-pick\" type=\"text\" size=\"20\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" value=\"".htmlentities($sDisplayValue, ENT_QUOTES, 'UTF-8')."\" id=\"$iId\"/> {$sValidationField}";
|
||||
$sHTMLValue = "<input title=\"$sHelpText\" class=\"datetime-pick\" type=\"text\" size=\"20\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" value=\"".htmlentities($value, ENT_QUOTES, 'UTF-8')."\" id=\"$iId\"/> {$sValidationField}";
|
||||
break;
|
||||
|
||||
case 'Duration':
|
||||
@@ -1503,7 +1731,6 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
$aStyles = array();
|
||||
$sStyle = '';
|
||||
$sWidth = $oAttDef->GetWidth('width', '');
|
||||
|
||||
if (!empty($sWidth))
|
||||
{
|
||||
$aStyles[] = 'width:'.$sWidth;
|
||||
@@ -1553,7 +1780,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
}
|
||||
$sHeader = '<div class="caselog_input_header"> '.Dict::S('UI:CaseLogTypeYourTextHere').'</div>';
|
||||
$sEditValue = $oAttDef->GetEditValue($value);
|
||||
$sPreviousLog = is_object($value) ? $value->GetAsHTML($oPage, true /* bEditMode */, array('AttributeText', 'RenderWikiHtml')) : '';
|
||||
$sPreviousLog = is_object($value) ? $value->GetAsHTML() : '';
|
||||
$iEntriesCount = is_object($value) ? count($value->GetIndex()) : 0;
|
||||
$sHidden = "<input type=\"hidden\" id=\"{$iId}_count\" value=\"$iEntriesCount\"/>"; // To know how many entries the case log already contains
|
||||
$sHTMLValue = "<div class=\"caselog\" $sStyle><table style=\"width:100%;\"><tr><td>$sHeader<textarea style=\"border:0;width:100%\" title=\"$sHelpText\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" rows=\"8\" cols=\"40\" id=\"$iId\">".htmlentities($sEditValue, ENT_QUOTES, 'UTF-8')."</textarea>$sPreviousLog</td><td>{$sValidationField}</td></tr></table>$sHidden</div>";
|
||||
@@ -1589,10 +1816,6 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
$sHTMLValue .= "<input title=\"$sHelpText\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}[fcontents]\" type=\"file\" id=\"file_$iId\" onChange=\"UpdateFileName('$iId', this.value)\"/> {$sValidationField}\n";
|
||||
break;
|
||||
|
||||
case 'StopWatch':
|
||||
$sHTMLValue = "The edition of a stopwatch is not allowed!!!";
|
||||
break;
|
||||
|
||||
case 'List':
|
||||
// Not editable for now...
|
||||
$sHTMLValue = '';
|
||||
@@ -1662,7 +1885,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHTMLValue = "<input title=\"$sHelpText\" type=\"text\" size=\"30\" maxlength=\"$iFieldSize\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" value=\"".htmlentities($sDisplayValue, ENT_QUOTES, 'UTF-8')."\" id=\"$iId\"/> {$sValidationField}";
|
||||
$sHTMLValue = "<input title=\"$sHelpText\" type=\"text\" size=\"30\" maxlength=\"$iFieldSize\" name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" value=\"".htmlentities($value, ENT_QUOTES, 'UTF-8')."\" id=\"$iId\"/> {$sValidationField}";
|
||||
$aEventsList[] ='keyup';
|
||||
$aEventsList[] ='change';
|
||||
}
|
||||
|
||||
@@ -1,699 +0,0 @@
|
||||
<?php
|
||||
// Copyright (C) 2012 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
require_once(APPROOT.'application/dashboardlayout.class.inc.php');
|
||||
require_once(APPROOT.'application/dashlet.class.inc.php');
|
||||
|
||||
/**
|
||||
* A user editable dashboard page
|
||||
*
|
||||
*/
|
||||
abstract class Dashboard
|
||||
{
|
||||
protected $sTitle;
|
||||
protected $sLayoutClass;
|
||||
protected $aWidgetsData;
|
||||
protected $oDOMNode;
|
||||
protected $sId;
|
||||
protected $aCells;
|
||||
|
||||
public function __construct($sId)
|
||||
{
|
||||
$this->sLayoutClass = null;
|
||||
$this->aCells = array();
|
||||
$this->oDOMNode = null;
|
||||
$this->sId = $sId;
|
||||
}
|
||||
|
||||
public function FromXml($sXml)
|
||||
{
|
||||
$this->aCells = array(); // reset the content of the dashboard
|
||||
set_error_handler(array('Dashboard', 'ErrorHandler'));
|
||||
$oDoc = new DOMDocument();
|
||||
$oDoc->loadXML($sXml);
|
||||
restore_error_handler();
|
||||
$this->oDOMNode = $oDoc->getElementsByTagName('dashboard')->item(0);
|
||||
|
||||
$oLayoutNode = $this->oDOMNode->getElementsByTagName('layout')->item(0);
|
||||
$this->sLayoutClass = $oLayoutNode->textContent;
|
||||
|
||||
$oTitleNode = $this->oDOMNode->getElementsByTagName('title')->item(0);
|
||||
$this->sTitle = $oTitleNode->textContent;
|
||||
|
||||
$oCellsNode = $this->oDOMNode->getElementsByTagName('cells')->item(0);
|
||||
$oCellsList = $oCellsNode->getElementsByTagName('cell');
|
||||
foreach($oCellsList as $oCellNode)
|
||||
{
|
||||
$aDashletList = array();
|
||||
$oDashletList = $oCellNode->getElementsByTagName('dashlet');
|
||||
foreach($oDashletList as $oDomNode)
|
||||
{
|
||||
$sDashletClass = $oDomNode->getAttribute('xsi:type');
|
||||
$sId = $oDomNode->getAttribute('id');
|
||||
$oNewDashlet = new $sDashletClass($sId);
|
||||
$oNewDashlet->FromDOMNode($oDomNode);
|
||||
$aDashletList[] = $oNewDashlet;
|
||||
}
|
||||
$this->aCells[] = $aDashletList;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Error handler to turn XML loading warnings into exceptions
|
||||
*/
|
||||
public static function ErrorHandler($errno, $errstr, $errfile, $errline)
|
||||
{
|
||||
if ($errno == E_WARNING && (substr_count($errstr,"DOMDocument::loadXML()")>0))
|
||||
{
|
||||
throw new DOMException($errstr);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function ToXml()
|
||||
{
|
||||
$oDoc = new DOMDocument();
|
||||
$oDoc->formatOutput = true; // indent (must be loaded with option LIBXML_NOBLANKS)
|
||||
$oDoc->preserveWhiteSpace = true; // otherwise the formatOutput option would have no effect
|
||||
|
||||
$oMainNode = $oDoc->createElement('dashboard');
|
||||
$oMainNode->setAttribute('xmlns:xsi', "http://www.w3.org/2001/XMLSchema-instance");
|
||||
$oDoc->appendChild($oMainNode);
|
||||
|
||||
$oNode = $oDoc->createElement('layout', $this->sLayoutClass);
|
||||
$oMainNode->appendChild($oNode);
|
||||
|
||||
$oNode = $oDoc->createElement('title', $this->sTitle);
|
||||
$oMainNode->appendChild($oNode);
|
||||
|
||||
$oCellsNode = $oDoc->createElement('cells');
|
||||
$oMainNode->appendChild($oCellsNode);
|
||||
|
||||
foreach ($this->aCells as $aCell)
|
||||
{
|
||||
$oCellNode = $oDoc->createElement('cell');
|
||||
$oCellsNode->appendChild($oCellNode);
|
||||
foreach ($aCell as $oDashlet)
|
||||
{
|
||||
$oNode = $oDoc->createElement('dashlet');
|
||||
$oCellNode->appendChild($oNode);
|
||||
$oNode->setAttribute('id', $oDashlet->GetID());
|
||||
$oNode->setAttribute('xsi:type', get_class($oDashlet));
|
||||
$oDashlet->ToDOMNode($oNode);
|
||||
}
|
||||
}
|
||||
|
||||
$sXml = $oDoc->saveXML();
|
||||
return $sXml;
|
||||
}
|
||||
|
||||
public function FromParams($aParams)
|
||||
{
|
||||
$this->sLayoutClass = $aParams['layout_class'];
|
||||
$this->sTitle = $aParams['title'];
|
||||
|
||||
foreach($aParams['cells'] as $aCell)
|
||||
{
|
||||
$aCellDashlets = array();
|
||||
foreach($aCell as $aDashletParams)
|
||||
{
|
||||
$sDashletClass = $aDashletParams['dashlet_class'];
|
||||
$sId = $aDashletParams['dashlet_id'];
|
||||
$oNewDashlet = new $sDashletClass($sId);
|
||||
|
||||
$oForm = $oNewDashlet->GetForm();
|
||||
$oForm->SetParamsContainer($sId);
|
||||
$oForm->SetPrefix('');
|
||||
$aValues = $oForm->ReadParams();
|
||||
$oNewDashlet->FromParams($aValues);
|
||||
$aCellDashlets[] = $oNewDashlet;
|
||||
}
|
||||
$this->aCells[] = $aCellDashlets;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function Save()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function GetLayout()
|
||||
{
|
||||
return $this->sLayoutClass;
|
||||
}
|
||||
|
||||
public function SetLayout($sLayoutClass)
|
||||
{
|
||||
$this->sLayoutClass = $sLayoutClass;
|
||||
}
|
||||
|
||||
public function GetTitle()
|
||||
{
|
||||
return $this->sTitle;
|
||||
}
|
||||
|
||||
public function SetTitle($sTitle)
|
||||
{
|
||||
$this->sTitle = $sTitle;
|
||||
}
|
||||
|
||||
public function AddDashlet($oDashlet)
|
||||
{
|
||||
$sId = $this->GetNewDashletId();
|
||||
$oDashlet->SetId($sId);
|
||||
$this->aCells[] = array($oDashlet);
|
||||
}
|
||||
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
$oPage->add('<h1>'.Dict::S($this->sTitle).'</h1>');
|
||||
$oLayout = new $this->sLayoutClass;
|
||||
$oLayout->Render($oPage, $this->aCells, $bEditMode, $aExtraParams);
|
||||
if (!$bEditMode)
|
||||
{
|
||||
$oPage->add_linked_script('../js/dashlet.js');
|
||||
$oPage->add_linked_script('../js/dashboard.js');
|
||||
}
|
||||
}
|
||||
|
||||
public function RenderProperties($oPage)
|
||||
{
|
||||
// menu to pick a layout and edit other properties of the dashboard
|
||||
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:Properties').'</div>');
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
|
||||
$oPage->add('<div style="text-align:center">'.Dict::S('UI:DashboardEdit:Layout').'</div>');
|
||||
$oPage->add('<div id="select_layout" style="text-align:center">');
|
||||
foreach( get_declared_classes() as $sLayoutClass)
|
||||
{
|
||||
if (is_subclass_of($sLayoutClass, 'DashboardLayout'))
|
||||
{
|
||||
$oReflection = new ReflectionClass($sLayoutClass);
|
||||
if (!$oReflection->isAbstract())
|
||||
{
|
||||
$aCallSpec = array($sLayoutClass, 'GetInfo');
|
||||
$aInfo = call_user_func($aCallSpec);
|
||||
$sChecked = ($this->sLayoutClass == $sLayoutClass) ? 'checked' : '';
|
||||
$oPage->add('<input type="radio" name="layout_class" '.$sChecked.' value="'.$sLayoutClass.'" id="layout_'.$sLayoutClass.'"><label for="layout_'.$sLayoutClass.'"><img src="'.$sUrl.$aInfo['icon'].'" /></label>'); // title="" on either the img or the label does nothing !
|
||||
}
|
||||
}
|
||||
}
|
||||
$oPage->add('</div>');
|
||||
|
||||
$oForm = new DesignerForm();
|
||||
$oField = new DesignerLongTextField('dashboard_title', Dict::S('UI:DashboardEdit:DashboardTitle'), $this->sTitle);
|
||||
$oForm->AddField($oField);
|
||||
$this->SetFormParams($oForm);
|
||||
$oForm->RenderAsPropertySheet($oPage, false, ':itop-dashboard');
|
||||
|
||||
$oPage->add('</div>');
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('#select_layout').buttonset();
|
||||
$('#select_layout input').click( function() {
|
||||
var sLayoutClass = $(this).val();
|
||||
$(':itop-dashboard').dashboard('option', {layout_class: sLayoutClass});
|
||||
} );
|
||||
$('#row_attr_dashboard_title').property_field('option', {parent_selector: ':itop-dashboard', auto_apply: false, 'do_apply': function() {
|
||||
var sTitle = $('#attr_dashboard_title').val();
|
||||
$(':itop-dashboard').dashboard('option', {title: sTitle});
|
||||
return true;
|
||||
}
|
||||
});
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
public function RenderDashletsSelection($oPage)
|
||||
{
|
||||
// Toolbox/palette to drag and drop dashlets
|
||||
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:Dashlets').'</div>');
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
|
||||
$oPage->add('<div id="select_dashlet" style="text-align:center">');
|
||||
foreach( get_declared_classes() as $sDashletClass)
|
||||
{
|
||||
if (is_subclass_of($sDashletClass, 'Dashlet'))
|
||||
{
|
||||
$oReflection = new ReflectionClass($sDashletClass);
|
||||
if (!$oReflection->isAbstract())
|
||||
{
|
||||
$aCallSpec = array($sDashletClass, 'IsVisible');
|
||||
$bVisible = call_user_func($aCallSpec);
|
||||
if ($bVisible)
|
||||
{
|
||||
$aCallSpec = array($sDashletClass, 'GetInfo');
|
||||
$aInfo = call_user_func($aCallSpec);
|
||||
$oPage->add('<span dashlet_class="'.$sDashletClass.'" class="dashlet_icon ui-widget-content ui-corner-all" id="dashlet_'.$sDashletClass.'" title="'.$aInfo['label'].'" style="width:34px; height:34px; display:inline-block; margin:2px;"><img src="'.$sUrl.$aInfo['icon'].'" /></span>');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$oPage->add('</div>');
|
||||
|
||||
$oPage->add('</div>');
|
||||
$oPage->add_ready_script("$('.dashlet_icon').draggable({helper: 'clone', appendTo: 'body', zIndex: 10000, revert:'invalid'});");
|
||||
$oPage->add_ready_script("$('.layout_cell').droppable({accept:'.dashlet_icon', hoverClass:'dragHover'});");
|
||||
}
|
||||
|
||||
public function RenderDashletsProperties($oPage)
|
||||
{
|
||||
// Toolbox/palette to edit the properties of each dashlet
|
||||
$oPage->add('<div class="ui-widget-content ui-corner-all"><div class="ui-widget-header ui-corner-all" style="text-align:center; padding: 2px;">'.Dict::S('UI:DashboardEdit:DashletProperties').'</div>');
|
||||
|
||||
$oPage->add('<div id="dashlet_properties" style="text-align:center">');
|
||||
foreach($this->aCells as $aCell)
|
||||
{
|
||||
foreach($aCell as $oDashlet)
|
||||
{
|
||||
$sId = $oDashlet->GetID();
|
||||
$sClass = get_class($oDashlet);
|
||||
if ($oDashlet->IsVisible())
|
||||
{
|
||||
$oPage->add('<div class="dashlet_properties" id="dashlet_properties_'.$sId.'" style="display:none">');
|
||||
$oForm = $oDashlet->GetForm();
|
||||
$this->SetFormParams($oForm);
|
||||
$oForm->RenderAsPropertySheet($oPage, false, ':itop-dashboard');
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
}
|
||||
}
|
||||
$oPage->add('</div>');
|
||||
|
||||
$oPage->add('</div>');
|
||||
}
|
||||
|
||||
protected function GetNewDashletId()
|
||||
{
|
||||
$iNewId = 0;
|
||||
foreach($this->aCells as $aDashlets)
|
||||
{
|
||||
foreach($aDashlets as $oDashlet)
|
||||
{
|
||||
$iNewId = max($iNewId, (int)$oDashlet->GetID());
|
||||
}
|
||||
}
|
||||
return $iNewId + 1;
|
||||
}
|
||||
|
||||
abstract protected function SetFormParams($oForm);
|
||||
}
|
||||
|
||||
class RuntimeDashboard extends Dashboard
|
||||
{
|
||||
protected $bCustomized;
|
||||
|
||||
public function __construct($sId)
|
||||
{
|
||||
parent::__construct($sId);
|
||||
$this->bCustomized = false;
|
||||
}
|
||||
|
||||
public function SetCustomFlag($bCustomized)
|
||||
{
|
||||
$this->bCustomized = $bCustomized;
|
||||
}
|
||||
|
||||
protected function SetFormParams($oForm)
|
||||
{
|
||||
$oForm->SetSubmitParams(utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php', array('operation' => 'update_dashlet_property'));
|
||||
}
|
||||
|
||||
public function Save()
|
||||
{
|
||||
$sXml = $this->ToXml();
|
||||
$oUDSearch = new DBObjectSearch('UserDashboard');
|
||||
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
|
||||
$oUDSearch->AddCondition('menu_code', $this->sId, '=');
|
||||
$oUDSet = new DBObjectSet($oUDSearch);
|
||||
if ($oUDSet->Count() > 0)
|
||||
{
|
||||
// Assuming there is at most one couple {user, menu}!
|
||||
$oUserDashboard = $oUDSet->Fetch();
|
||||
$oUserDashboard->Set('contents', $sXml);
|
||||
|
||||
$oUserDashboard->DBUpdate();
|
||||
}
|
||||
else
|
||||
{
|
||||
// No such customized dasboard for the current user, let's create a new record
|
||||
$oUserDashboard = new UserDashboard();
|
||||
$oUserDashboard->Set('user_id', UserRights::GetUserId());
|
||||
$oUserDashboard->Set('menu_code', $this->sId);
|
||||
$oUserDashboard->Set('contents', $sXml);
|
||||
|
||||
$oUserDashboard->DBInsert();
|
||||
}
|
||||
}
|
||||
|
||||
public function Revert()
|
||||
{
|
||||
$oUDSearch = new DBObjectSearch('UserDashboard');
|
||||
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
|
||||
$oUDSearch->AddCondition('menu_code', $this->sId, '=');
|
||||
$oUDSet = new DBObjectSet($oUDSearch);
|
||||
if ($oUDSet->Count() > 0)
|
||||
{
|
||||
// Assuming there is at most one couple {user, menu}!
|
||||
$oUserDashboard = $oUDSet->Fetch();
|
||||
$oUserDashboard->DBDelete();
|
||||
}
|
||||
}
|
||||
|
||||
public function Render($oPage, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
parent::Render($oPage, $bEditMode, $aExtraParams);
|
||||
if (!$bEditMode)
|
||||
{
|
||||
$sEditMenu = "<td><span id=\"DashboardMenu\"><ul><li><img src=\"../images/edit.png\"><ul>";
|
||||
|
||||
$aActions = array();
|
||||
$oEdit = new JSPopupMenuItem('UI:Dashboard:Edit', Dict::S('UI:Dashboard:Edit'), "return EditDashboard('{$this->sId}')");
|
||||
$aActions[$oEdit->GetUID()] = $oEdit->GetMenuItem();
|
||||
|
||||
if ($this->bCustomized)
|
||||
{
|
||||
$oRevert = new JSPopupMenuItem('UI:Dashboard:RevertConfirm', Dict::S('UI:Dashboard:Revert'),
|
||||
"if (confirm('".addslashes(Dict::S('UI:Dashboard:RevertConfirm'))."')) return RevertDashboard('{$this->sId}'); else return false");
|
||||
$aActions[$oRevert->GetUID()] = $oRevert->GetMenuItem();
|
||||
}
|
||||
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_DASHBOARD_ACTIONS, $this, $aActions);
|
||||
$sEditMenu .= $oPage->RenderPopupMenuItems($aActions);
|
||||
|
||||
|
||||
$sEditMenu = addslashes($sEditMenu);
|
||||
//$sEditBtn = addslashes('<div style="display: inline-block; height: 55px; width:200px;vertical-align:center;line-height:60px;text-align:left;"><button onclick="EditDashboard(\''.$this->sId.'\');">Edit This Page</button></div>');
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('#logOffBtn').parent().before('$sEditMenu');
|
||||
$('#DashboardMenu>ul').popupmenu();
|
||||
|
||||
EOF
|
||||
);
|
||||
$oPage->add_script(
|
||||
<<<EOF
|
||||
function EditDashboard(sId)
|
||||
{
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'dashboard_editor', id: sId},
|
||||
function(data)
|
||||
{
|
||||
$('body').append(data);
|
||||
}
|
||||
);
|
||||
return false;
|
||||
}
|
||||
function RevertDashboard(sId)
|
||||
{
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', {operation: 'revert_dashboard', dashboard_id: sId},
|
||||
function(data)
|
||||
{
|
||||
$('body').append(data);
|
||||
}
|
||||
);
|
||||
return false;
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function RenderEditor($oPage)
|
||||
{
|
||||
$oPage->add('<div id="dashboard_editor">');
|
||||
$oPage->add('<div class="ui-layout-center">');
|
||||
$this->Render($oPage, true);
|
||||
$oPage->add('</div>');
|
||||
$oPage->add('<div class="ui-layout-east">');
|
||||
$this->RenderProperties($oPage);
|
||||
$this->RenderDashletsSelection($oPage);
|
||||
$this->RenderDashletsProperties($oPage);
|
||||
$oPage->add('</div>');
|
||||
$oPage->add('<div id="event_bus"/>'); // For exchanging messages between the panes, same as in the designer
|
||||
$oPage->add('</div>');
|
||||
|
||||
$sDialogTitle = Dict::S('UI:DashboardEdit:Title');
|
||||
$sOkButtonLabel = Dict::S('UI:Button:Save');
|
||||
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
|
||||
|
||||
$sId = addslashes($this->sId);
|
||||
$sLayoutClass = addslashes($this->sLayoutClass);
|
||||
$sTitle = addslashes($this->sTitle);
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php';
|
||||
|
||||
$sExitConfirmationMessage = addslashes(Dict::S('UI:NavigateAwayConfirmationMessage'));
|
||||
$sCancelConfirmationMessage = addslashes(Dict::S('UI:CancelConfirmationMessage'));
|
||||
$sAutoApplyConfirmationMessage = addslashes(Dict::S('UI:AutoApplyConfirmationMessage'));
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
window.bLeavingOnUserAction = false;
|
||||
|
||||
$('#dashboard_editor').dialog({
|
||||
height: $('body').height() - 50,
|
||||
width: $('body').width() - 50,
|
||||
modal: true,
|
||||
title: '$sDialogTitle',
|
||||
buttons: [
|
||||
{ text: "$sOkButtonLabel", click: function() {
|
||||
var oDashboard = $(':itop-dashboard').data('dashboard');
|
||||
if (oDashboard.is_dirty())
|
||||
{
|
||||
if (!confirm('$sAutoApplyConfirmationMessage'))
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
oDashboard.apply_changes();
|
||||
}
|
||||
}
|
||||
window.bLeavingOnUserAction = true;
|
||||
oDashboard.save();
|
||||
} },
|
||||
{ text: "$sCancelButtonLabel", click: function() {
|
||||
var oDashboard = $(':itop-dashboard').data('dashboard');
|
||||
if (oDashboard.is_modified())
|
||||
{
|
||||
if (!confirm('$sCancelConfirmationMessage'))
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
window.bLeavingOnUserAction = true;
|
||||
$(this).dialog( "close" );
|
||||
$(this).remove();
|
||||
} },
|
||||
],
|
||||
close: function() { $(this).remove(); }
|
||||
});
|
||||
|
||||
$('#dashboard_editor .ui-layout-center').dashboard({
|
||||
dashboard_id: '$sId', layout_class: '$sLayoutClass', title: '$sTitle',
|
||||
submit_to: '$sUrl', submit_parameters: {operation: 'save_dashboard'},
|
||||
render_to: '$sUrl', render_parameters: {operation: 'render_dashboard'},
|
||||
new_dashlet_parameters: {operation: 'new_dashlet'}
|
||||
});
|
||||
|
||||
$('#select_dashlet').droppable({
|
||||
accept: '.dashlet',
|
||||
drop: function(event, ui) {
|
||||
$( this ).find( ".placeholder" ).remove();
|
||||
var oDashlet = ui.draggable;
|
||||
oDashlet.remove();
|
||||
},
|
||||
});
|
||||
|
||||
$('#event_bus').bind('dashlet-selected', function(event, data){
|
||||
var sDashletId = data.dashlet_id;
|
||||
var sPropId = 'dashlet_properties_'+sDashletId;
|
||||
$('.dashlet_properties').each(function() {
|
||||
var sId = $(this).attr('id');
|
||||
var bShow = (sId == sPropId);
|
||||
if (bShow)
|
||||
{
|
||||
$(this).show();
|
||||
}
|
||||
else
|
||||
{
|
||||
$(this).hide();
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
dashboard_prop_size = GetUserPreference('dashboard_prop_size', 350);
|
||||
$('#dashboard_editor').layout({
|
||||
east: {
|
||||
minSize: 200,
|
||||
size: dashboard_prop_size,
|
||||
togglerLength_open: 0,
|
||||
togglerLength_closed: 0,
|
||||
onresize_end: function(name, elt, state, options, layout)
|
||||
{
|
||||
if (state.isSliding == false)
|
||||
{
|
||||
SetUserPreference('dashboard_prop_size', state.size, true);
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
window.onbeforeunload = function() {
|
||||
if (!window.bLeavingOnUserAction)
|
||||
{
|
||||
var oDashboard = $(':itop-dashboard').data('dashboard');
|
||||
if (oDashboard)
|
||||
{
|
||||
if (oDashboard.is_dirty())
|
||||
{
|
||||
return '$sExitConfirmationMessage';
|
||||
}
|
||||
if (oDashboard.is_modified())
|
||||
{
|
||||
return '$sExitConfirmationMessage';
|
||||
}
|
||||
}
|
||||
}
|
||||
// return nothing ! safer for IE
|
||||
};
|
||||
EOF
|
||||
);
|
||||
$oPage->add_ready_script("");
|
||||
}
|
||||
|
||||
public static function GetDashletCreationForm($sOQL = null)
|
||||
{
|
||||
$oForm = new DesignerForm();
|
||||
|
||||
// Get the list of all 'dashboard' menus in which we can insert a dashlet
|
||||
$aAllMenus = ApplicationMenu::ReflectionMenuNodes();
|
||||
$aAllowedDashboards = array();
|
||||
foreach($aAllMenus as $idx => $aMenu)
|
||||
{
|
||||
$oMenu = $aMenu['node'];
|
||||
$sParentId = $aMenu['parent'];
|
||||
if ($oMenu instanceof DashboardMenuNode)
|
||||
{
|
||||
$sMenuLabel = $oMenu->GetTitle();
|
||||
$sParentLabel = Dict::S('Menu:'.$sParentId);
|
||||
if ($sParentLabel != $sMenuLabel)
|
||||
{
|
||||
$aAllowedDashboards[$oMenu->GetMenuId()] = $sParentLabel.' - '.$sMenuLabel;
|
||||
}
|
||||
else
|
||||
{
|
||||
$aAllowedDashboards[$oMenu->GetMenuId()] = $sMenuLabel;
|
||||
}
|
||||
}
|
||||
}
|
||||
asort($aAllowedDashboards);
|
||||
|
||||
$aKeys = array_keys($aAllowedDashboards); // Select the first one by default
|
||||
$sDefaultDashboard = $aKeys[0];
|
||||
$oField = new DesignerComboField('menu_id', Dict::S('UI:DashletCreation:Dashboard'), $sDefaultDashboard);
|
||||
$oField->SetAllowedValues($aAllowedDashboards);
|
||||
$oField->SetMandatory(true);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
// Get the list of possible dashlets that support a creation from
|
||||
// an OQL
|
||||
$aDashlets = array();
|
||||
foreach(get_declared_classes() as $sDashletClass)
|
||||
{
|
||||
if (is_subclass_of($sDashletClass, 'Dashlet'))
|
||||
{
|
||||
$oReflection = new ReflectionClass($sDashletClass);
|
||||
if (!$oReflection->isAbstract())
|
||||
{
|
||||
$aCallSpec = array($sDashletClass, 'CanCreateFromOQL');
|
||||
$bShorcutMode = call_user_func($aCallSpec);
|
||||
if ($bShorcutMode)
|
||||
{
|
||||
$aCallSpec = array($sDashletClass, 'GetInfo');
|
||||
$aInfo = call_user_func($aCallSpec);
|
||||
$aDashlets[$sDashletClass] = array('label' => $aInfo['label'], 'class' => $sDashletClass, 'icon' => $aInfo['icon']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$oSelectorField = new DesignerFormSelectorField('dashlet_class', Dict::S('UI:DashletCreation:DashletType'), '');
|
||||
$oForm->AddField($oSelectorField);
|
||||
foreach($aDashlets as $sDashletClass => $aDashletInfo)
|
||||
{
|
||||
$oSubForm = new DesignerForm();
|
||||
$oDashlet = new $sDashletClass(0);
|
||||
$oDashlet->GetPropertiesFieldsFromOQL($oSubForm, $sOQL);
|
||||
|
||||
$oSelectorField->AddSubForm($oSubForm, $aDashletInfo['label'], $aDashletInfo['class']);
|
||||
}
|
||||
$oField = new DesignerBooleanField('open_editor', Dict::S('UI:DashletCreation:EditNow'), true);
|
||||
$oForm->AddField($oField);
|
||||
|
||||
return $oForm;
|
||||
}
|
||||
|
||||
public static function GetDashletCreationDlgFromOQL($oPage, $sOQL)
|
||||
{
|
||||
$oPage->add('<div id="dashlet_creation_dlg">');
|
||||
|
||||
$oForm = self::GetDashletCreationForm($sOQL);
|
||||
|
||||
$oForm->Render($oPage);
|
||||
$oPage->add('</div>');
|
||||
|
||||
$sDialogTitle = Dict::S('UI:DashletCreation:Title');
|
||||
$sOkButtonLabel = Dict::S('UI:Button:Ok');
|
||||
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('#dashlet_creation_dlg').dialog({
|
||||
width: 400,
|
||||
modal: true,
|
||||
title: '$sDialogTitle',
|
||||
buttons: [
|
||||
{ text: "$sOkButtonLabel", click: function() {
|
||||
var oForm = $(this).find('form');
|
||||
var sFormId = oForm.attr('id');
|
||||
var oParams = null;
|
||||
var aErrors = ValidateForm(sFormId, false);
|
||||
if (aErrors.length == 0)
|
||||
{
|
||||
oParams = ReadFormParams(sFormId);
|
||||
}
|
||||
oParams.operation = 'add_dashlet';
|
||||
var me = $(this);
|
||||
$.post(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php', oParams, function(data) {
|
||||
me.dialog( "close" );
|
||||
me.remove();
|
||||
$('body').append(data);
|
||||
});
|
||||
} },
|
||||
{ text: "$sCancelButtonLabel", click: function() {
|
||||
$(this).dialog( "close" ); $(this).remove();
|
||||
} },
|
||||
],
|
||||
close: function() { $(this).remove(); }
|
||||
});
|
||||
EOF
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,185 +0,0 @@
|
||||
<?php
|
||||
abstract class DashboardLayout
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
abstract public function Render($oPage, $aDashlets, $bEditMode = false);
|
||||
|
||||
static public function GetInfo()
|
||||
{
|
||||
return array(
|
||||
'label' => '',
|
||||
'icon' => '',
|
||||
'description' => '',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class DashboardLayoutMultiCol extends DashboardLayout
|
||||
{
|
||||
protected $iNbCols;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->iNbCols = 1;
|
||||
}
|
||||
|
||||
protected function TrimCell($aDashlets)
|
||||
{
|
||||
$aKeys = array_reverse(array_keys($aDashlets));
|
||||
$idx = 0;
|
||||
$bNoVisibleFound = true;
|
||||
while($idx < count($aKeys) && $bNoVisibleFound)
|
||||
{
|
||||
$oDashlet = $aDashlets[$aKeys[$idx]];
|
||||
if ($oDashlet->IsVisible())
|
||||
{
|
||||
$bNoVisibleFound = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($aDashlets[$aKeys[$idx]]);
|
||||
}
|
||||
$idx++;
|
||||
}
|
||||
return $aDashlets;
|
||||
}
|
||||
|
||||
protected function TrimCellsArray($aCells)
|
||||
{
|
||||
foreach($aCells as $key => $aDashlets)
|
||||
{
|
||||
$aCells[$key] = $this->TrimCell($aDashlets);
|
||||
}
|
||||
$aKeys = array_reverse(array_keys($aCells));
|
||||
$idx = 0;
|
||||
$bNoVisibleFound = true;
|
||||
while($idx < count($aKeys) && $bNoVisibleFound)
|
||||
{
|
||||
$aDashlets = $aCells[$aKeys[$idx]];
|
||||
if (count($aDashlets) > 0)
|
||||
{
|
||||
$bNoVisibleFound = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($aCells[$aKeys[$idx]]);
|
||||
}
|
||||
$idx++;
|
||||
}
|
||||
return $aCells;
|
||||
|
||||
}
|
||||
|
||||
public function Render($oPage, $aCells, $bEditMode = false, $aExtraParams = array())
|
||||
{
|
||||
// Trim the list of cells to remove the invisible/empty ones at the end of the array
|
||||
$aCells = $this->TrimCellsArray($aCells);
|
||||
|
||||
$oPage->add('<table style="width:100%"><tbody>');
|
||||
$iCellIdx = 0;
|
||||
$fColSize = 100 / $this->iNbCols;
|
||||
$sStyle = $bEditMode ? 'style="border: 1px #ccc dashed; width:'.$fColSize.'%;" class="layout_cell edit_mode"' : 'style="width: '.$fColSize.'%;" class="dashboard"';
|
||||
$iNbRows = ceil(count($aCells) / $this->iNbCols);
|
||||
for($iRows = 0; $iRows < $iNbRows; $iRows++)
|
||||
{
|
||||
$oPage->add('<tr>');
|
||||
for($iCols = 0; $iCols < $this->iNbCols; $iCols++)
|
||||
{
|
||||
$oPage->add("<td $sStyle>");
|
||||
if (array_key_exists($iCellIdx, $aCells))
|
||||
{
|
||||
$aDashlets = $aCells[$iCellIdx];
|
||||
if (count($aDashlets) > 0)
|
||||
{
|
||||
foreach($aDashlets as $oDashlet)
|
||||
{
|
||||
if ($oDashlet->IsVisible())
|
||||
{
|
||||
$oDashlet->DoRender($oPage, $bEditMode, true /* bEnclosingDiv */, $aExtraParams);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$oPage->add(' ');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$oPage->add(' ');
|
||||
}
|
||||
$oPage->add('</td>');
|
||||
$iCellIdx++;
|
||||
}
|
||||
$oPage->add('</tr>');
|
||||
}
|
||||
if ($bEditMode) // Add one row for extensibility
|
||||
{
|
||||
$sStyle = 'style="border: 1px #ccc dashed; width:'.$fColSize.'%;" class="layout_cell edit_mode layout_extension"';
|
||||
$oPage->add('<tr>');
|
||||
for($iCols = 0; $iCols < $this->iNbCols; $iCols++)
|
||||
{
|
||||
$oPage->add("<td $sStyle>");
|
||||
$oPage->add(' ');
|
||||
$oPage->add('</td>');
|
||||
}
|
||||
$oPage->add('</tr>');
|
||||
}
|
||||
$oPage->add('</tbody></table>');
|
||||
}
|
||||
}
|
||||
|
||||
class DashboardLayoutOneCol extends DashboardLayoutMultiCol
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->iNbCols = 1;
|
||||
}
|
||||
static public function GetInfo()
|
||||
{
|
||||
return array(
|
||||
'label' => 'One Column',
|
||||
'icon' => 'images/layout_1col.png',
|
||||
'description' => '',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DashboardLayoutTwoCols extends DashboardLayoutMultiCol
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->iNbCols = 2;
|
||||
}
|
||||
static public function GetInfo()
|
||||
{
|
||||
return array(
|
||||
'label' => 'Two Columns',
|
||||
'icon' => 'images/layout_2col.png',
|
||||
'description' => '',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class DashboardLayoutThreeCols extends DashboardLayoutMultiCol
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
$this->iNbCols = 3;
|
||||
}
|
||||
static public function GetInfo()
|
||||
{
|
||||
return array(
|
||||
'label' => 'Two Columns',
|
||||
'icon' => 'images/layout_3col.png',
|
||||
'description' => '',
|
||||
);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,833 +0,0 @@
|
||||
<?php
|
||||
// Copyright (C) 2012 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
/**
|
||||
* Data Table to display a set of objects in a tabular manner in HTML
|
||||
*
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html GPL
|
||||
*/
|
||||
|
||||
class DataTable
|
||||
{
|
||||
protected $iListId; // Unique ID inside the web page
|
||||
protected $sTableId; // identifier for saving the settings (combined with the class aliases)
|
||||
protected $oSet; // The set of objects to display
|
||||
protected $aClassAliases; // The aliases (alias => class) inside the set
|
||||
protected $iNbObjects; // Total number of objects inthe set
|
||||
protected $bUseCustomSettings; // Whether or not the current display uses custom settings
|
||||
protected $oDefaultSettings; // the default settings for displaying such a list
|
||||
|
||||
/**
|
||||
* @param $iListId mixed Unique ID for this div/table in the page
|
||||
* @param $oSet DBObjectSet The set of data to display
|
||||
* @param $aClassAliases Hash The list of classes/aliases to be displayed in this set $sAlias => $sClassName
|
||||
* @param $sTableId mixed A string (or null) identifying this table in order to persist its settings
|
||||
*/
|
||||
public function __construct($iListId, $oSet, $aClassAliases, $sTableId = null)
|
||||
{
|
||||
$this->iListId = $iListId;
|
||||
$this->oSet = $oSet;
|
||||
$this->aClassAliases = $aClassAliases;
|
||||
$this->sTableId = $sTableId;
|
||||
$this->iNbObjects = $oSet->Count();
|
||||
$this->bUseCustomSettings = false;
|
||||
$this->oDefaultSettings = null;
|
||||
}
|
||||
|
||||
public function Display(WebPage $oPage, DataTableSettings $oSettings, $bActionsMenu, $sSelectMode, $bViewLink, $aExtraParams)
|
||||
{
|
||||
$this->oDefaultSettings = $oSettings;
|
||||
|
||||
// Identified tables can have their own specific settings
|
||||
$oCustomSettings = DataTableSettings::GetTableSettings($this->aClassAliases, $this->sTableId);
|
||||
|
||||
if ($oCustomSettings != null)
|
||||
{
|
||||
// Custom settings overload the default ones
|
||||
$this->bUseCustomSettings = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
$oCustomSettings = $oSettings;
|
||||
}
|
||||
|
||||
if ($oCustomSettings->iDefaultPageSize > 0)
|
||||
{
|
||||
$this->oSet->SetLimit($oCustomSettings->iDefaultPageSize);
|
||||
}
|
||||
$this->oSet->SetOrderBy($oCustomSettings->GetSortOrder());
|
||||
|
||||
$bToolkitMenu = true;
|
||||
if (UserRights::IsPortalUser())
|
||||
{
|
||||
// Portal users have a limited access to data, for now they can only see what's configured for them
|
||||
$bToolkitMenu = false;
|
||||
}
|
||||
|
||||
return $this->GetAsHTML($oPage, $oCustomSettings->iDefaultPageSize, $oCustomSettings->iDefaultPageSize, 0, $oCustomSettings->aColumns, $bActionsMenu, $bToolkitMenu, $sSelectMode, $bViewLink, $aExtraParams);
|
||||
}
|
||||
|
||||
public function GetAsHTML(WebPage $oPage, $iPageSize, $iDefaultPageSize, $iPageIndex, $aColumns, $bActionsMenu, $bToolkitMenu, $sSelectMode, $bViewLink, $aExtraParams)
|
||||
{
|
||||
$sObjectsCount = $this->GetObjectCount($oPage, $sSelectMode);
|
||||
$sPager = $this->GetPager($oPage, $iPageSize, $iDefaultPageSize, $iPageIndex);
|
||||
$sActionsMenu = '';
|
||||
$sToolkitMenu = '';
|
||||
if ($bActionsMenu)
|
||||
{
|
||||
$sActionsMenu = $this->GetActionsMenu($oPage, $aExtraParams);
|
||||
}
|
||||
if ($bToolkitMenu)
|
||||
{
|
||||
$sToolkitMenu = $this->GetToolkitMenu($oPage, $aExtraParams);
|
||||
}
|
||||
$sDataTable = $this->GetHTMLTable($oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
|
||||
$sConfigDlg = $this->GetTableConfigDlg($oPage, $aColumns, $bViewLink, $iDefaultPageSize);
|
||||
|
||||
$sHtml = "<table id=\"datatable_{$this->iListId}\" class=\"datatable\">";
|
||||
$sHtml .= "<tr><td>";
|
||||
$sHtml .= "<table style=\"width:100%;\">";
|
||||
$sHtml .= "<tr><td class=\"pagination_container\">$sObjectsCount</td><td class=\"menucontainer\">$sToolkitMenu $sActionsMenu</td></tr>";
|
||||
$sHtml .= "<tr>$sPager</tr>";
|
||||
$sHtml .= "</table>";
|
||||
$sHtml .= "</td></tr>";
|
||||
$sHtml .= "<tr><td class=\"datacontents\">$sDataTable</td></tr>";
|
||||
$sHtml .= "</table>\n";
|
||||
$oPage->add_at_the_end($sConfigDlg);
|
||||
|
||||
$aOptions = array(
|
||||
'sPersistentId' => '',
|
||||
'sFilter' => $this->oSet->GetFilter()->serialize(),
|
||||
'oColumns' => $aColumns,
|
||||
'sSelectMode' => $sSelectMode,
|
||||
'sViewLink' => ($bViewLink ? 'true' : 'false'),
|
||||
'iNbObjects' => $this->iNbObjects,
|
||||
'iDefaultPageSize' => $iDefaultPageSize,
|
||||
'iPageSize' => $iPageSize,
|
||||
'iPageIndex' => $iPageIndex,
|
||||
'oClassAliases' => $this->aClassAliases,
|
||||
'sTableId' => $this->sTableId,
|
||||
'oExtraParams' => $aExtraParams,
|
||||
'sRenderUrl' => utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php',
|
||||
'oRenderParameters' => array('str' => ''), // Forces JSON to encode this as a object...
|
||||
'oDefaultSettings' => array('str' => ''), // Forces JSON to encode this as a object...
|
||||
'oLabels' => array('moveup' => Dict::S('UI:Button:MoveUp'), 'movedown' => Dict::S('UI:Button:MoveDown')),
|
||||
);
|
||||
if($this->oDefaultSettings != null)
|
||||
{
|
||||
$aOptions['oDefaultSettings'] = $this->GetAsHash($this->oDefaultSettings);
|
||||
}
|
||||
$sJSOptions = json_encode($aOptions);
|
||||
$oPage->add_ready_script("$('#datatable_{$this->iListId}').datatable($sJSOptions);");
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
/**
|
||||
* When refreshing the body of a paginated table, get the rows of the table (inside the TBODY)
|
||||
* return string The HTML rows to insert inside the <tbody> node
|
||||
*/
|
||||
public function GetAsHTMLTableRows(WebPage $oPage, $iPageSize, $aColumns, $sSelectMode, $bViewLink, $aExtraParams)
|
||||
{
|
||||
$aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink);
|
||||
$aValues = $this->GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
|
||||
|
||||
$sHtml = '';
|
||||
foreach($aValues as $aRow)
|
||||
{
|
||||
$sHtml .= $oPage->GetTableRow($aRow, $aAttribs);
|
||||
}
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
protected function GetObjectCount(WebPage $oPage, $sSelectMode)
|
||||
{
|
||||
if (($sSelectMode == 'single') || ($sSelectMode == 'multiple'))
|
||||
{
|
||||
$sHtml = '<div class="pagination_objcount">'.Dict::Format('UI:Pagination:HeaderSelection', '<span id="total">'.$this->iNbObjects.'</span>', '<span class="selectedCount">0</span>').'</div>';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHtml = '<div class="pagination_objcount">'.Dict::Format('UI:Pagination:HeaderNoSelection', '<span id="total">'.$this->iNbObjects.'</span>').'</div>';
|
||||
}
|
||||
return $sHtml;
|
||||
}
|
||||
protected function GetPager(WebPage $oPage, $iPageSize, $iDefaultPageSize, $iPageIndex)
|
||||
{
|
||||
$sHtml = '';
|
||||
if ($iPageSize < 1) // Display all
|
||||
{
|
||||
$sPagerStyle = 'style="display:none"'; // no limit: display the full table, so hide the "pager" UI
|
||||
}
|
||||
else
|
||||
{
|
||||
$sPagerStyle = '';
|
||||
}
|
||||
|
||||
$sCombo = '<select class="pagesize">';
|
||||
for($iPage = 1; $iPage < 5; $iPage++)
|
||||
{
|
||||
$iNbItems = $iPage * $iDefaultPageSize;
|
||||
$sSelected = ($iNbItems == $iPageSize) ? 'selected="selected"' : '';
|
||||
$sCombo .= "<option $sSelected value=\"$iNbItems\">$iNbItems</option>";
|
||||
}
|
||||
$sSelected = ($iPageSize < 1) ? 'selected="selected"' : '';
|
||||
$sCombo .= "<option $sSelected value=\"-1\">".Dict::S('UI:Pagination:All')."</option>";
|
||||
$sCombo .= '</select>';
|
||||
|
||||
$sPages = Dict::S('UI:Pagination:PagesLabel');
|
||||
$sPageSizeCombo = Dict::Format('UI:Pagination:PageSize', $sCombo);
|
||||
|
||||
$iNbPages = ($iPageSize < 1) ? 1 : ceil($this->iNbObjects / $iPageSize);
|
||||
if ($iNbPages == 1)
|
||||
{
|
||||
// No need to display the pager
|
||||
$sPagerStyle = 'style="display:none"';
|
||||
}
|
||||
$aPagesToDisplay = array();
|
||||
for($idx = 0; $idx <= min(4, $iNbPages-1); $idx++)
|
||||
{
|
||||
if ($idx == 0)
|
||||
{
|
||||
$aPagesToDisplay[$idx] = '<span page="0" class="curr_page">1</span>';
|
||||
}
|
||||
else
|
||||
{
|
||||
$aPagesToDisplay[$idx] = "<span id=\"gotopage_$idx\" class=\"gotopage\" page=\"$idx\">".(1+$idx)."</span>";
|
||||
}
|
||||
}
|
||||
$iLastPageIdx = $iNbPages - 1;
|
||||
if (!isset($aPagesToDisplay[$iLastPageIdx]))
|
||||
{
|
||||
unset($aPagesToDisplay[$idx - 1]); // remove the last page added to make room for the very last page
|
||||
$aPagesToDisplay[$iLastPageIdx] = "<span id=\"gotopage_$iLastPageIdx\" class=\"gotopage\" page=\"$iLastPageIdx\">... $iNbPages</span>";
|
||||
}
|
||||
$sPagesLinks = implode('', $aPagesToDisplay);
|
||||
$sPagesList = '['.implode(',', array_keys($aPagesToDisplay)).']';
|
||||
|
||||
$sSelectionMode = ($iNbPages == 1) ? '' : 'positive';
|
||||
$sHtml =
|
||||
<<<EOF
|
||||
<td $sPagerStyle colspan="2">
|
||||
<table id="pager{$this->iListId}" class="pager"><tr>
|
||||
<td>$sPages</td>
|
||||
<td><img src="../images/first.png" class="first"/></td>
|
||||
<td><img src="../images/prev.png" class="prev"/></td>
|
||||
<td><span id="index">$sPagesLinks</span></td>
|
||||
<td><img src="../images/next.png" class="next"/></td>
|
||||
<td><img src="../images/last.png" class="last"/></td>
|
||||
<td>$sPageSizeCombo</td>
|
||||
<td><span id="loading"> </span><input type="hidden" name="selectionMode" value="$sSelectionMode"></input>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
EOF;
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
protected function GetActionsMenu(WebPage $oPage, $aExtraParams)
|
||||
{
|
||||
$oMenuBlock = new MenuBlock($this->oSet->GetFilter(), 'list');
|
||||
|
||||
$sHtml = $oMenuBlock->GetRenderContent($oPage, $aExtraParams, $this->iListId);
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
protected function GetToolkitMenu(WebPage $oPage, $aExtraParams)
|
||||
{
|
||||
$sMenuTitle = Dict::S('UI:ConfigureThisList');
|
||||
$sHtml = '<div class="itop_popup toolkit_menu" id="tk_'.$this->iListId.'"><ul><li><img src="../images/toolkit_menu.png"><ul>';
|
||||
|
||||
$oMenuItem1 = new JSPopupMenuItem('iTop::ConfigureList', $sMenuTitle, "$('#datatable_dlg_".$this->iListId."').dialog('open');");
|
||||
$aActions = array(
|
||||
$oMenuItem1->GetUID() => $oMenuItem1->GetMenuItem(),
|
||||
);
|
||||
$this->oSet->Rewind();
|
||||
utils::GetPopupMenuItems($oPage, iPopupMenuExtension::MENU_OBJLIST_TOOLKIT, $this->oSet, $aActions);
|
||||
$this->oSet->Rewind();
|
||||
$sHtml .= $oPage->RenderPopupMenuItems($aActions);
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
protected function GetTableConfigDlg(WebPage $oPage, $aColumns, $bViewLink, $iDefaultPageSize)
|
||||
{
|
||||
$sHtml = "<div id=\"datatable_dlg_{$this->iListId}\" style=\"display: none;\">";
|
||||
$sHtml .= "<form onsubmit=\"return false\">";
|
||||
$sChecked = ($this->bUseCustomSettings) ? '' : 'checked';
|
||||
$sHtml .= "<p><input id=\"dtbl_dlg_settings_{$this->iListId}\" type=\"radio\" name=\"settings\" $sChecked value=\"defaults\"><label for=\"dtbl_dlg_settings_{$this->iListId}\"> ".Dict::S('UI:UseDefaultSettings').'</label></p>';
|
||||
$sHtml .= "<fieldset>";
|
||||
$sChecked = ($this->bUseCustomSettings) ? 'checked': '';
|
||||
$sHtml .= "<legend class=\"transparent\"><input id=\"dtbl_dlg_specific_{$this->iListId}\" type=\"radio\" class=\"specific_settings\" name=\"settings\" $sChecked value=\"specific\"><label for=\"dtbl_dlg_specific_{$this->iListId}\"> ".Dict::S('UI:UseSpecificSettings')."</label></legend>";
|
||||
$sHtml .= Dict::S('UI:ColumnsAndSortOrder').'<br/><ul class="sortable_field_list" id="sfl_'.$this->iListId.'"></ul>';
|
||||
|
||||
$sHtml .= '<p>'.Dict::Format('UI:Display_X_ItemsPerPage', '<input type="text" size="4" name="page_size" value="'.$iDefaultPageSize.'">').'</p>';
|
||||
$sHtml .= "</fieldset>";
|
||||
$sHtml .= "<fieldset>";
|
||||
$sSaveChecked = ($this->sTableId != null) ? 'checked' : '';
|
||||
$sCustomDisabled = ($this->sTableId == null) ? 'disabled="disabled" stay-disabled="true" ' : '';
|
||||
$sCustomChecked = ($this->sTableId != null) ? 'checked' : '';
|
||||
$sGenericChecked = ($this->sTableId == null) ? 'checked' : '';
|
||||
$sHtml .= "<legend class=\"transparent\"><input id=\"dtbl_dlg_save_{$this->iListId}\" type=\"checkbox\" $sSaveChecked name=\"save_settings\"><label for=\"dtbl_dlg_save_{$this->iListId}\"> ".Dict::S('UI:UseSavetheSettings')."</label></legend>";
|
||||
$sHtml .= "<p><input id=\"dtbl_dlg_this_list_{$this->iListId}\" type=\"radio\" name=\"scope\" $sCustomChecked $sCustomDisabled value=\"this_list\"><label for=\"dtbl_dlg_this_list_{$this->iListId}\"> ".Dict::S('UI:OnlyForThisList').'</label> ';
|
||||
$sHtml .= "<input id=\"dtbl_dlg_all_{$this->iListId}\" type=\"radio\" name=\"scope\" $sGenericChecked value=\"defaults\"><label for=\"dtbl_dlg_all_{$this->iListId}\"> ".Dict::S('UI:ForAllLists').'</label></p>';
|
||||
$sHtml .= "</fieldset>";
|
||||
$sHtml .= '<table style="width:100%"><tr><td style="text-align:center;">';
|
||||
$sHtml .= '<button type="button" onclick="$(\'#datatable_'.$this->iListId.'\').datatable(\'onDlgCancel\'); $(\'#datatable_dlg_'.$this->iListId.'\').dialog(\'close\')">'.Dict::S('UI:Button:Cancel').'</button>';
|
||||
$sHtml .= '</td><td style="text-align:center;">';
|
||||
$sHtml .= '<button type="submit" onclick="$(\'#datatable_'.$this->iListId.'\').datatable(\'onDlgOk\');$(\'#datatable_dlg_'.$this->iListId.'\').dialog(\'close\');">'.Dict::S('UI:Button:Ok').'</button>';
|
||||
$sHtml .= '</td></tr></table>';
|
||||
$sHtml .= "</form>";
|
||||
$sHtml .= "</div>";
|
||||
|
||||
$sDlgTitle = addslashes(Dict::S('UI:ListConfigurationTitle'));
|
||||
$oPage->add_ready_script("$('#datatable_dlg_{$this->iListId}').dialog({autoOpen: false, title: '$sDlgTitle', width: 500, close: function() { $('#datatable_{$this->iListId}').datatable('onDlgCancel'); } });");
|
||||
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
public function GetAsHash($oSetting)
|
||||
{
|
||||
$aSettings = array('iDefaultPageSize' => $oSetting->iDefaultPageSize, 'oColumns' => $oSetting->aColumns);
|
||||
return $aSettings;
|
||||
}
|
||||
|
||||
protected function GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink)
|
||||
{
|
||||
$aAttribs = array();
|
||||
if ($sSelectMode == 'multiple')
|
||||
{
|
||||
$aAttribs['form::select'] = array('label' => "<input type=\"checkbox\" onClick=\"CheckAll('.selectList{$this->iListId}:not(:disabled)', this.checked);\" class=\"checkAll\"></input>", 'description' => Dict::S('UI:SelectAllToggle+'));
|
||||
}
|
||||
else if ($sSelectMode == 'single')
|
||||
{
|
||||
$aAttribs['form::select'] = array('label' => "", 'description' => '');
|
||||
}
|
||||
|
||||
foreach($this->aClassAliases as $sAlias => $sClassName)
|
||||
{
|
||||
foreach($aColumns[$sAlias] as $sAttCode => $aData)
|
||||
{
|
||||
if ($aData['checked'])
|
||||
{
|
||||
if ($sAttCode == '_key_')
|
||||
{
|
||||
$aAttribs['key_'.$sAlias] = array('label' => MetaModel::GetName($sClassName), 'description' => '');
|
||||
}
|
||||
else
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClassName, $sAttCode);
|
||||
$aAttribs[$sAttCode.'_'.$sAlias] = array('label' => MetaModel::GetLabel($sClassName, $sAttCode), 'description' => $oAttDef->GetOrderByHint());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return $aAttribs;
|
||||
}
|
||||
|
||||
protected function GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams)
|
||||
{
|
||||
$aValues = array();
|
||||
$this->oSet->Seek(0);
|
||||
$iMaxObjects = $iPageSize;
|
||||
while (($aObjects = $this->oSet->FetchAssoc()) && ($iMaxObjects != 0))
|
||||
{
|
||||
$bFirstObject = true;
|
||||
$aRow = array();
|
||||
foreach($this->aClassAliases as $sAlias => $sClassName)
|
||||
{
|
||||
$sHilightClass = $aObjects[$sAlias]->GetHilightClass();
|
||||
if ($sHilightClass != '')
|
||||
{
|
||||
$aRow['@class'] = $sHilightClass;
|
||||
}
|
||||
if ((($sSelectMode == 'single') || ($sSelectMode == 'multiple')) && $bFirstObject)
|
||||
{
|
||||
if (array_key_exists('selection_enabled', $aExtraParams) && isset($aExtraParams['selection_enabled'][$aObjects[$sAlias]->GetKey()]))
|
||||
{
|
||||
$sDisabled = ($aExtraParams['selection_enabled'][$aObjects[$sAlias]->GetKey()]) ? '' : ' disabled="disabled"';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sDisabled = '';
|
||||
}
|
||||
if ($sSelectMode == 'single')
|
||||
{
|
||||
$aRow['form::select'] = "<input type=\"radio\" $sDisabled class=\"selectList{$this->iListId}\" name=\"selectObject\" value=\"".$aObjects[$sAlias]->GetKey()."\"></input>";
|
||||
}
|
||||
else
|
||||
{
|
||||
$aRow['form::select'] = "<input type=\"checkBox\" $sDisabled class=\"selectList{$this->iListId}\" name=\"selectObject[]\" value=\"".$aObjects[$sAlias]->GetKey()."\"></input>";
|
||||
}
|
||||
}
|
||||
foreach($aColumns[$sAlias] as $sAttCode => $aData)
|
||||
{
|
||||
if ($aData['checked'])
|
||||
{
|
||||
if ($sAttCode == '_key_')
|
||||
{
|
||||
$aRow['key_'.$sAlias] = $aObjects[$sAlias]->GetHyperLink();
|
||||
}
|
||||
else
|
||||
{
|
||||
$aRow[$sAttCode.'_'.$sAlias] = $aObjects[$sAlias]->GetAsHTML($sAttCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
$bFirstObject = false;
|
||||
}
|
||||
$aValues[] = $aRow;
|
||||
$iMaxObjects--;
|
||||
}
|
||||
return $aValues;
|
||||
}
|
||||
|
||||
public function GetHTMLTable(WebPage $oPage, $aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams)
|
||||
{
|
||||
$iNbPages = ($iPageSize < 1) ? 1 : ceil($this->iNbObjects / $iPageSize);
|
||||
if ($iPageSize < 1)
|
||||
{
|
||||
$iPageSize = -1; // convention: no pagination
|
||||
}
|
||||
$aAttribs = $this->GetHTMLTableConfig($aColumns, $sSelectMode, $bViewLink);
|
||||
|
||||
$aValues = $this->GetHTMLTableValues($aColumns, $sSelectMode, $iPageSize, $bViewLink, $aExtraParams);
|
||||
|
||||
$sHtml = '<table class="listContainer">';
|
||||
|
||||
foreach($this->oSet->GetFilter()->GetInternalParams() as $sName => $sValue)
|
||||
{
|
||||
$aExtraParams['query_params'][$sName] = $sValue;
|
||||
}
|
||||
|
||||
$sHtml .= "<tr><td>";
|
||||
$sHtml .= $oPage->GetTable($aAttribs, $aValues);
|
||||
$sHtml .= '</td></tr>';
|
||||
$sHtml .= '</table>';
|
||||
$iCount = $this->iNbObjects;
|
||||
|
||||
$aArgs = $this->oSet->GetArgs();
|
||||
$sExtraParams = addslashes(str_replace('"', "'", json_encode(array_merge($aExtraParams, $aArgs)))); // JSON encode, change the style of the quotes and escape them
|
||||
$sSelectModeJS = '';
|
||||
$sHeaders = '';
|
||||
if (($sSelectMode == 'single') || ($sSelectMode == 'multiple'))
|
||||
{
|
||||
$sSelectModeJS = $sSelectMode;
|
||||
$sHeaders = 'headers: { 0: {sorter: false}},';
|
||||
}
|
||||
$sDisplayKey = ($bViewLink) ? 'true' : 'false';
|
||||
// Protect against duplicate elements in the Zlist
|
||||
$aUniqueOrderedList = array();
|
||||
foreach($this->aClassAliases as $sAlias => $sClassName)
|
||||
{
|
||||
foreach($aColumns[$sAlias] as $sAttCode => $aData)
|
||||
{
|
||||
if ($aData['checked'])
|
||||
{
|
||||
$aUniqueOrderedList[$sAttCode] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
$aUniqueOrderedList = array_keys($aUniqueOrderedList);
|
||||
$sJSColumns = json_encode($aColumns);
|
||||
$sJSClassAliases = json_encode($this->aClassAliases);
|
||||
$sCssCount = isset($aExtraParams['cssCount']) ? ", cssCount: '{$aExtraParams['cssCount']}'" : '';
|
||||
$this->oSet->ApplyParameters();
|
||||
// Display the actual sort order of the table
|
||||
$aRealSortOrder = $this->oSet->GetRealSortOrder();
|
||||
$aDefaultSort = array();
|
||||
$iColOffset = 0;
|
||||
if (($sSelectMode == 'single') || ($sSelectMode == 'multiple'))
|
||||
{
|
||||
$iColOffset += 1;
|
||||
}
|
||||
if ($bViewLink)
|
||||
{
|
||||
// $iColOffset += 1;
|
||||
}
|
||||
foreach($aRealSortOrder as $sColCode => $bAscending)
|
||||
{
|
||||
$iPos = array_search($sColCode, $aUniqueOrderedList);
|
||||
if ($iPos !== false)
|
||||
{
|
||||
$aDefaultSort[] = "[".($iColOffset+$iPos).",".($bAscending ? '0' : '1')."]";
|
||||
}
|
||||
else if (($iPos = array_search(preg_replace('/_friendlyname$/', '', $sColCode), $aUniqueOrderedList)) !== false)
|
||||
{
|
||||
// if sorted on the friendly name of an external key, then consider it sorted on the column that shows the links
|
||||
$aDefaultSort[] = "[".($iColOffset+$iPos).",".($bAscending ? '0' : '1')."]";
|
||||
}
|
||||
else if($sColCode == 'friendlyname' && $bViewLink)
|
||||
{
|
||||
$aDefaultSort[] = "[".($iColOffset).",".($bAscending ? '0' : '1')."]";
|
||||
}
|
||||
}
|
||||
$sSortList = '';
|
||||
if (count($aDefaultSort) > 0)
|
||||
{
|
||||
$sSortList = ', sortList: ['.implode(',', $aDefaultSort).']';
|
||||
}
|
||||
$sOQL = addslashes($this->oSet->GetFilter()->serialize());
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
var oTable = $('#{$this->iListId} table.listResults');
|
||||
oTable.tablesorter( { $sHeaders widgets: ['myZebra', 'truncatedList'] $sSortList} ).tablesorterPager({container: $('#pager{$this->iListId}'), totalRows:$iCount, size: $iPageSize, filter: '$sOQL', extra_params: '$sExtraParams', select_mode: '$sSelectModeJS', displayKey: $sDisplayKey, columns: $sJSColumns, class_aliases: $sJSClassAliases $sCssCount});
|
||||
EOF
|
||||
);
|
||||
//if ($iNbPages == 1)
|
||||
if (false)
|
||||
{
|
||||
if (isset($aExtraParams['cssCount']))
|
||||
{
|
||||
$sCssCount = $aExtraParams['cssCount'];
|
||||
if ($sSelectMode == 'single')
|
||||
{
|
||||
$sSelectSelector = ":radio[name^=selectObj]";
|
||||
}
|
||||
else if ($sSelectMode == 'multiple')
|
||||
{
|
||||
$sSelectSelector = ":checkbox[name^=selectObj]";
|
||||
}
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
$('#{$this->iListId} table.listResults $sSelectSelector').change(function() {
|
||||
var c = $('{$sCssCount}');
|
||||
var v = $('#{$this->iListId} table.listResults $sSelectSelector:checked').length;
|
||||
c.val(v);
|
||||
$('#{$this->iListId} .selectedCount').text(v);
|
||||
c.trigger('change');
|
||||
});
|
||||
EOF
|
||||
);
|
||||
}
|
||||
}
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
public function UpdatePager(WebPage $oPage, $iDefaultPageSize, $iStart)
|
||||
{
|
||||
$iPageSize = ($iDefaultPageSize < 1) ? 1 : $iDefaultPageSize;
|
||||
$iPageIndex = 1 + floor($iStart / $iPageSize);
|
||||
$sHtml = $this->GetPager($oPage, $iPageSize, $iDefaultPageSize, $iPageIndex);
|
||||
$oPage->add_ready_script("$('#pager{$this->iListId}').html('".str_replace("\n", ' ', addslashes($sHtml))."');");
|
||||
if ($iDefaultPageSize < 1)
|
||||
{
|
||||
$oPage->add_ready_script("$('#pager{$this->iListId}').parent().hide()");
|
||||
}
|
||||
else
|
||||
{
|
||||
$oPage->add_ready_script("$('#pager{$this->iListId}').parent().show()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DataTableSettings implements Serializable
|
||||
{
|
||||
public $aClassAliases;
|
||||
public $sTableId;
|
||||
public $iDefaultPageSize;
|
||||
public $aColumns;
|
||||
|
||||
|
||||
public function __construct($aClassAliases, $sTableId = null)
|
||||
{
|
||||
$this->aClassAliases = $aClassAliases;
|
||||
$this->sTableId = $sTableId;
|
||||
$this->iDefaultPageSize = 10;
|
||||
$this->aColumns = array();
|
||||
}
|
||||
|
||||
protected function Init($iDefaultPageSize, $aSortOrder, $aColumns)
|
||||
{
|
||||
$this->iDefaultPageSize = $iDefaultPageSize;
|
||||
$this->aColumns = $aColumns;
|
||||
$this->FixVisibleColumns();
|
||||
}
|
||||
|
||||
public function serialize()
|
||||
{
|
||||
// Save only the 'visible' columns
|
||||
$aColumns = array();
|
||||
foreach($this->aClassAliases as $sAlias => $sClass)
|
||||
{
|
||||
$aColumns[$sAlias] = array();
|
||||
foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
|
||||
{
|
||||
unset($aData['label']); // Don't save the display name
|
||||
unset($aData['alias']); // Don't save the alias (redundant)
|
||||
unset($aData['code']); // Don't save the code (redundant)
|
||||
if ($aData['checked'])
|
||||
{
|
||||
$aColumns[$sAlias][$sAttCode] = $aData;
|
||||
}
|
||||
}
|
||||
}
|
||||
return serialize(
|
||||
array(
|
||||
'iDefaultPageSize' => $this->iDefaultPageSize,
|
||||
'aColumns' => $aColumns,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function unserialize($sData)
|
||||
{
|
||||
$aData = unserialize($sData);
|
||||
$this->iDefaultPageSize = $aData['iDefaultPageSize'];
|
||||
$this->aColumns = $aData['aColumns'];
|
||||
foreach($this->aClassAliases as $sAlias => $sClass)
|
||||
{
|
||||
foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
|
||||
{
|
||||
$aFieldData = false;
|
||||
if ($sAttCode == '_key_')
|
||||
{
|
||||
$aFieldData = $this->GetFieldData($sAlias, $sAttCode, null, true /* bChecked */, $aData['sort']);
|
||||
}
|
||||
else if (MetaModel::isValidAttCode($sClass, $sAttCode))
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
$aFieldData = $this->GetFieldData($sAlias, $sAttCode, $oAttDef, true /* bChecked */, $aData['sort']);
|
||||
}
|
||||
|
||||
if ($aFieldData)
|
||||
{
|
||||
$this->aColumns[$sAlias][$sAttCode] = $aFieldData;
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($this->aColumns[$sAlias][$sAttCode]);
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->FixVisibleColumns();
|
||||
}
|
||||
|
||||
static public function GetDataModelSettings($aClassAliases, $bViewLink, $aDefaultLists)
|
||||
{
|
||||
$oSettings = new DataTableSettings($aClassAliases);
|
||||
// Retrieve the class specific settings for each class/alias based on the 'list' ZList
|
||||
//TODO let the caller pass some other default settings (another Zlist, extre fields...)
|
||||
$aColumns = array();
|
||||
foreach($aClassAliases as $sAlias => $sClass)
|
||||
{
|
||||
if ($aDefaultLists == null)
|
||||
{
|
||||
$aList = cmdbAbstract::FlattenZList(MetaModel::GetZListItems($sClass, 'list'));
|
||||
}
|
||||
else
|
||||
{
|
||||
$aList = $aDefaultLists[$sAlias];
|
||||
}
|
||||
|
||||
$aSortOrder = MetaModel::GetOrderByDefault($sClass);
|
||||
if ($bViewLink)
|
||||
{
|
||||
$sSort = 'none';
|
||||
if(array_key_exists('friendlyname', $aSortOrder))
|
||||
{
|
||||
$sSort = $aSortOrder['friendlyname'] ? 'asc' : 'desc';
|
||||
}
|
||||
$aColumns[$sAlias]['_key_'] = $oSettings->GetFieldData($sAlias, '_key_', null, true /* bChecked */, $sSort);
|
||||
}
|
||||
foreach($aList as $sAttCode)
|
||||
{
|
||||
$sSort = 'none';
|
||||
if(array_key_exists($sAttCode, $aSortOrder))
|
||||
{
|
||||
$sSort = $aSortOrder[$sAttCode] ? 'asc' : 'desc';
|
||||
}
|
||||
$oAttDef = Metamodel::GetAttributeDef($sClass, $sAttCode);
|
||||
$aFieldData = $oSettings->GetFieldData($sAlias, $sAttCode, $oAttDef, true /* bChecked */, $sSort);
|
||||
if ($aFieldData) $aColumns[$sAlias][$sAttCode] = $aFieldData;
|
||||
}
|
||||
}
|
||||
$iDefaultPageSize = appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit());
|
||||
$oSettings->Init($iDefaultPageSize, $aSortOrder, $aColumns);
|
||||
return $oSettings;
|
||||
}
|
||||
|
||||
protected function FixVisibleColumns()
|
||||
{
|
||||
foreach($this->aClassAliases as $sAlias => $sClass)
|
||||
{
|
||||
foreach($this->aColumns[$sAlias] as $sAttCode => $aData)
|
||||
{
|
||||
// Remove non-existent columns
|
||||
// TODO: check if the existing ones are still valid (in case their type changed)
|
||||
if (($sAttCode != '_key_') && (!MetaModel::IsValidAttCode($sClass, $sAttCode)))
|
||||
{
|
||||
unset($this->aColumns[$sAlias][$sAttCode]);
|
||||
}
|
||||
}
|
||||
$aList = MetaModel::ListAttributeDefs($sClass);
|
||||
|
||||
// Add the other (non visible ones), sorted in alphabetical order
|
||||
$aTempData = array();
|
||||
foreach($aList as $sAttCode => $oAttDef)
|
||||
{
|
||||
if ( (!array_key_exists($sAttCode, $this->aColumns[$sAlias])) && (!$oAttDef instanceof AttributeLinkSet))
|
||||
{
|
||||
$aFieldData = $this->GetFieldData($sAlias, $sAttCode, $oAttDef, false /* bChecked */, 'none');
|
||||
if ($aFieldData) $aTempData[$aFieldData['label']] = $aFieldData;
|
||||
}
|
||||
}
|
||||
ksort($aTempData);
|
||||
foreach($aTempData as $sLabel => $aFieldData)
|
||||
{
|
||||
$this->aColumns[$sAlias][$aFieldData['code']] = $aFieldData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static public function GetTableSettings($aClassAliases, $sTableId = null)
|
||||
{
|
||||
$pref = null;
|
||||
$oSettings = new DataTableSettings($aClassAliases, $sTableId);
|
||||
|
||||
if ($sTableId != null)
|
||||
{
|
||||
// An identified table, let's fetch its own settings (if any)
|
||||
$pref = appUserPreferences::GetPref($oSettings->GetPrefsKey($sTableId), null);
|
||||
}
|
||||
|
||||
if ($pref == null)
|
||||
{
|
||||
// Try the global preferred values for this class / set of classes
|
||||
$pref = appUserPreferences::GetPref($oSettings->GetPrefsKey(null), null);
|
||||
if ($pref == null)
|
||||
{
|
||||
// no such settings, use the default values provided by the data model
|
||||
return null;
|
||||
}
|
||||
}
|
||||
$oSettings->unserialize($pref);
|
||||
|
||||
return $oSettings;
|
||||
}
|
||||
|
||||
public function GetSortOrder()
|
||||
{
|
||||
$aSortOrder = array();
|
||||
foreach($this->aColumns as $sAlias => $aColumns)
|
||||
{
|
||||
foreach($aColumns as $aColumn)
|
||||
{
|
||||
if ($aColumn['sort'] != 'none')
|
||||
{
|
||||
$sCode = ($aColumn['code'] == '_key_') ? 'friendlyname' : $aColumn['code'];
|
||||
$aSortOrder[$sCode] = ($aColumn['sort']=='asc'); // true for ascending, false for descending
|
||||
}
|
||||
}
|
||||
break; // TODO: For now the Set object supports only sorting on the first class of the set
|
||||
}
|
||||
return $aSortOrder;
|
||||
}
|
||||
|
||||
public function Save()
|
||||
{
|
||||
if ($this->sTableId == null) return false; // Cannot save, the table is not identified, use SaveAsDefault instead
|
||||
|
||||
$sSettings = $this->serialize();
|
||||
appUserPreferences::SetPref($this->GetPrefsKey($this->sTableId), $sSettings);
|
||||
return true;
|
||||
}
|
||||
|
||||
public function SaveAsDefault()
|
||||
{
|
||||
$sSettings = $this->serialize();
|
||||
appUserPreferences::SetPref($this->GetPrefsKey(null), $sSettings);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clear the preferences for this particular table
|
||||
* @param $bResetAll boolean If true,the settings for all tables of the same class(es)/alias(es) are reset
|
||||
*/
|
||||
public function ResetToDefault($bResetAll)
|
||||
{
|
||||
if (($this->sTableId == null) && (!$bResetAll)) return false; // Cannot reset, the table is not identified, use force $bResetAll instead
|
||||
if ($bResetAll)
|
||||
{
|
||||
// Turn the key into a suitable PCRE pattern
|
||||
$sKey = $this->GetPrefsKey(null);
|
||||
$sPattern = str_replace(array('|'), array('\\|'), $sKey); // escape the | character
|
||||
$sPattern = '#^'.str_replace(array('*'), array('.*'), $sPattern).'$#'; // Don't use slash as the delimiter since it's used in our key to delimit aliases
|
||||
appUserPreferences::UnsetPref($sPattern, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
appUserPreferences::UnsetPref($this->GetPrefsKey($this->sTableId), false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function GetPrefsKey($sTableId = null)
|
||||
{
|
||||
if ($sTableId == null) $sTableId = '*';
|
||||
$aKeys = array();
|
||||
foreach($this->aClassAliases as $sAlias => $sClass)
|
||||
{
|
||||
$aKeys[] = $sAlias.'-'.$sClass;
|
||||
}
|
||||
return implode('/', $aKeys).'|'.$sTableId;
|
||||
}
|
||||
|
||||
protected function GetFieldData($sAlias, $sAttCode, $oAttDef, $bChecked, $sSort)
|
||||
{
|
||||
$ret = false;
|
||||
if ($sAttCode == '_key_')
|
||||
{
|
||||
$sLabel = Dict::Format('UI:ExtKey_AsLink', MetaModel::GetName($this->aClassAliases[$sAlias]));
|
||||
$ret = array(
|
||||
'label' => $sLabel,
|
||||
'checked' => true,
|
||||
'disabled' => true,
|
||||
'alias' => $sAlias,
|
||||
'code' => $sAttCode,
|
||||
'sort' => $sSort,
|
||||
);
|
||||
}
|
||||
else if (!$oAttDef->IsLinkSet())
|
||||
{
|
||||
$sLabel = $oAttDef->GetLabel();
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
$sLabel = Dict::Format('UI:ExtKey_AsLink', $oAttDef->GetLabel());
|
||||
}
|
||||
else if ($oAttDef->IsExternalField())
|
||||
{
|
||||
$oExtAttDef = $oAttDef->GetExtAttDef();
|
||||
$sLabel = Dict::Format('UI:ExtField_AsRemoteField', $oAttDef->GetLabel(), $oExtAttDef->GetLabel());
|
||||
}
|
||||
elseif ($oAttDef instanceof AttributeFriendlyName)
|
||||
{
|
||||
$sLabel = Dict::Format('UI:ExtKey_AsFriendlyName', $oAttDef->GetLabel());
|
||||
}
|
||||
$ret = array(
|
||||
'label' => $sLabel,
|
||||
'checked' => $bChecked,
|
||||
'disabled' => false,
|
||||
'alias' => $sAlias,
|
||||
'code' => $sAttCode,
|
||||
'sort' => $sSort,
|
||||
);
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,6 @@ class DisplayBlock
|
||||
{
|
||||
const TAG_BLOCK = 'itopblock';
|
||||
protected $m_oFilter;
|
||||
protected $m_aConditions; // Conditions added to the filter -> avoid duplicate conditions
|
||||
protected $m_sStyle;
|
||||
protected $m_bAsynchronous;
|
||||
protected $m_aParams;
|
||||
@@ -52,8 +51,7 @@ class DisplayBlock
|
||||
|
||||
public function __construct(DBObjectSearch $oFilter, $sStyle = 'list', $bAsynchronous = false, $aParams = array(), $oSet = null)
|
||||
{
|
||||
$this->m_oFilter = clone $oFilter;
|
||||
$this->m_aConditions = array();
|
||||
$this->m_oFilter = $oFilter;
|
||||
$this->m_sStyle = $sStyle;
|
||||
$this->m_bAsynchronous = $bAsynchronous;
|
||||
$this->m_aParams = $aParams;
|
||||
@@ -254,7 +252,7 @@ class DisplayBlock
|
||||
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
{
|
||||
if (!isset($aExtraParams['currentId']))
|
||||
if (empty($aExtraParams['currentId']))
|
||||
{
|
||||
$sId = $oPage->GetUniqueId(); // Works only if the page is not an Ajax one !
|
||||
}
|
||||
@@ -283,18 +281,15 @@ class DisplayBlock
|
||||
$sClass = $this->m_oFilter->GetClass();
|
||||
$aFilterCodes = array_keys(MetaModel::GetClassFilterDefs($sClass));
|
||||
$aCallSpec = array($sClass, 'MapContextParam');
|
||||
if (is_callable($aCallSpec))
|
||||
foreach($oAppContext->GetNames() as $sContextParam)
|
||||
{
|
||||
foreach($oAppContext->GetNames() as $sContextParam)
|
||||
$sParamCode = call_user_func($aCallSpec, $sContextParam); //Map context parameter to the value/filter code depending on the class
|
||||
if (!is_null($sParamCode))
|
||||
{
|
||||
$sParamCode = call_user_func($aCallSpec, $sContextParam); //Map context parameter to the value/filter code depending on the class
|
||||
if (!is_null($sParamCode))
|
||||
$sParamValue = $oAppContext->GetCurrentValue($sContextParam, null);
|
||||
if (!is_null($sParamValue))
|
||||
{
|
||||
$sParamValue = $oAppContext->GetCurrentValue($sContextParam, null);
|
||||
if (!is_null($sParamValue))
|
||||
{
|
||||
$aExtraParams[$sParamCode] = $sParamValue;
|
||||
}
|
||||
$aExtraParams[$sParamCode] = $sParamValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -319,15 +314,6 @@ class DisplayBlock
|
||||
$this->AddCondition($sFilterCode, $condition);
|
||||
}
|
||||
}
|
||||
if ($bDoSearch)
|
||||
{
|
||||
// Keep the table_id identifying this table if we're performing a search
|
||||
$sTableId = utils::ReadParam('_table_id_', null, false, 'raw_data');
|
||||
if ($sTableId != null)
|
||||
{
|
||||
$aExtraParams['table_id'] = $sTableId;
|
||||
}
|
||||
}
|
||||
}
|
||||
$aOrderBy = array();
|
||||
if (isset($aExtraParams['order_by']))
|
||||
@@ -358,55 +344,38 @@ class DisplayBlock
|
||||
case 'count':
|
||||
if (isset($aExtraParams['group_by']))
|
||||
{
|
||||
if (isset($aExtraParams['group_by_label']))
|
||||
{
|
||||
$oGroupByExp = Expression::FromOQL($aExtraParams['group_by']);
|
||||
$sGroupByLabel = $aExtraParams['group_by_label'];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Backward compatibility: group_by is simply a field id
|
||||
$sAlias = $this->m_oFilter->GetClassAlias();
|
||||
$oGroupByExp = new FieldExpression($aExtraParams['group_by'], $sAlias);
|
||||
$sGroupByLabel = MetaModel::GetLabel($this->m_oFilter->GetClass(), $aExtraParams['group_by']);
|
||||
}
|
||||
|
||||
$sGroupByField = $aExtraParams['group_by'];
|
||||
$aGroupBy = array();
|
||||
$aGroupBy['grouped_by_1'] = $oGroupByExp;
|
||||
$sSql = MetaModel::MakeGroupByQuery($this->m_oFilter, $aQueryParams, $aGroupBy);
|
||||
$aRes = CMDBSource::QueryToArray($sSql);
|
||||
|
||||
$aGroupBy = array();
|
||||
$aLabels = array();
|
||||
$aValues = array();
|
||||
$iTotalCount = 0;
|
||||
foreach ($aRes as $iRow => $aRow)
|
||||
$sLabels = array();
|
||||
$iTotalCount = $this->m_oSet->Count();
|
||||
$oTmpSet = clone $this->m_oSet;
|
||||
// Speed up the load, load only the needed field to group on
|
||||
$sAlias = $oTmpSet->GetFilter()->GetClassAlias();
|
||||
$oTmpSet->OptimizeColumnLoad(array($sAlias => array($sGroupByField)));
|
||||
while($oObj = $oTmpSet->Fetch())
|
||||
{
|
||||
$sValue = $aRow['grouped_by_1'];
|
||||
$aValues[$iRow] = $sValue;
|
||||
$sHtmlValue = $oGroupByExp->MakeValueLabel($this->m_oFilter, $sValue, $sValue);
|
||||
$aLabels[$iRow] = $sHtmlValue;
|
||||
$aGroupBy[$iRow] = (int) $aRow['_itop_count_'];
|
||||
$iTotalCount += $aRow['_itop_count_'];
|
||||
if (isset($aExtraParams['group_by_expr']))
|
||||
{
|
||||
eval("\$sValue = ".sprintf($aExtraParams['group_by_expr'], $oObj->Get($sGroupByField)).';');
|
||||
}
|
||||
else
|
||||
{
|
||||
$sValue = $oObj->Get($sGroupByField);
|
||||
}
|
||||
$aGroupBy[$sValue] = isset($aGroupBy[$sValue]) ? $aGroupBy[$sValue]+1 : 1;
|
||||
$sLabels[$sValue] = $oObj->GetAsHtml($sGroupByField);
|
||||
}
|
||||
|
||||
|
||||
$sFilter = urlencode($this->m_oFilter->serialize());
|
||||
$aData = array();
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sParams = $oAppContext->GetForLink();
|
||||
foreach($aGroupBy as $iRow => $iCount)
|
||||
foreach($aGroupBy as $sValue => $iCount)
|
||||
{
|
||||
// Build the search for this subset
|
||||
$oSubsetSearch = clone $this->m_oFilter;
|
||||
$oCondition = new BinaryExpression($oGroupByExp, '=', new ScalarExpression($aValues[$iRow]));
|
||||
$oSubsetSearch->AddConditionExpression($oCondition);
|
||||
$sFilter = urlencode($oSubsetSearch->serialize());
|
||||
|
||||
$aData[] = array ( 'group' => $aLabels[$iRow],
|
||||
'value' => "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&dosearch=1&$sParams&filter=$sFilter\">$iCount</a>"); // TO DO: add the context information
|
||||
$aData[] = array ( 'group' => $sLabels[$sValue],
|
||||
'value' => "<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&dosearch=1&$sParams&filter=$sFilter&$sGroupByField=".urlencode($sValue)."\">$iCount</a>"); // TO DO: add the context information
|
||||
}
|
||||
$aAttribs =array(
|
||||
'group' => array('label' => $sGroupByLabel, 'description' => ''),
|
||||
'group' => array('label' => MetaModel::GetLabel($this->m_oFilter->GetClass(), $sGroupByField), 'description' => ''),
|
||||
'value' => array('label'=> Dict::S('UI:GroupBy:Count'), 'description' => Dict::S('UI:GroupBy:Count+'))
|
||||
);
|
||||
$sFormat = isset($aExtraParams['format']) ? $aExtraParams['format'] : 'UI:Pagination:HeaderNoSelection';
|
||||
@@ -656,10 +625,9 @@ class DisplayBlock
|
||||
$this->m_oSet = new CMDBObjectSet($this->m_oFilter, array(), $aQueryParams);
|
||||
}
|
||||
$iCount = $this->m_oSet->Count();
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.urlencode($this->m_oFilter->serialize());
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.$this->m_oFilter->serialize();
|
||||
$sHtml .= '<p><a class="actions" href="'.$sHyperlink.'">';
|
||||
// Note: border set to 0 due to various browser interpretations (IE9 adding a 2px border)
|
||||
$sHtml .= MetaModel::GetClassIcon($sClass, true, 'float;left;margin-right:10px;border:0;');
|
||||
$sHtml .= MetaModel::GetClassIcon($sClass, true, 'float;left;margin-right:10px;');
|
||||
$sHtml .= MetaModel::GetName($sClass).': '.$iCount.'</a></p>';
|
||||
$sParams = $oAppContext->GetForLink();
|
||||
$sHtml .= '<p>';
|
||||
@@ -718,7 +686,7 @@ class DisplayBlock
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.urlencode($oFilter->serialize());
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.$oFilter->serialize();
|
||||
$aCounts[$sStateValue] = "<a href=\"$sHyperlink\">{$aCounts[$sStateValue]}</a>";
|
||||
}
|
||||
}
|
||||
@@ -727,7 +695,7 @@ class DisplayBlock
|
||||
$sHtml .= '<tr><td>'.implode('</td><td>', $aCounts).'</td></tr></table></div>';
|
||||
// Title & summary
|
||||
$iCount = $this->m_oSet->Count();
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.urlencode($this->m_oFilter->serialize());
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=search&'.$oAppContext->GetForLink().'&filter='.$this->m_oFilter->serialize();
|
||||
$sHtml .= '<h1>'.Dict::S(str_replace('_', ':', $sTitle)).'</h1>';
|
||||
$sHtml .= '<a class="summary" href="'.$sHyperlink.'">'.Dict::Format(str_replace('_', ':', $sLabel), $iCount).'</a>';
|
||||
break;
|
||||
@@ -779,70 +747,43 @@ EOF
|
||||
$sGroupBy = isset($aExtraParams['group_by']) ? $aExtraParams['group_by'] : '';
|
||||
$sGroupByExpr = isset($aExtraParams['group_by_expr']) ? '¶ms[group_by_expr]='.$aExtraParams['group_by_expr'] : '';
|
||||
$sFilter = $this->m_oFilter->serialize();
|
||||
$sHtml .= "<div id=\"my_chart_$sId{$iChartCounter}\">If the chart does not display, <a href=\"http://get.adobe.com/flash/\" target=\"_blank\">install Flash</a></div>\n";
|
||||
$sHtml .= "<div id=\"my_chart_{$iChartCounter}\">If the chart does not display, <a href=\"http://get.adobe.com/flash/\" target=\"_blank\">install Flash</a></div>\n";
|
||||
$oPage->add_script("function ofc_resize(left, width, top, height) { /* do nothing special */ }");
|
||||
if (isset($aExtraParams['group_by_label']))
|
||||
{
|
||||
$sUrl = urlencode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=open_flash_chart¶ms[group_by]=$sGroupBy{$sGroupByExpr}¶ms[group_by_label]={$aExtraParams['group_by_label']}¶ms[chart_type]=$sChartType¶ms[chart_title]=$sTitle¶ms[currentId]=$sId&id=$sId&filter=".urlencode($sFilter));
|
||||
}
|
||||
else
|
||||
{
|
||||
$sUrl = urlencode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=open_flash_chart¶ms[group_by]=$sGroupBy{$sGroupByExpr}¶ms[chart_type]=$sChartType¶ms[chart_title]=$sTitle¶ms[currentId]=$sId&id=$sId&filter=".urlencode($sFilter));
|
||||
}
|
||||
|
||||
$oPage->add_ready_script("swfobject.embedSWF(\"../images/open-flash-chart.swf\", \"my_chart_$sId{$iChartCounter}\", \"100%\", \"300\",\"9.0.0\", \"expressInstall.swf\",
|
||||
{\"data-file\":\"".$sUrl."\"}, {wmode: 'transparent'} );\n");
|
||||
$oPage->add_ready_script("swfobject.embedSWF(\"../images/open-flash-chart.swf\", \"my_chart_{$iChartCounter}\", \"100%\", \"300\",\"9.0.0\", \"expressInstall.swf\",
|
||||
{\"data-file\":\"".urlencode(utils::GetAbsoluteUrlAppRoot()."pages/ajax.render.php?operation=open_flash_chart¶ms[group_by]=$sGroupBy{$sGroupByExpr}¶ms[chart_type]=$sChartType¶ms[chart_title]=$sTitle¶ms[currentId]=$sId&id=$sId&filter=".$sFilter)."\"}, {wmode: 'transparent'} );\n");
|
||||
$iChartCounter++;
|
||||
if (isset($aExtraParams['group_by']))
|
||||
{
|
||||
if (isset($aExtraParams['group_by_label']))
|
||||
{
|
||||
$oGroupByExp = Expression::FromOQL($aExtraParams['group_by']);
|
||||
$sGroupByLabel = $aExtraParams['group_by_label'];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Backward compatibility: group_by is simply a field id
|
||||
$sAlias = $this->m_oFilter->GetClassAlias();
|
||||
$oGroupByExp = new FieldExpression($aExtraParams['group_by'], $sAlias);
|
||||
$sGroupByLabel = MetaModel::GetLabel($this->m_oFilter->GetClass(), $aExtraParams['group_by']);
|
||||
}
|
||||
|
||||
$sGroupByField = $aExtraParams['group_by'];
|
||||
$aGroupBy = array();
|
||||
$aGroupBy['grouped_by_1'] = $oGroupByExp;
|
||||
$sSql = MetaModel::MakeGroupByQuery($this->m_oFilter, $aQueryParams, $aGroupBy);
|
||||
$aRes = CMDBSource::QueryToArray($sSql);
|
||||
|
||||
$aGroupBy = array();
|
||||
$aLabels = array();
|
||||
$aValues = array();
|
||||
$iTotalCount = 0;
|
||||
foreach ($aRes as $iRow => $aRow)
|
||||
while($oObj = $this->m_oSet->Fetch())
|
||||
{
|
||||
$sValue = $aRow['grouped_by_1'];
|
||||
$aValues[$iRow] = $sValue;
|
||||
$sHtmlValue = $oGroupByExp->MakeValueLabel($this->m_oFilter, $sValue, $sValue);
|
||||
$aLabels[$iRow] = $sHtmlValue;
|
||||
$aGroupBy[$iRow] = (int) $aRow['_itop_count_'];
|
||||
$iTotalCount += $aRow['_itop_count_'];
|
||||
if (isset($aExtraParams['group_by_expr']))
|
||||
{
|
||||
eval("\$sValue = ".sprintf($aExtraParams['group_by_expr'], $oObj->Get($sGroupByField)).';');
|
||||
}
|
||||
else
|
||||
{
|
||||
$sValue = $oObj->Get($sGroupByField);
|
||||
}
|
||||
$aGroupBy[$sValue] = isset($aGroupBy[$sValue]) ? $aGroupBy[$sValue]+1 : 1;
|
||||
}
|
||||
|
||||
$sFilter = urlencode($this->m_oFilter->serialize());
|
||||
$aData = array();
|
||||
$aLabels = array();
|
||||
$idx = 0;
|
||||
$aURLs = array();
|
||||
foreach($aGroupBy as $iRow => $iCount)
|
||||
foreach($aGroupBy as $sValue => $iValue)
|
||||
{
|
||||
// Build the search for this subset
|
||||
$oSubsetSearch = clone $this->m_oFilter;
|
||||
$oCondition = new BinaryExpression($oGroupByExp, '=', new ScalarExpression($aValues[$iRow]));
|
||||
$oSubsetSearch->AddConditionExpression($oCondition);
|
||||
$aURLs[$idx] = $oSubsetSearch->serialize();
|
||||
$oDrillDownFilter = clone $this->m_oFilter;
|
||||
$oDrillDownFilter->AddCondition($sGroupByField, $sValue, '=');
|
||||
$aURLs[$idx] = $oDrillDownFilter->serialize();
|
||||
$idx++;
|
||||
}
|
||||
$sURLList = '';
|
||||
foreach($aURLs as $index => $sURL)
|
||||
{
|
||||
$sURLList .= "\taURLs[$index] = '".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&format=html{$sContext}&filter=".urlencode($sURL)."';\n";
|
||||
$sURLList .= "\taURLs[$index] = '".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?operation=search&format=html{$sContext}&filter=".addslashes($sURL)."';\n";
|
||||
}
|
||||
$oPage->add_script(
|
||||
<<<EOF
|
||||
@@ -870,46 +811,31 @@ EOF
|
||||
|
||||
if (isset($aExtraParams['group_by']))
|
||||
{
|
||||
if (isset($aExtraParams['group_by_label']))
|
||||
{
|
||||
$oGroupByExp = Expression::FromOQL($aExtraParams['group_by']);
|
||||
$sGroupByLabel = $aExtraParams['group_by_label'];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Backward compatibility: group_by is simply a field id
|
||||
$sAlias = $this->m_oFilter->GetClassAlias();
|
||||
$oGroupByExp = new FieldExpression($aExtraParams['group_by'], $sAlias);
|
||||
$sGroupByLabel = MetaModel::GetLabel($this->m_oFilter->GetClass(), $aExtraParams['group_by']);
|
||||
}
|
||||
|
||||
$sGroupByField = $aExtraParams['group_by'];
|
||||
$aGroupBy = array();
|
||||
$aGroupBy['grouped_by_1'] = $oGroupByExp;
|
||||
$sSql = MetaModel::MakeGroupByQuery($this->m_oFilter, $aQueryParams, $aGroupBy);
|
||||
$aRes = CMDBSource::QueryToArray($sSql);
|
||||
|
||||
$aGroupBy = array();
|
||||
$aLabels = array();
|
||||
$iTotalCount = 0;
|
||||
foreach ($aRes as $iRow => $aRow)
|
||||
while($oObj = $this->m_oSet->Fetch())
|
||||
{
|
||||
$sValue = $aRow['grouped_by_1'];
|
||||
$sHtmlValue = $oGroupByExp->MakeValueLabel($this->m_oFilter, $sValue, $sValue);
|
||||
$aLabels[$iRow] = strip_tags($sHtmlValue);
|
||||
$aGroupBy[$iRow] = (int) $aRow['_itop_count_'];
|
||||
$iTotalCount += $aRow['_itop_count_'];
|
||||
if (isset($aExtraParams['group_by_expr']))
|
||||
{
|
||||
eval("\$sValue = ".sprintf($aExtraParams['group_by_expr'], $oObj->Get($sGroupByField)).';');
|
||||
}
|
||||
else
|
||||
{
|
||||
$sValue = $oObj->Get($sGroupByField);
|
||||
}
|
||||
$aGroupBy[$sValue] = isset($aGroupBy[$sValue]) ? $aGroupBy[$sValue]+1 : 1;
|
||||
}
|
||||
|
||||
$sFilter = urlencode($this->m_oFilter->serialize());
|
||||
$aData = array();
|
||||
$aChartLabels = array();
|
||||
$aLabels = array();
|
||||
$maxValue = 0;
|
||||
foreach($aGroupBy as $iRow => $iCount)
|
||||
foreach($aGroupBy as $sValue => $iValue)
|
||||
{
|
||||
$oBarValue = new bar_value($iCount);
|
||||
$oBarValue = new bar_value($iValue);
|
||||
$oBarValue->on_click("ofc_drill_down_$sId");
|
||||
$aData[] = $oBarValue;
|
||||
if ($iCount > $maxValue) $maxValue = $iCount;
|
||||
$aChartLabels[] = html_entity_decode($aLabels[$iRow], ENT_QUOTES, 'UTF-8');
|
||||
if ($iValue > $maxValue) $maxValue = $iValue;
|
||||
$aLabels[] = $sValue;
|
||||
}
|
||||
$oYAxis = new y_axis();
|
||||
$aMagicValues = array(1,2,5,10);
|
||||
@@ -935,7 +861,7 @@ EOF
|
||||
// set them vertical
|
||||
$oXLabels->set_vertical();
|
||||
// set the label text
|
||||
$oXLabels->set_labels($aChartLabels);
|
||||
$oXLabels->set_labels($aLabels);
|
||||
// Add the X Axis Labels to the X Axis
|
||||
$oXAxis->set_labels( $oXLabels );
|
||||
$oChart->set_x_axis( $oXAxis );
|
||||
@@ -951,64 +877,37 @@ EOF
|
||||
$oChartElement->set_colours( array('#FF8A00', '#909980', '#2C2B33', '#CCC08D', '#596664') );
|
||||
if (isset($aExtraParams['group_by']))
|
||||
{
|
||||
if (isset($aExtraParams['group_by_label']))
|
||||
{
|
||||
$oGroupByExp = Expression::FromOQL($aExtraParams['group_by']);
|
||||
$sGroupByLabel = $aExtraParams['group_by_label'];
|
||||
}
|
||||
else
|
||||
{
|
||||
// Backward compatibility: group_by is simply a field id
|
||||
$sAlias = $this->m_oFilter->GetClassAlias();
|
||||
$oGroupByExp = new FieldExpression($aExtraParams['group_by'], $sAlias);
|
||||
$sGroupByLabel = MetaModel::GetLabel($this->m_oFilter->GetClass(), $aExtraParams['group_by']);
|
||||
}
|
||||
|
||||
$sGroupByField = $aExtraParams['group_by'];
|
||||
$aGroupBy = array();
|
||||
$aGroupBy['grouped_by_1'] = $oGroupByExp;
|
||||
$sSql = MetaModel::MakeGroupByQuery($this->m_oFilter, $aQueryParams, $aGroupBy);
|
||||
$aRes = CMDBSource::QueryToArray($sSql);
|
||||
|
||||
$aGroupBy = array();
|
||||
$aLabels = array();
|
||||
$iTotalCount = 0;
|
||||
foreach ($aRes as $iRow => $aRow)
|
||||
while($oObj = $this->m_oSet->Fetch())
|
||||
{
|
||||
$sValue = $aRow['grouped_by_1'];
|
||||
$sHtmlValue = $oGroupByExp->MakeValueLabel($this->m_oFilter, $sValue, $sValue);
|
||||
$aLabels[$iRow] = strip_tags($sHtmlValue);
|
||||
$aGroupBy[$iRow] = (int) $aRow['_itop_count_'];
|
||||
$iTotalCount += $aRow['_itop_count_'];
|
||||
if (isset($aExtraParams['group_by_expr']))
|
||||
{
|
||||
eval("\$sValue = ".sprintf($aExtraParams['group_by_expr'], $oObj->Get($sGroupByField)).';');
|
||||
}
|
||||
else
|
||||
{
|
||||
$sValue = $oObj->Get($sGroupByField);
|
||||
}
|
||||
$aGroupBy[$sValue] = isset($aGroupBy[$sValue]) ? $aGroupBy[$sValue]+1 : 1;
|
||||
}
|
||||
|
||||
$sFilter = urlencode($this->m_oFilter->serialize());
|
||||
$aData = array();
|
||||
foreach($aGroupBy as $iRow => $iCount)
|
||||
foreach($aGroupBy as $sValue => $iValue)
|
||||
{
|
||||
$sFlashLabel = html_entity_decode($aLabels[$iRow], ENT_QUOTES, 'UTF-8');
|
||||
$PieValue = new pie_value($iCount, $sFlashLabel); //@@ BUG: not passed via ajax !!!
|
||||
$PieValue = new pie_value($iValue, $sValue); //@@ BUG: not passed via ajax !!!
|
||||
$PieValue->on_click("ofc_drill_down_$sId");
|
||||
$aData[] = $PieValue;
|
||||
}
|
||||
|
||||
|
||||
$oChartElement->set_values( $aData );
|
||||
$oChart->x_axis = null;
|
||||
}
|
||||
}
|
||||
if (isset($aExtraParams['chart_title']))
|
||||
{
|
||||
// The title has been given in an url, and urlencoded...
|
||||
// and urlencode transforms utf-8 into something similar to ISO-8859-1
|
||||
// Example: é (C3A9 becomes %E9)
|
||||
// As a consequence, json_encode (called within open-flash-chart.php)
|
||||
// was returning 'null' and the graph was not displayed at all
|
||||
// To make sure that the graph is displayed AND to get a correct title
|
||||
// (at least for european characters) let's transform back into utf-8 !
|
||||
$sTitle = iconv("ISO-8859-1", "UTF-8//IGNORE", $aExtraParams['chart_title']);
|
||||
|
||||
// If the title is a dictionnary entry, fetch it
|
||||
$sTitle = Dict::S($sTitle);
|
||||
|
||||
$oTitle = new title($sTitle);
|
||||
$oTitle = new title( Dict::S($aExtraParams['chart_title']) );
|
||||
$oChart->set_title( $oTitle );
|
||||
}
|
||||
$oChart->set_bg_colour('#FFFFFF');
|
||||
@@ -1030,15 +929,6 @@ EOF
|
||||
*/
|
||||
protected function AddCondition($sFilterCode, $condition)
|
||||
{
|
||||
// Workaround to an issue revealed whenever a condition on org_id is applied twice (with a hierarchy of organizations)
|
||||
// Moreover, it keeps the query as simple as possible
|
||||
if (isset($this->m_aConditions[$sFilterCode]) && $condition == $this->m_aConditions[$sFilterCode])
|
||||
{
|
||||
// Skip
|
||||
return;
|
||||
}
|
||||
$this->m_aConditions[$sFilterCode] = $condition;
|
||||
|
||||
$sClass = $this->m_oFilter->GetClass();
|
||||
$bConditionAdded = false;
|
||||
|
||||
@@ -1155,13 +1045,8 @@ class HistoryBlock extends DisplayBlock
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the 'Actions' menu for a given (list of) object(s)
|
||||
* The 'style' of the list (see constructor of DisplayBlock) can be either 'list' or 'details'
|
||||
* For backward compatibility 'popup' is equivalent to 'list'...
|
||||
*/
|
||||
class MenuBlock extends DisplayBlock
|
||||
{
|
||||
{
|
||||
/**
|
||||
* Renders the "Actions" popup menu for the given set of objects
|
||||
*
|
||||
@@ -1173,10 +1058,6 @@ class MenuBlock extends DisplayBlock
|
||||
*/
|
||||
public function GetRenderContent(WebPage $oPage, $aExtraParams = array(), $sId)
|
||||
{
|
||||
if ($this->m_sStyle == 'popup') // popup is a synonym of 'list' for backward compatibility
|
||||
{
|
||||
$this->m_sStyle = 'list';
|
||||
}
|
||||
$sHtml = '';
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sContext = $oAppContext->GetForLink();
|
||||
@@ -1187,7 +1068,7 @@ class MenuBlock extends DisplayBlock
|
||||
$sClass = $this->m_oFilter->GetClass();
|
||||
$oSet = new CMDBObjectSet($this->m_oFilter);
|
||||
$sFilter = $this->m_oFilter->serialize();
|
||||
$sFilterDesc = $this->m_oFilter->ToOql(true);
|
||||
$sFilterDesc = $this->m_oFilter->ToOql();
|
||||
$aActions = array();
|
||||
$sUIPage = cmdbAbstractObject::ComputeStandardUIPage($sClass);
|
||||
$sRootUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
@@ -1204,7 +1085,7 @@ class MenuBlock extends DisplayBlock
|
||||
$sDefault.= "&default[$sKey]=$sValue";
|
||||
}
|
||||
}
|
||||
$bIsCreationAllowed = (UserRights::IsActionAllowed($sClass, UR_ACTION_CREATE) == UR_ALLOWED_YES);
|
||||
$bIsCreationAllowed = (UserRights::IsActionAllowed($sClass, UR_ACTION_MODIFY) == UR_ALLOWED_YES);
|
||||
switch($oSet->Count())
|
||||
{
|
||||
case 0:
|
||||
@@ -1259,14 +1140,7 @@ class MenuBlock extends DisplayBlock
|
||||
// Static menus: Email this page & CSV Export
|
||||
$sUrl = ApplicationContext::MakeObjectUrl($sClass, $id);
|
||||
$aActions['UI:Menu:EMail'] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=".urlencode($oObj->GetRawName())."&body=".urlencode($sUrl));
|
||||
$aActions['UI:Menu:CSVExport'] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."&format=csv{$sContext}");
|
||||
// The style tells us whether the menu is displayed on a list of one object, or on the details of the given object
|
||||
if ($this->m_sStyle == 'list')
|
||||
{
|
||||
// Actions specific to the list
|
||||
$sOQL = addslashes($sFilterDesc);
|
||||
$aActions['UI:Menu:AddToDashboard'] = array ('label' => Dict::S('UI:Menu:AddToDashboard'), 'url' => "#", 'onclick' => "return DashletCreationDlg('$sOQL')");
|
||||
}
|
||||
$aActions['UI:Menu:CSVExport'] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=search&filter=$sFilter&format=csv{$sContext}");
|
||||
}
|
||||
$this->AddMenuSeparator($aActions);
|
||||
foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance)
|
||||
@@ -1300,12 +1174,15 @@ class MenuBlock extends DisplayBlock
|
||||
{
|
||||
// many objects in the set, possible actions are: new / modify all / delete all
|
||||
if ($bIsCreationAllowed) { $aActions['UI:Menu:New'] = array ('label' => Dict::S('UI:Menu:New'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=new&class=$sClass{$sContext}{$sDefault}"); }
|
||||
if ($bIsBulkModifyAllowed) { $aActions['UI:Menu:ModifyAll'] = array ('label' => Dict::S('UI:Menu:ModifyAll'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=select_for_modify_all&class=$sClass&filter=".urlencode($sFilter)."{$sContext}"); }
|
||||
if ($bIsBulkDeleteAllowed) { $aActions['UI:Menu:BulkDelete'] = array ('label' => Dict::S('UI:Menu:BulkDelete'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=select_for_deletion&filter=".urlencode($sFilter)."{$sContext}"); }
|
||||
if ($bIsBulkModifyAllowed) { $aActions['UI:Menu:ModifyAll'] = array ('label' => Dict::S('UI:Menu:ModifyAll'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=select_for_modify_all&class=$sClass&filter=$sFilter{$sContext}"); }
|
||||
if ($bIsBulkDeleteAllowed) { $aActions['UI:Menu:BulkDelete'] = array ('label' => Dict::S('UI:Menu:BulkDelete'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=select_for_deletion&filter=$sFilter{$sContext}"); }
|
||||
|
||||
// Stimuli
|
||||
$aStates = MetaModel::EnumStates($sClass);
|
||||
if (count($aStates) > 0)
|
||||
// Do not perform time consuming computations if there are too may objects in the list
|
||||
$iLimit = MetaModel::GetConfig()->Get('complex_actions_limit');
|
||||
|
||||
if ((count($aStates) > 0) && (($iLimit == 0) || ($oSet->Count() < $iLimit)))
|
||||
{
|
||||
// Life cycle actions may be available... if all objects are in the same state
|
||||
$oSet->Rewind();
|
||||
@@ -1332,7 +1209,7 @@ class MenuBlock extends DisplayBlock
|
||||
{
|
||||
case UR_ALLOWED_YES:
|
||||
case UR_ALLOWED_DEPENDS:
|
||||
$aActions[$sStimulusCode] = array('label' => $aStimuli[$sStimulusCode]->GetLabel(), 'url' => "{$sRootUrl}pages/UI.php?operation=select_bulk_stimulus&stimulus=$sStimulusCode&state=$sState&class=$sClass&filter=".urlencode($sFilter)."{$sContext}");
|
||||
$aActions[$sStimulusCode] = array('label' => $aStimuli[$sStimulusCode]->GetLabel(), 'url' => "{$sRootUrl}pages/UI.php?operation=select_bulk_stimulus&stimulus=$sStimulusCode&state=$sState&class=$sClass&filter=$sFilter{$sContext}");
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1344,48 +1221,18 @@ class MenuBlock extends DisplayBlock
|
||||
}
|
||||
$this->AddMenuSeparator($aActions);
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
$aActions['UI:Menu:EMail'] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=$sFilterDesc&body=".urlencode("{$sUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."{$sContext}"));
|
||||
$aActions['UI:Menu:CSVExport'] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=search&filter=".urlencode($sFilter)."&format=csv{$sContext}");
|
||||
$sOQL = addslashes($sFilterDesc);
|
||||
$aActions['UI:Menu:AddToDashboard'] = array ('label' => Dict::S('UI:Menu:AddToDashboard'), 'url' => "#", 'onclick' => "return DashletCreationDlg('$sOQL')");
|
||||
$aActions['UI:Menu:EMail'] = array ('label' => Dict::S('UI:Menu:EMail'), 'url' => "mailto:?subject=$sFilterDesc&body=".urlencode("{$sUrl}pages/$sUIPage?operation=search&filter=$sFilter{$sContext}"));
|
||||
$aActions['UI:Menu:CSVExport'] = array ('label' => Dict::S('UI:Menu:CSVExport'), 'url' => "{$sRootUrl}pages/$sUIPage?operation=search&filter=$sFilter&format=csv{$sContext}");
|
||||
}
|
||||
$this->AddMenuSeparator($aActions);
|
||||
foreach (MetaModel::EnumPlugins('iApplicationUIExtension') as $oExtensionInstance)
|
||||
{
|
||||
$oSet->Rewind();
|
||||
foreach($oExtensionInstance->EnumAllowedActions($oSet) as $sLabel => $data)
|
||||
foreach($oExtensionInstance->EnumAllowedActions($oSet) as $sLabel => $sUrl)
|
||||
{
|
||||
if (is_array($data))
|
||||
{
|
||||
// New plugins can provide javascript handlers via the 'onclick' property
|
||||
//TODO: enable extension of different menus by checking the 'target' property ??
|
||||
$aActions[$sLabel] = array ('label' => $sLabel, 'url' => isset($data['url']) ? $data['url'] : '#', 'onclick' => isset($data['onclick']) ? $data['onclick'] : '');
|
||||
}
|
||||
else
|
||||
{
|
||||
// Backward compatibility with old plugins
|
||||
$aActions[$sLabel] = array ('label' => $sLabel, 'url' => $data);
|
||||
}
|
||||
$aActions[$sLabel] = array ('label' => $sLabel, 'url' => $sUrl);
|
||||
}
|
||||
}
|
||||
|
||||
// New extensions based on iPopupMenuItem interface
|
||||
switch($this->m_sStyle)
|
||||
{
|
||||
case 'list':
|
||||
$oSet->Rewind();
|
||||
$param = $oSet;
|
||||
$iMenuId = iPopupMenuExtension::MENU_OBJLIST_ACTIONS;
|
||||
break;
|
||||
|
||||
case 'details':
|
||||
$oSet->Rewind();
|
||||
$param = $oSet->Fetch();
|
||||
$iMenuId = iPopupMenuExtension::MENU_OBJDETAILS_ACTIONS;
|
||||
break;
|
||||
|
||||
}
|
||||
utils::GetPopupMenuItems($oPage, $iMenuId, $param, $aActions);
|
||||
}
|
||||
$aFavoriteActions = array();
|
||||
$aCallSpec = array($sClass, 'GetShortcutActions');
|
||||
@@ -1408,15 +1255,42 @@ class MenuBlock extends DisplayBlock
|
||||
|
||||
if (count($aFavoriteActions) > 0)
|
||||
{
|
||||
$sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li>".Dict::S('UI:Menu:OtherActions')."\n<ul>\n";
|
||||
$sHtml .= "<div class=\"itop_popup\"><ul>\n<li>".Dict::S('UI:Menu:OtherActions')."\n<ul>\n";
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHtml .= "<div class=\"itop_popup actions_menu\"><ul>\n<li>".Dict::S('UI:Menu:Actions')."\n<ul>\n";
|
||||
$sHtml .= "<div class=\"itop_popup\"><ul>\n<li>".Dict::S('UI:Menu:Actions')."\n<ul>\n";
|
||||
}
|
||||
$sPrevUrl = '';
|
||||
foreach ($aActions as $key => $aAction)
|
||||
{
|
||||
if (in_array($key, $aShortcutActions))
|
||||
{
|
||||
$aFavoriteActions[] = $aAction;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sClass = isset($aAction['class']) ? " class=\"{$aAction['class']}\"" : "";
|
||||
if (empty($aAction['url']))
|
||||
{
|
||||
if ($sPrevUrl != '') // Don't output consecutively two separators...
|
||||
{
|
||||
$sHtml .= "<li>{$aAction['label']}</li>\n";
|
||||
}
|
||||
$sPrevUrl = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHtml .= "<li><a href=\"{$aAction['url']}\"$sClass>{$aAction['label']}</a></li>\n";
|
||||
$sPrevUrl = $aAction['url'];
|
||||
}
|
||||
}
|
||||
}
|
||||
$sHtml .= "</ul>\n</li>\n</ul></div>";
|
||||
foreach(array_reverse($aFavoriteActions) as $aAction)
|
||||
{
|
||||
$sHtml .= "<div class=\"actions_button\"><a href='{$aAction['url']}'>{$aAction['label']}</a></div>";
|
||||
}
|
||||
|
||||
$sHtml .= $oPage->RenderPopupMenuItems($aActions, $aFavoriteActions);
|
||||
|
||||
static $bPopupScript = false;
|
||||
if (!$bPopupScript)
|
||||
{
|
||||
@@ -1446,87 +1320,4 @@ class MenuBlock extends DisplayBlock
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Some dummy menus for testing
|
||||
*/
|
||||
class ExtraMenus implements iPopupMenuExtension
|
||||
{
|
||||
/*
|
||||
const MENU_OBJLIST_ACTIONS = 1; // $param is a DBObjectSet containing the list of objects
|
||||
const MENU_OBJLIST_TOOLKIT = 2; // $param is a DBObjectSet containing the list of objects
|
||||
const MENU_OBJDETAILS_ACTIONS = 3; // $param is a DBObject instance: the object currently displayed
|
||||
const MENU_DASHBOARD_ACTIONS = 4; // $param is a Dashboard instance: the dashboard currently displayed
|
||||
const MENU_USER_ACTIONS = 5; // $param is a null ??
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get the list of items to be added to a menu. The items will be inserted in the menu in the order of the returned array
|
||||
* @param int $iMenuId The identifier of the type of menu, as listed by the constants MENU_xxx above
|
||||
* @param mixed $param Depends on $iMenuId see the constants define above
|
||||
* @return Array An array of ApplicationPopupMenuItem or an empty array if no action is to be added to the menu
|
||||
*/
|
||||
public static function EnumItems($iMenuId, $param)
|
||||
{
|
||||
switch($iMenuId)
|
||||
{
|
||||
/*
|
||||
case iPopupMenuExtension::MENU_OBJLIST_ACTIONS:
|
||||
// $param is a DBObjectSet
|
||||
$aResult = array(
|
||||
new JSPopupMenuItem('Test::Item1', 'List Test 1', "alert('Test 1')"),
|
||||
new JSPopupMenuItem('Test::Item2', 'List Test 2', "alert('Test 2')"),
|
||||
);
|
||||
break;
|
||||
|
||||
case iPopupMenuExtension::MENU_OBJLIST_TOOLKIT:
|
||||
// $param is a DBObjectSet
|
||||
$aResult = array(
|
||||
new JSPopupMenuItem('Test::Item1', 'Toolkit Test 1', "alert('Test 1')"),
|
||||
new JSPopupMenuItem('Test::Item2', 'Toolkit Test 2', "alert('Test 2')"),
|
||||
);
|
||||
break;
|
||||
|
||||
case iPopupMenuExtension::MENU_OBJDETAILS_ACTIONS:
|
||||
// $param is a DBObject
|
||||
$aResult = array(
|
||||
new JSPopupMenuItem('Test::Item1', 'Object Test 1', "alert('Test 1')"),
|
||||
new JSPopupMenuItem('Test::Item2', 'Object Test 2', "alert('Test 2')"),
|
||||
);
|
||||
break;
|
||||
*/
|
||||
|
||||
case iPopupMenuExtension::MENU_DASHBOARD_ACTIONS:
|
||||
// $param is a Dashboard
|
||||
$oAppContext = new ApplicationContext();
|
||||
$aParams = $oAppContext->GetAsHash();
|
||||
$sMenuId = ApplicationMenu::GetActiveNodeId();
|
||||
$sDlgTitle = addslashes(Dict::S('UI:ImportDashboardTitle'));
|
||||
$sDlgText = addslashes(Dict::S('UI:ImportDashboardText'));
|
||||
$sCloseBtn = addslashes(Dict::S('UI:Button:Cancel'));
|
||||
$aResult = array(
|
||||
new SeparatorPopupMenuItem(),
|
||||
new URLPopupMenuItem('UI:ExportDashboard', Dict::S('UI:ExportDashBoard'), utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=export_dashboard&id='.$sMenuId),
|
||||
new JSPopupMenuItem('UI:ImportDashboard', Dict::S('UI:ImportDashBoard'), "UploadDashboard({dashboard_id: '$sMenuId', title: '$sDlgTitle', text: '$sDlgText', close_btn: '$sCloseBtn' })",
|
||||
array('../js/ajaxfileupload.js')),
|
||||
);
|
||||
break;
|
||||
|
||||
/*
|
||||
case iPopupMenuExtension::MENU_USER_ACTIONS:
|
||||
// $param is null ??
|
||||
$aResult = array(
|
||||
new SeparatorPopupMenuItem(),
|
||||
new JSPopupMenuItem('Test::Item1', 'Reset preferences...', "alert('Test 1')"),
|
||||
new JSPopupMenuItem('Test::Item2', 'Do Something Stupid', "alert('Hey Dude !')"),
|
||||
);
|
||||
break;
|
||||
*/
|
||||
|
||||
default:
|
||||
// Unknown type of menu, do nothing
|
||||
$aResult = array();
|
||||
}
|
||||
return $aResult;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,26 +1,26 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
* Class iTopWebPage
|
||||
*
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
require_once(APPROOT."/application/nicewebpage.class.inc.php");
|
||||
@@ -50,36 +50,30 @@ class iTopWebPage extends NiceWebPage
|
||||
$this->m_aTabs = array();
|
||||
$this->m_sMenu = "";
|
||||
$this->m_sMessage = '';
|
||||
$this->SetRootUrl(utils::GetAbsoluteUrlAppRoot());
|
||||
$sAbsURLAppRoot = addslashes(utils::GetAbsoluteUrlAppRoot()); // Pass it to Javascript scripts
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sExtraParams = $oAppContext->GetForLink();
|
||||
$sAppContext = addslashes($sExtraParams);
|
||||
$this->add_header("Content-type: text/html; charset=utf-8");
|
||||
$this->add_header("Cache-control: no-cache");
|
||||
$this->add_linked_stylesheet("../css/jquery.treeview.css");
|
||||
$this->add_linked_stylesheet("../css/jquery.autocomplete.css");
|
||||
$this->add_linked_stylesheet("../css/fg.menu.css");
|
||||
$this->add_linked_script('../js/jquery.layout.min.js');
|
||||
$this->add_linked_script('../js/jquery.ba-bbq.min.js');
|
||||
$this->add_linked_script("../js/jquery.tablehover.js");
|
||||
$this->add_linked_script("../js/jquery.treeview.js");
|
||||
$this->add_linked_script("../js/jquery.autocomplete.js");
|
||||
$this->add_linked_script("../js/jquery.positionBy.js");
|
||||
$this->add_linked_script("../js/jquery.popupmenu.js");
|
||||
$this->add_linked_script("../js/date.js");
|
||||
$this->add_linked_script("../js/jquery.tablesorter.min.js");
|
||||
$this->add_linked_script("../js/jquery.blockUI.js");
|
||||
$this->add_linked_script("../js/utils.js");
|
||||
$this->add_linked_script("../js/swfobject.js");
|
||||
$this->add_linked_script("../js/ckeditor/ckeditor.js");
|
||||
$this->add_linked_script("../js/ckeditor/adapters/jquery.js");
|
||||
$this->add_linked_script("../js/jquery.qtip-1.0.min.js");
|
||||
$this->add_linked_script('../js/property_field.js');
|
||||
$this->add_linked_script('../js/fg.menu.js');
|
||||
$this->add_linked_script('../js/icon_select.js');
|
||||
$this->add_linked_script('../js/raphael-min.js');
|
||||
$this->add_linked_script('../js/g.raphael.js');
|
||||
$this->add_linked_script('../js/g.pie.js');
|
||||
$this->add_linked_script('../js/g.dot.js');
|
||||
$this->add_linked_script('../js/charts.js');
|
||||
$this->add_linked_script('../js/field_sorter.js');
|
||||
$this->add_linked_script('../js/datatable.js');
|
||||
|
||||
$this->add_linked_script("../js/jquery.tablesorter.pager.js");
|
||||
$this->m_sInitScript =
|
||||
<<< EOF
|
||||
try
|
||||
@@ -89,56 +83,54 @@ class iTopWebPage extends NiceWebPage
|
||||
// Layout
|
||||
paneSize = GetUserPreference('menu_size', 300)
|
||||
myLayout = $('body').layout({
|
||||
west : {
|
||||
minSize: 200, size: paneSize, spacing_open: 16, spacing_close: 16, slideTrigger_open: "mouseover", hideTogglerOnSlide: true, enableCursorHotkey: false,
|
||||
onclose_end: function(name, elt, state, options, layout)
|
||||
{
|
||||
if (state.isSliding == false)
|
||||
{
|
||||
SetUserPreference('menu_pane', 'closed', true);
|
||||
}
|
||||
},
|
||||
onresize_end: function(name, elt, state, options, layout)
|
||||
{
|
||||
if (state.isSliding == false)
|
||||
{
|
||||
SetUserPreference('menu_size', state.size, true);
|
||||
}
|
||||
},
|
||||
|
||||
onopen_end: function(name, elt, state, options, layout)
|
||||
{
|
||||
if (state.isSliding == false)
|
||||
{
|
||||
SetUserPreference('menu_pane', 'open', true);
|
||||
}
|
||||
}
|
||||
west : {
|
||||
minSize: 200, size: paneSize, spacing_open: 16, spacing_close: 16, slideTrigger_open: "mouseover", hideTogglerOnSlide: true,
|
||||
onclose_end: function(name, elt, state, options, layout)
|
||||
{
|
||||
if (state.isSliding == false)
|
||||
{
|
||||
SetUserPreference('menu_pane', 'closed', true);
|
||||
}
|
||||
},
|
||||
onresize_end: function(name, elt, state, options, layout)
|
||||
{
|
||||
if (state.isSliding == false)
|
||||
{
|
||||
SetUserPreference('menu_size', state.size, true);
|
||||
}
|
||||
},
|
||||
|
||||
onopen_end: function(name, elt, state, options, layout)
|
||||
{
|
||||
if (state.isSliding == false)
|
||||
{
|
||||
SetUserPreference('menu_pane', 'open', true);
|
||||
}
|
||||
}
|
||||
},
|
||||
center: {
|
||||
onresize_end: function(name, elt, state, options, layout)
|
||||
{
|
||||
$('.v-resizable').each( function() {
|
||||
var fixedWidth = $(this).parent().innerWidth() - 6;
|
||||
$(this).width(fixedWidth);
|
||||
// Make sure it cannot be resized horizontally
|
||||
$(this).resizable('options', { minWidth: fixedWidth, maxWidth: fixedWidth });
|
||||
center: {
|
||||
onresize_end: function(name, elt, state, options, layout)
|
||||
{
|
||||
$('.v-resizable').each( function() {
|
||||
var fixedWidth = $(this).parent().innerWidth() - 6;
|
||||
$(this).width(fixedWidth);
|
||||
// Make sure it cannot be resized horizontally
|
||||
$(this).resizable('options', { minWidth: fixedWidth, maxWidth: fixedWidth });
|
||||
// Now adjust all the child 'items'
|
||||
var innerWidth = $(this).innerWidth() - 10;
|
||||
$(this).find('.item').width(innerWidth);
|
||||
});
|
||||
}
|
||||
var innerWidth = $(this).innerWidth() - 10;
|
||||
$(this).find('.item').width(innerWidth);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
});
|
||||
myLayout.addPinBtn( "#tPinMenu", "west" );
|
||||
//myLayout.open( "west" );
|
||||
$('.ui-layout-resizer-west .ui-layout-toggler').css({background: 'transparent'});
|
||||
$('.ui-layout-resizer-west').html('<img src="../images/splitter-top-corner.png"/>');
|
||||
if (GetUserPreference('menu_pane', 'open') == 'closed')
|
||||
{
|
||||
myLayout.close('west');
|
||||
}
|
||||
|
||||
$('#left-pane').layout({ resizable: false, spacing_open: 0, south: { size: 94 }, enableCursorHotkey: false });
|
||||
|
||||
// Accordion Menu
|
||||
$("#accordion").accordion({ header: "h3", navigation: true, autoHeight: false, collapsible: false, icons: false }); // collapsible will be enabled once the item will be selected
|
||||
@@ -146,7 +138,7 @@ class iTopWebPage extends NiceWebPage
|
||||
// Tabs, using JQuery BBQ to store the history
|
||||
// The "tab widgets" to handle.
|
||||
var tabs = $('div[id^=tabbedContent]');
|
||||
|
||||
|
||||
// This selector will be reused when selecting actual tab widget A elements.
|
||||
var tab_a_selector = 'ul.ui-tabs-nav a';
|
||||
|
||||
@@ -170,7 +162,47 @@ EOF
|
||||
;
|
||||
$this->add_ready_script(
|
||||
<<< EOF
|
||||
//add new widget called TruncatedList to properly display truncated lists when they are sorted
|
||||
$.tablesorter.addWidget({
|
||||
// give the widget a id
|
||||
id: "truncatedList",
|
||||
// format is called when the on init and when a sorting has finished
|
||||
format: function(table)
|
||||
{
|
||||
// Check if there is a "truncated" line
|
||||
this.truncatedList = false;
|
||||
if ($("tr td.truncated",table).length > 0)
|
||||
{
|
||||
this.truncatedList = true;
|
||||
}
|
||||
if (this.truncatedList)
|
||||
{
|
||||
$("tr td",table).removeClass('truncated');
|
||||
$("tr:last td",table).addClass('truncated');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
$.tablesorter.addWidget({
|
||||
// give the widget a id
|
||||
id: "myZebra",
|
||||
// format is called when the on init and when a sorting has finished
|
||||
format: function(table)
|
||||
{
|
||||
// Replace the 'red even' lines by 'red_even' since most browser do not support 2 classes selector in CSS, etc..
|
||||
$("tbody tr:even",table).addClass('even');
|
||||
$("tbody tr.red:even",table).removeClass('red').removeClass('even').addClass('red_even');
|
||||
$("tbody tr.orange:even",table).removeClass('orange').removeClass('even').addClass('orange_even');
|
||||
$("tbody tr.green:even",table).removeClass('green').removeClass('even').addClass('green_even');
|
||||
// In case we sort again the table, we need to remove the added 'even' classes on odd rows
|
||||
$("tbody tr:odd",table).removeClass('even');
|
||||
$("tbody tr.red_even:odd",table).removeClass('even').removeClass('red_even').addClass('red');
|
||||
$("tbody tr.orange_even:odd",table).removeClass('even').removeClass('orange_even').addClass('orange');
|
||||
$("tbody tr.green_even:odd",table).removeClass('even').removeClass('green_even').addClass('green');
|
||||
}
|
||||
});
|
||||
|
||||
// Adjust initial size
|
||||
$('.v-resizable').each( function()
|
||||
{
|
||||
@@ -206,7 +238,7 @@ EOF
|
||||
// Tabs, using JQuery BBQ to store the history
|
||||
// The "tab widgets" to handle.
|
||||
var tabs = $('div[id^=tabbedContent]');
|
||||
|
||||
|
||||
// This selector will be reused when selecting actual tab widget A elements.
|
||||
var tab_a_selector = 'ul.ui-tabs-nav a';
|
||||
|
||||
@@ -275,7 +307,7 @@ EOF
|
||||
});
|
||||
|
||||
// End of Tabs handling
|
||||
|
||||
$("table.listResults").tableHover(); // hover tables
|
||||
$(".date-pick").datepicker({
|
||||
showOn: 'button',
|
||||
buttonImage: '../images/calendar.png',
|
||||
@@ -302,13 +334,13 @@ EOF
|
||||
{
|
||||
var aSerialized = sTemp.split(',');
|
||||
var sortable = $(this);
|
||||
$.each(aSerialized, function(i,v) {
|
||||
var item = $('#menu_'+v);
|
||||
if (item.length > 0) // Check that the menu exists
|
||||
{
|
||||
sortable.append(item);
|
||||
}
|
||||
});
|
||||
$.each(aSerialized, function(i,v) {
|
||||
var item = $('#menu_'+v);
|
||||
if (item.length > 0) // Check that the menu exists
|
||||
{
|
||||
sortable.append(item);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -379,24 +411,59 @@ EOF
|
||||
}
|
||||
}
|
||||
|
||||
function GetAbsoluteUrlAppRoot()
|
||||
{
|
||||
return '$sAbsURLAppRoot';
|
||||
}
|
||||
|
||||
function GetAbsoluteUrlModulesRoot()
|
||||
{
|
||||
return '$sAbsURLAppRoot'+'modules/';
|
||||
}
|
||||
|
||||
function AddAppContext(sURL)
|
||||
{
|
||||
var sContext = '$sAppContext';
|
||||
if (sContext.length > 0)
|
||||
{
|
||||
if (sURL.indexOf('?') == -1)
|
||||
{
|
||||
return sURL+'?'+sContext;
|
||||
}
|
||||
return sURL+'&'+sContext;
|
||||
}
|
||||
return sURL;
|
||||
}
|
||||
|
||||
var oUserPreferences = $sUserPrefs;
|
||||
|
||||
// For disabling the CKEditor at init time when the corresponding textarea is disabled !
|
||||
CKEDITOR.plugins.add( 'disabler',
|
||||
{
|
||||
init : function( editor )
|
||||
{
|
||||
editor.on( 'instanceReady', function(e)
|
||||
{
|
||||
e.removeListener();
|
||||
$('#'+ editor.name).trigger('update');
|
||||
});
|
||||
}
|
||||
|
||||
init : function( editor )
|
||||
{
|
||||
editor.on( 'instanceReady', function(e)
|
||||
{
|
||||
e.removeListener();
|
||||
$('#'+ editor.name).trigger('update');
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
EOF
|
||||
);
|
||||
|
||||
// Build menus from module handlers
|
||||
//
|
||||
foreach(get_declared_classes() as $sPHPClass)
|
||||
{
|
||||
if (is_subclass_of($sPHPClass, 'ModuleHandlerAPI'))
|
||||
{
|
||||
$aCallSpec = array($sPHPClass, 'OnMenuCreation');
|
||||
call_user_func($aCallSpec);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function AddToMenu($sHtml)
|
||||
@@ -430,35 +497,53 @@ EOF
|
||||
switch($iCount)
|
||||
{
|
||||
case 0:
|
||||
// No such dimension/silo => nothing to select
|
||||
$sHtml = '<div id="SiloSelection"><!-- nothing to select --></div>';
|
||||
break;
|
||||
// No such dimension/silo => nothing to select
|
||||
$sHtml = '<div id="SiloSelection"><!-- nothing to select --></div>';
|
||||
break;
|
||||
|
||||
case 1:
|
||||
// Only one possible choice... no selection, but display the value
|
||||
$oOrg = $oSet->Fetch();
|
||||
$sHtml = '<div id="SiloSelection">'.$oOrg->GetName().'</div>';
|
||||
$sHtml .= '';
|
||||
break;
|
||||
// Only one possible choice... no selection, but display the value
|
||||
$oOrg = $oSet->Fetch();
|
||||
$sHtml = '<div id="SiloSelection">'.$oOrg->GetName().'</div>';
|
||||
$sHtml .= '';
|
||||
break;
|
||||
|
||||
default:
|
||||
$sHtml = '';
|
||||
$oAppContext = new ApplicationContext();
|
||||
$iCurrentOrganization = $oAppContext->GetCurrentValue('org_id');
|
||||
$sHtml = '<div id="SiloSelection">';
|
||||
$sHtml .= '<form style="display:inline" action="'.utils::GetAbsoluteUrlAppRoot().'pages/UI.php">'; //<select class="org_combo" name="c[org_id]" title="Pick an organization" onChange="this.form.submit();">';
|
||||
|
||||
$sFavoriteOrgs = '';
|
||||
$oWidget = new UIExtKeyWidget('Organization', 'org_id', '', true /* search mode */);
|
||||
$sHtml .= $oWidget->Display($this, 50, false, '', $oSet, $iCurrentOrganization, 'org_id', false, 'c[org_id]', '', array('iFieldSize' => 20, 'iMinChars' => MetaModel::GetConfig()->Get('min_autocomplete_chars'), 'sDefaultValue' => Dict::S('UI:AllOrganizations')));
|
||||
$this->add_ready_script('$("#org_id").bind("extkeychange", function() { $("#SiloSelection form").submit(); } )');
|
||||
$this->add_ready_script("$('#label_org_id').click( function() { $(this).val(''); $('#org_id').val(''); return true; } );\n");
|
||||
// Add other dimensions/context information to this form
|
||||
$oAppContext->Reset('org_id'); // org_id is handled above and we want to be able to change it here !
|
||||
$oAppContext->Reset('menu'); // don't pass the menu, since a menu may expect more parameters
|
||||
$sHtml .= $oAppContext->GetForForm(); // Pass what remains, if anything...
|
||||
$sHtml .= '</form>';
|
||||
$sHtml .= '</div>';
|
||||
$sHtml = '';
|
||||
$oAppContext = new ApplicationContext();
|
||||
$iCurrentOrganization = $oAppContext->GetCurrentValue('org_id');
|
||||
$sHtml = '<div id="SiloSelection">';
|
||||
$sHtml .= '<form style="display:inline" action="'.utils::GetAbsoluteUrlAppRoot().'pages/UI.php">'; //<select class="org_combo" name="c[org_id]" title="Pick an organization" onChange="this.form.submit();">';
|
||||
/*
|
||||
$sSelected = ($iCurrentOrganization == '') ? ' selected' : '';
|
||||
$sHtml .= '<option value=""'.$sSelected.'>'.Dict::S('UI:AllOrganizations').'</option>';
|
||||
while($oOrg = $oSet->Fetch())
|
||||
{
|
||||
if ($iCurrentOrganization == $oOrg->GetKey())
|
||||
{
|
||||
// $oCurrentOrganization = $oOrg;
|
||||
$sSelected = " selected";
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSelected = "";
|
||||
}
|
||||
$sHtml .= '<option title="'.$oOrg->GetName().'" value="'.$oOrg->GetKey().'"'.$sSelected.'>'.$oOrg->GetName().'</option>';
|
||||
}
|
||||
$sHtml .= '</select>';
|
||||
*/
|
||||
$sFavoriteOrgs = '';
|
||||
$oWidget = new UIExtKeyWidget('Organization', 'org_id', '', true /* search mode */);
|
||||
$sHtml .= $oWidget->Display($this, 50, false, '', $oSet, $iCurrentOrganization, 'org_id', false, 'c[org_id]', '', array('iFieldSize' => 20, 'iMinChars' => MetaModel::GetConfig()->Get('min_autocomplete_chars'), 'sDefaultValue' => Dict::S('UI:AllOrganizations')));
|
||||
$this->add_ready_script('$("#org_id").bind("extkeychange", function() { $("#SiloSelection form").submit(); } )');
|
||||
$this->add_ready_script("$('#label_org_id').click( function() { $(this).val(''); $('#org_id').val(''); return true; } );\n");
|
||||
// Add other dimensions/context information to this form
|
||||
$oAppContext->Reset('org_id'); // org_id is handled above and we want to be able to change it here !
|
||||
$oAppContext->Reset('menu'); // don't pass the menu, since a menu may expect more parameters
|
||||
$sHtml .= $oAppContext->GetForForm(); // Pass what remains, if anything...
|
||||
$sHtml .= '</form>';
|
||||
$sHtml .= '</div>';
|
||||
}
|
||||
return $sHtml;
|
||||
}
|
||||
@@ -477,21 +562,19 @@ EOF
|
||||
*/
|
||||
public function output()
|
||||
{
|
||||
$sAbsURLAppRoot = addslashes($this->m_sRootUrl);
|
||||
|
||||
//$this->set_base($this->m_sRootUrl.'pages/');
|
||||
$sForm = $this->GetSiloSelectionForm();
|
||||
$this->DisplayMenu(); // Compute the menu
|
||||
|
||||
// Put here the 'ready scripts' that must be executed after all others
|
||||
$this->add_ready_script(
|
||||
<<<EOF
|
||||
// Since the event is only triggered when the hash changes, we need to trigger
|
||||
// the event now, to handle the hash the page may have loaded with.
|
||||
$(window).trigger( 'hashchange' );
|
||||
|
||||
// Some table are sort-able, some are not, let's fix this
|
||||
$('table.listResults').each( function() { FixTableSorter($(this)); } );
|
||||
// Since the event is only triggered when the hash changes, we need to trigger
|
||||
// the event now, to handle the hash the page may have loaded with.
|
||||
$(window).trigger( 'hashchange' );
|
||||
|
||||
// Some table are sort-able, some are not, let's fix this
|
||||
$('table.listResults').each( function() { FixTableSorter($(this)); } );
|
||||
|
||||
EOF
|
||||
);
|
||||
if ($this->GetOutputFormat() == 'html')
|
||||
@@ -532,17 +615,17 @@ EOF
|
||||
{
|
||||
foreach($this->a_linked_scripts as $s_script)
|
||||
{
|
||||
// Make sure that the URL to the script contains the application's version number
|
||||
// so that the new script do NOT get reloaded from the cache when the application is upgraded
|
||||
if (strpos($s_script, '?') === false)
|
||||
{
|
||||
$s_script .= "?itopversion=".ITOP_VERSION;
|
||||
}
|
||||
else
|
||||
{
|
||||
$s_script .= "&itopversion=".ITOP_VERSION;
|
||||
}
|
||||
$sHtml .= "<script type=\"text/javascript\" src=\"$s_script\"></script>\n";
|
||||
// Make sure that the URL to the script contains the application's version number
|
||||
// so that the new script do NOT get reloaded from the cache when the application is upgraded
|
||||
if (strpos($s_script, '?') === false)
|
||||
{
|
||||
$s_script .= "?itopversion=".ITOP_VERSION;
|
||||
}
|
||||
else
|
||||
{
|
||||
$s_script .= "&itopversion=".ITOP_VERSION;
|
||||
}
|
||||
$sHtml .= "<script type=\"text/javascript\" src=\"$s_script\"></script>\n";
|
||||
}
|
||||
$this->add_script("\$(document).ready(function() {\n{$this->m_sInitScript};\nwindow.setTimeout('onDelayedReady()',10)\n});");
|
||||
if (count($this->m_aReadyScripts)>0)
|
||||
@@ -559,7 +642,7 @@ EOF
|
||||
$sHtml .= "</script>\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (count($this->a_styles)>0)
|
||||
{
|
||||
$sHtml .= "<style>\n";
|
||||
@@ -571,7 +654,7 @@ EOF
|
||||
}
|
||||
$sHtml .= "<link rel=\"search\" type=\"application/opensearchdescription+xml\" title=\"iTop\" href=\"".utils::GetAbsoluteUrlAppRoot()."pages/opensearch.xml.php\" />\n";
|
||||
$sHtml .= "<link rel=\"shortcut icon\" href=\"".utils::GetAbsoluteUrlAppRoot()."images/favicon.ico\" />\n";
|
||||
|
||||
|
||||
$sHtml .= "</head>\n";
|
||||
$sHtml .= "<body>\n";
|
||||
|
||||
@@ -636,8 +719,6 @@ EOF
|
||||
|
||||
if ($this->GetOutputFormat() == 'html')
|
||||
{
|
||||
$oAppContext = new ApplicationContext();
|
||||
|
||||
$sUserName = UserRights::GetUser();
|
||||
$sIsAdmin = UserRights::IsAdministrator() ? '(Administrator)' : '';
|
||||
if (UserRights::IsAdministrator())
|
||||
@@ -650,24 +731,18 @@ EOF
|
||||
}
|
||||
$sLogOffMenu = "<span id=\"logOffBtn\"><ul><li><img src=\"../images/onOffBtn.png\"><ul>";
|
||||
$sLogOffMenu .= "<li><span>$sLogonMessage</span></li>\n";
|
||||
$aActions = array();
|
||||
|
||||
$oPrefs = new URLPopupMenuItem('UI:Preferences', Dict::S('UI:Preferences'), utils::GetAbsoluteUrlAppRoot()."pages/preferences.php?".$oAppContext->GetForLink());
|
||||
$aActions[$oPrefs->GetUID()] = $oPrefs->GetMenuItem();
|
||||
$sLogOffMenu .= "<li><a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/preferences.php\">".Dict::S('UI:Preferences')."</a></li>\n";
|
||||
|
||||
if (utils::CanLogOff())
|
||||
{
|
||||
$oLogOff = new URLPopupMenuItem('UI:LogOffMenu', Dict::S('UI:LogOffMenu'), utils::GetAbsoluteUrlAppRoot().'pages/logoff.php');
|
||||
$aActions[$oLogOff->GetUID()] = $oLogOff->GetMenuItem();
|
||||
//$sLogOffMenu .= "<li><a href=\"../pages/UI.php?loginop=logoff\">".Dict::S('UI:LogOffMenu')."</a></li>\n";
|
||||
$sLogOffMenu .= "<li><a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/logoff.php\">".Dict::S('UI:LogOffMenu')."</a></li>\n";
|
||||
}
|
||||
if (UserRights::CanChangePassword())
|
||||
{
|
||||
$oChangePwd = new URLPopupMenuItem('UI:ChangePwdMenu', Dict::S('UI:ChangePwdMenu'), utils::GetAbsoluteUrlAppRoot().'pages/UI.php?loginop=change_pwd');
|
||||
$aActions[$oChangePwd->GetUID()] = $oChangePwd->GetMenuItem();
|
||||
$sLogOffMenu .= "<li><a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/UI.php?loginop=change_pwd\">".Dict::S('UI:ChangePwdMenu')."</a></li>\n";
|
||||
}
|
||||
utils::GetPopupMenuItems($this, iPopupMenuExtension::MENU_USER_ACTIONS, null, $aActions);
|
||||
$sLogOffMenu .= $this->RenderPopupMenuItems($aActions);
|
||||
|
||||
$sLogOffMenu .= "</ul>\n</li>\n</ul></span>\n";
|
||||
|
||||
$sRestrictions = '';
|
||||
if (!MetaModel::DBHasAccess(ACCESS_ADMIN_WRITE))
|
||||
@@ -682,11 +757,10 @@ EOF
|
||||
$sRestrictions = Dict::S('UI:AccessRO-Users');
|
||||
}
|
||||
|
||||
$sApplicationBanner = '';
|
||||
if (strlen($sRestrictions) > 0)
|
||||
{
|
||||
$sAdminMessage = trim(MetaModel::GetConfig()->Get('access_message'));
|
||||
$sApplicationBanner .= '<div id="admin-banner">';
|
||||
$sApplicationBanner = '<div id="admin-banner">';
|
||||
$sApplicationBanner .= '<img src="../images/locked.png" style="vertical-align:middle;">';
|
||||
$sApplicationBanner .= ' <b>'.$sRestrictions.'</b>';
|
||||
if (strlen($sAdminMessage) > 0)
|
||||
@@ -695,22 +769,13 @@ EOF
|
||||
}
|
||||
$sApplicationBanner .= '</div>';
|
||||
}
|
||||
|
||||
if(strlen($this->m_sMessage))
|
||||
else if(strlen($this->m_sMessage))
|
||||
{
|
||||
$sApplicationBanner .= '<div id="admin-banner"><span style="padding:5px;">'.$this->m_sMessage.'<span></div>';
|
||||
$sApplicationBanner = '<div id="admin-banner"><span style="padding:5px;">'.$this->m_sMessage.'<span></div>';
|
||||
}
|
||||
|
||||
$sEnvironment = utils::GetCurrentEnvironment();
|
||||
$sBackButton = utils::GetEnvironmentBackButton();
|
||||
if($sEnvironment != 'production')
|
||||
else
|
||||
{
|
||||
$sEnvLabel = trim(MetaModel::GetConfig()->Get('app_env_label'));
|
||||
if (strlen($sEnvLabel) == 0)
|
||||
{
|
||||
$sEnvLabel = $sEnvironment;
|
||||
}
|
||||
$sApplicationBanner .= '<div id="admin-banner"><span style="padding:5px;">'.Dict::Format('UI:ApplicationEnvironment', $sEnvLabel).$sBackButton.'<span></div>';
|
||||
$sApplicationBanner = '';
|
||||
}
|
||||
|
||||
$sOnlineHelpUrl = MetaModel::GetConfig()->Get('online_help');
|
||||
@@ -718,16 +783,14 @@ EOF
|
||||
|
||||
$sHtml .= '<div id="left-pane" class="ui-layout-west">';
|
||||
$sHtml .= '<!-- Beginning of the left pane -->';
|
||||
$sHtml .= ' <div class="ui-layout-north">';
|
||||
$sHtml .= ' <div id="header-logo">';
|
||||
$sHtml .= ' <div id="top-left"></div><div id="logo"><a href="http://www.combodo.com/itop"><img src="../images/itop-logo.png" title="'.htmlentities($sVersionString, ENT_QUOTES, 'UTF-8').'" style="border:0; margin-top:16px; margin-right:40px;"/></a></div>';
|
||||
$sHtml .= ' </div>';
|
||||
$sHtml .= ' <div class="header-menu">';
|
||||
$sHtml .= ' <div id="header-logo">';
|
||||
$sHtml .= ' <div id="top-left"></div><div id="logo"><a href="http://www.combodo.com/itop"><img src="../images/itop-logo.png" title="'.htmlentities($sVersionString, ENT_QUOTES, 'UTF-8').'" style="border:0; margin-top:16px; margin-right:40px;"/></a></div>';
|
||||
$sHtml .= ' </div>';
|
||||
$sHtml .= ' <div class="header-menu">';
|
||||
$sHtml .= ' <div class="icon ui-state-default ui-corner-all"><span id="tPinMenu" class="ui-icon ui-icon-pin-w">pin</span></div>';
|
||||
$sHtml .= ' <div style="text-align:center;">'.self::FilterXSS($sForm).'</div>';
|
||||
$sHtml .= ' </div>';
|
||||
$sHtml .= ' </div>';
|
||||
$sHtml .= ' <div id="menu" class="ui-layout-center">';
|
||||
$sHtml .= ' </div>';
|
||||
$sHtml .= ' <div id="menu" class="ui-layout-content">';
|
||||
$sHtml .= ' <div id="inner_menu">';
|
||||
$sHtml .= ' <div id="accordion">';
|
||||
$sHtml .= self::FilterXSS($this->m_sMenu);
|
||||
@@ -735,25 +798,25 @@ EOF
|
||||
$sHtml .= ' <!-- End of the accordion menu-->';
|
||||
$sHtml .= ' </div>';
|
||||
$sHtml .= ' </div> <!-- /inner menu -->';
|
||||
$sHtml .= ' </div> <!-- /menu -->';
|
||||
$sHtml .= ' <div class="footer ui-layout-south"><a href="http://www.combodo.com" title="www.combodo.com" target="_blank"><img src="../images/logo-combodo.png"/></a></div>';
|
||||
$sHtml .= ' </div> <!-- /menu -->';
|
||||
$sHtml .= ' <div class="footer"><a href="http://www.combodo.com" title="www.combodo.com" target="_blank"><img src="../images/logo-combodo.png"/></a></div>';
|
||||
$sHtml .= '<!-- End of the left pane -->';
|
||||
$sHtml .= '</div>';
|
||||
|
||||
$sHtml .= '<div class="ui-layout-center">';
|
||||
$sHtml .= ' <div id="top-bar" style="width:100%">';
|
||||
$sHtml .= ' <div id="top-bar" style="width:100%">';
|
||||
$sHtml .= self::FilterXSS($sApplicationBanner);
|
||||
$sHtml .= ' <div id="global-search"><form action="'.utils::GetAbsoluteUrlAppRoot().'pages/UI.php"><table><tr><td></td><td id="g-search-input"><input type="text" name="text" value="'.$sText.'"'.$sOnClick.'/></td>';
|
||||
$sHtml .= '<td><input type="image" src="../images/searchBtn.png"/></a></td>';
|
||||
$sHtml .= '<td><a style="background:transparent;" href="'.$sOnlineHelpUrl.'" target="_blank"><img style="border:0;padding-left:20px;padding-right:10px;" title="'.Dict::S('UI:Help').'" src="../images/help.png"/></td>';
|
||||
$sHtml .= '<td style="padding-right:20px;padding-left:10px;">'.self::FilterXSS($sLogOffMenu).'</td><td><input type="hidden" name="operation" value="full_text"/></td></tr></table></form></div>';
|
||||
//echo '<td> <input type="hidden" name="operation" value="full_text"/></td></tr></table></form></div>';
|
||||
$sHtml .= ' </div>';
|
||||
$sHtml .= ' <div class="ui-layout-content">';
|
||||
$sHtml .= ' <!-- Beginning of page content -->';
|
||||
$sHtml .= ' </div>';
|
||||
$sHtml .= ' <div class="ui-layout-content">';
|
||||
$sHtml .= ' <!-- Beginning of page content -->';
|
||||
$sHtml .= self::FilterXSS($this->s_content);
|
||||
$sHtml .= ' <!-- End of page content -->';
|
||||
$sHtml .= ' </div>';
|
||||
$sHtml .= ' <!-- End of page content -->';
|
||||
$sHtml .= ' </div>';
|
||||
$sHtml .= '</div>';
|
||||
|
||||
// Add the captured output
|
||||
@@ -762,6 +825,7 @@ EOF
|
||||
$sHtml .= "<div id=\"rawOutput\" title=\"Debug Output\"><div style=\"height:500px; overflow-y:auto;\">".self::FilterXSS($s_captured_output)."</div></div>\n";
|
||||
}
|
||||
$sHtml .= "<div id=\"at_the_end\">".self::FilterXSS($this->s_deferred_content)."</div>";
|
||||
// echo $this->s_deferred_content;
|
||||
$sHtml .= "<div style=\"display:none\" title=\"ex2\" id=\"ex2\">Please wait...</div>\n"; // jqModal Window
|
||||
$sHtml .= "<div style=\"display:none\" title=\"dialog\" id=\"ModalDlg\"></div>";
|
||||
$sHtml .= "<div style=\"display:none\" id=\"ajax_content\"></div>";
|
||||
@@ -776,7 +840,7 @@ EOF
|
||||
|
||||
if ($this->GetOutputFormat() == 'html')
|
||||
{
|
||||
echo $sHtml;
|
||||
echo $sHtml;
|
||||
}
|
||||
else if ($this->GetOutputFormat() == 'pdf' && $this->IsOutputFormatAvailable('pdf') )
|
||||
{
|
||||
@@ -785,13 +849,13 @@ EOF
|
||||
$oMPDF->mirroMargins = false;
|
||||
if ($this->a_base['href'] != '')
|
||||
{
|
||||
$oMPDF->setBasePath($this->a_base['href']); // Seems that the <BASE> tag is not recognized by mPDF...
|
||||
$oMPDF->setBasePath($this->a_base['href']); // Seems that the <BASE> tag is not recognized by mPDF...
|
||||
}
|
||||
$oMPDF->showWatermarkText = true;
|
||||
if ($this->GetOutputOption('pdf', 'template_path'))
|
||||
{
|
||||
$oMPDF->setImportUse(); // Allow templates
|
||||
$oMPDF->SetDocTemplate ($this->GetOutputOption('pdf', 'template_path'), 1);
|
||||
$oMPDF->setImportUse(); // Allow templates
|
||||
$oMPDF->SetDocTemplate ($this->GetOutputOption('pdf', 'template_path'), 1);
|
||||
}
|
||||
$oMPDF->WriteHTML($sHtml);
|
||||
$sOutputName = $this->s_title.'.pdf';
|
||||
@@ -1003,7 +1067,8 @@ EOF
|
||||
*/
|
||||
public function SetMessage($sMessage)
|
||||
{
|
||||
$this->m_sMessage = $sMessage;
|
||||
$this->m_sMessage = $sMessage;
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
?>
|
||||
|
||||
@@ -34,7 +34,7 @@ class LoginWebPage extends NiceWebPage
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct("iTop Login");
|
||||
parent::__construct(Dict::S("UI:iTopLogin"));
|
||||
$this->add_style(<<<EOF
|
||||
body {
|
||||
background: #eee;
|
||||
@@ -206,10 +206,15 @@ EOF
|
||||
$sPreviousLoginMode = '';
|
||||
}
|
||||
// Unset all of the session variables.
|
||||
unset($_SESSION['auth_user']);
|
||||
unset($_SESSION['login_mode']);
|
||||
$_SESSION = array();
|
||||
// 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!
|
||||
if (isset($_COOKIE[session_name()]))
|
||||
{
|
||||
setcookie(session_name(), '', time()-3600, '/');
|
||||
}
|
||||
// Finally, destroy the session.
|
||||
session_destroy();
|
||||
}
|
||||
|
||||
static function SecureConnectionRequired()
|
||||
@@ -379,6 +384,8 @@ EOF
|
||||
{
|
||||
$sMessage = ''; // In case we need to return a message to the calling web page
|
||||
$operation = utils::ReadParam('loginop', '');
|
||||
session_name(MetaModel::GetConfig()->Get('session_name'));
|
||||
session_start();
|
||||
|
||||
if ($operation == 'logoff')
|
||||
{
|
||||
@@ -433,7 +440,7 @@ EOF
|
||||
if ($bMustBeAdmin && !UserRights::IsAdministrator())
|
||||
{
|
||||
require_once(APPROOT.'/setup/setuppage.class.inc.php');
|
||||
$oP = new SetupPage(Dict::S('UI:PageTitle:FatalError'));
|
||||
$oP = new SetupWebPage(Dict::S('UI:PageTitle:FatalError'));
|
||||
$oP->add("<h1>".Dict::S('UI:Login:Error:AccessAdmin')."</h1>\n");
|
||||
$oP->p("<a href=\"".utils::GetAbsoluteUrlAppRoot()."pages/logoff.php\">".Dict::S('UI:LogOffMenu')."</a>");
|
||||
$oP->output();
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
require_once(APPROOT.'/application/template.class.inc.php');
|
||||
require_once(APPROOT."/application/user.dashboard.class.inc.php");
|
||||
|
||||
|
||||
/**
|
||||
@@ -60,29 +59,10 @@ require_once(APPROOT."/application/user.dashboard.class.inc.php");
|
||||
|
||||
class ApplicationMenu
|
||||
{
|
||||
static $bAdditionalMenusLoaded = false;
|
||||
static $aRootMenus = array();
|
||||
static $aMenusIndex = array();
|
||||
static $sFavoriteSiloQuery = 'SELECT Organization';
|
||||
|
||||
static public function LoadAdditionalMenus()
|
||||
{
|
||||
if (!self::$bAdditionalMenusLoaded)
|
||||
{
|
||||
// Build menus from module handlers
|
||||
//
|
||||
foreach(get_declared_classes() as $sPHPClass)
|
||||
{
|
||||
if (is_subclass_of($sPHPClass, 'ModuleHandlerAPI'))
|
||||
{
|
||||
$aCallSpec = array($sPHPClass, 'OnMenuCreation');
|
||||
call_user_func($aCallSpec);
|
||||
}
|
||||
}
|
||||
self::$bAdditionalMenusLoaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the query used to limit the list of displayed organizations in the drop-down menu
|
||||
* @param $sOQL string The OQL query returning a list of Organization objects
|
||||
@@ -146,7 +126,6 @@ class ApplicationMenu
|
||||
*/
|
||||
static public function ReflectionMenuNodes()
|
||||
{
|
||||
self::LoadAdditionalMenus();
|
||||
return self::$aMenusIndex;
|
||||
}
|
||||
|
||||
@@ -155,11 +134,10 @@ class ApplicationMenu
|
||||
*/
|
||||
static public function DisplayMenu(iTopWebPage $oPage, $aExtraParams)
|
||||
{
|
||||
self::LoadAdditionalMenus();
|
||||
// Sort the root menu based on the rank
|
||||
usort(self::$aRootMenus, array('ApplicationMenu', 'CompareOnRank'));
|
||||
$iAccordion = 0;
|
||||
$iActiveMenu = self::GetMenuIndexById(self::GetActiveNodeId());
|
||||
$iActiveMenu = ApplicationMenu::GetActiveNodeId();
|
||||
foreach(self::$aRootMenus as $aMenu)
|
||||
{
|
||||
$oMenuNode = self::GetMenuNode($aMenu['index']);
|
||||
@@ -278,21 +256,22 @@ class ApplicationMenu
|
||||
|
||||
/**
|
||||
* Retrieves the currently active menu (if any, otherwise the first menu is the default)
|
||||
* @return string The Id of the currently active menu
|
||||
* @return MenuNode or null if there is no menu at all !
|
||||
*/
|
||||
static public function GetActiveNodeId()
|
||||
{
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sMenuId = $oAppContext->GetCurrentValue('menu', null);
|
||||
if ($sMenuId === null)
|
||||
$iMenuIndex = $oAppContext->GetCurrentValue('menu', -1);
|
||||
|
||||
if ($iMenuIndex == -1)
|
||||
{
|
||||
// Make sure the root menu is sorted on 'rank'
|
||||
usort(self::$aRootMenus, array('ApplicationMenu', 'CompareOnRank'));
|
||||
$oFirstGroup = self::GetMenuNode(self::$aRootMenus[0]['index']);
|
||||
$oMenuNode = self::GetMenuNode(self::$aMenusIndex[$oFirstGroup->GetIndex()]['children'][0]['index']);
|
||||
$sMenuId = $oMenuNode->GetMenuId();
|
||||
$iMenuIndex = $oMenuNode->GetIndex();
|
||||
}
|
||||
return $sMenuId;
|
||||
return $iMenuIndex;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -393,12 +372,12 @@ abstract class MenuNode
|
||||
|
||||
public function GetTitle()
|
||||
{
|
||||
return Dict::S("Menu:$this->sMenuId", str_replace('_', ' ', $this->sMenuId));
|
||||
return Dict::S("Menu:$this->sMenuId");
|
||||
}
|
||||
|
||||
public function GetLabel()
|
||||
{
|
||||
return Dict::S("Menu:$this->sMenuId+", "");
|
||||
return Dict::S("Menu:$this->sMenuId+");
|
||||
}
|
||||
|
||||
public function GetIndex()
|
||||
@@ -408,7 +387,7 @@ abstract class MenuNode
|
||||
|
||||
public function GetHyperlink($aExtraParams)
|
||||
{
|
||||
$aExtraParams['c[menu]'] = $this->GetMenuId();
|
||||
$aExtraParams['c[menu]'] = $this->GetIndex();
|
||||
return $this->AddParams(utils::GetAbsoluteUrlAppRoot().'pages/UI.php', $aExtraParams);
|
||||
}
|
||||
|
||||
@@ -549,7 +528,6 @@ class TemplateMenuNode extends MenuNode
|
||||
$sTemplate = @file_get_contents($this->sTemplateFile);
|
||||
if ($sTemplate !== false)
|
||||
{
|
||||
$aExtraParams['table_id'] = 'Menu_'.$this->GetMenuId();
|
||||
$oTemplate = new DisplayTemplate($sTemplate);
|
||||
$oTemplate->Render($oPage, $aExtraParams);
|
||||
}
|
||||
@@ -626,19 +604,31 @@ class OQLMenuNode extends MenuNode
|
||||
{
|
||||
$sIcon = '';
|
||||
}
|
||||
// The standard template used for all such pages: a (closed) search form at the top and a list of results at the bottom
|
||||
$sTemplate = '';
|
||||
|
||||
if ($this->bSearch)
|
||||
{
|
||||
$aParams = array_merge(array('open' => true, 'table_id' => 'Menu_'.$this->GetMenuId()), $aExtraParams);
|
||||
$oBlock = new DisplayBlock($oSearch, 'search', false /* Asynchronous */, $aParams);
|
||||
$oBlock->Display($oPage, 0);
|
||||
$sTemplate .= <<<EOF
|
||||
<itopblock BlockClass="DisplayBlock" type="search" asynchronous="false" encoding="text/oql">$this->sOQL</itopblock>
|
||||
EOF;
|
||||
}
|
||||
|
||||
$oPage->add("<p class=\"page-header\">$sIcon ".Dict::S($this->sPageTitle)."</p>");
|
||||
|
||||
$aParams = array_merge(array('table_id' => 'Menu_'.$this->GetMenuId()), $aExtraParams);
|
||||
$oBlock = new DisplayBlock($oSearch, 'list', false /* Asynchronous */, $aParams);
|
||||
$oBlock->Display($oPage, 1);
|
||||
$sParams = '';
|
||||
if (!empty($this->m_aParams))
|
||||
{
|
||||
$sParams = 'parameters="';
|
||||
foreach($this->m_aParams as $sName => $sValue)
|
||||
{
|
||||
$sParams .= $sName.':'.$sValue.';';
|
||||
}
|
||||
$sParams .= '"';
|
||||
}
|
||||
$sTemplate .= <<<EOF
|
||||
<p class="page-header">$sIcon<itopstring>$this->sPageTitle</itopstring></p>
|
||||
<itopblock BlockClass="DisplayBlock" type="list" asynchronous="false" encoding="text/oql" $sParams>$this->sOQL</itopblock>
|
||||
EOF;
|
||||
$oTemplate = new DisplayTemplate($sTemplate);
|
||||
$oTemplate->Render($oPage, $aExtraParams);
|
||||
}
|
||||
}
|
||||
/**
|
||||
@@ -671,10 +661,12 @@ class SearchMenuNode extends MenuNode
|
||||
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
{
|
||||
$oSearch = new DBObjectSearch($this->sClass);
|
||||
$aParams = array_merge(array('open' => true, 'table_id' => 'Menu_'.$this->GetMenuId()), $aExtraParams);
|
||||
$oBlock = new DisplayBlock($oSearch, 'search', false /* Asynchronous */, $aParams);
|
||||
$oBlock->Display($oPage, 0);
|
||||
// The standard template used for all such pages: an open search form at the top
|
||||
$sTemplate = <<<EOF
|
||||
<itopblock BlockClass="DisplayBlock" type="search" asynchronous="false" encoding="text/oql" parameters="open:true">SELECT $this->sClass</itopblock>
|
||||
EOF;
|
||||
$oTemplate = new DisplayTemplate($sTemplate);
|
||||
$oTemplate->Render($oPage, $aExtraParams);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -709,7 +701,7 @@ class WebPageMenuNode extends MenuNode
|
||||
|
||||
public function GetHyperlink($aExtraParams)
|
||||
{
|
||||
$aExtraParams['c[menu]'] = $this->GetMenuId();
|
||||
$aExtraParams['c[menu]'] = $this->GetIndex();
|
||||
return $this->AddParams( $this->sHyperlink, $aExtraParams);
|
||||
}
|
||||
|
||||
@@ -748,7 +740,7 @@ class NewObjectMenuNode extends MenuNode
|
||||
public function GetHyperlink($aExtraParams)
|
||||
{
|
||||
$sHyperlink = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=new&class='.$this->sClass;
|
||||
$aExtraParams['c[menu]'] = $this->GetMenuId();
|
||||
$aExtraParams['c[menu]'] = $this->GetIndex();
|
||||
return $this->AddParams($sHyperlink, $aExtraParams);
|
||||
}
|
||||
|
||||
@@ -779,116 +771,4 @@ class NewObjectMenuNode extends MenuNode
|
||||
assert(false); // Shall never be called, the external web page will handle the display by itself
|
||||
}
|
||||
}
|
||||
|
||||
require_once(APPROOT.'application/dashboard.class.inc.php');
|
||||
/**
|
||||
* This class defines a menu item which content is based on XML dashboard.
|
||||
*/
|
||||
class DashboardMenuNode extends MenuNode
|
||||
{
|
||||
protected $sDashboardFile;
|
||||
|
||||
/**
|
||||
* Create a menu item based on a custom template and inserts it into the application's main menu
|
||||
* @param string $sMenuId Unique identifier of the menu (used to identify the menu for bookmarking, and for getting the labels from the dictionary)
|
||||
* @param string $sTemplateFile Path (or URL) to the file that will be used as a template for displaying the page's content
|
||||
* @param integer $iParentIndex ID of the parent menu
|
||||
* @param float $fRank Number used to order the list, any number will do, but for a given level (i.e same parent) all menus are sorted based on this value
|
||||
* @param string $sEnableClass Name of class of object
|
||||
* @param integer $iActionCode Either UR_ACTION_READ, UR_ACTION_MODIFY, UR_ACTION_DELETE, UR_ACTION_BULKREAD, UR_ACTION_BULKMODIFY or UR_ACTION_BULKDELETE
|
||||
* @param integer $iAllowedResults Expected "rights" for the action: either UR_ALLOWED_YES, UR_ALLOWED_NO, UR_ALLOWED_DEPENDS or a mix of them...
|
||||
* @return MenuNode
|
||||
*/
|
||||
public function __construct($sMenuId, $sDashboardFile, $iParentIndex, $fRank = 0, $sEnableClass = null, $iActionCode = null, $iAllowedResults = UR_ALLOWED_YES, $sEnableStimulus = null)
|
||||
{
|
||||
parent::__construct($sMenuId, $iParentIndex, $fRank, $sEnableClass, $iActionCode, $iAllowedResults, $sEnableStimulus);
|
||||
$this->sDashboardFile = $sDashboardFile;
|
||||
$this->aReflectionProperties['definition_file'] = $sDashboardFile;
|
||||
}
|
||||
|
||||
public function GetHyperlink($aExtraParams)
|
||||
{
|
||||
if ($this->sDashboardFile == '') return '';
|
||||
return parent::GetHyperlink($aExtraParams);
|
||||
}
|
||||
|
||||
public function GetDashboard()
|
||||
{
|
||||
$sDashboardDefinition = @file_get_contents($this->sDashboardFile);
|
||||
if ($sDashboardDefinition !== false)
|
||||
{
|
||||
$bCustomized = false;
|
||||
|
||||
// Search for an eventual user defined dashboard, overloading the existing one
|
||||
$oUDSearch = new DBObjectSearch('UserDashboard');
|
||||
$oUDSearch->AddCondition('user_id', UserRights::GetUserId(), '=');
|
||||
$oUDSearch->AddCondition('menu_code', $this->sMenuId, '=');
|
||||
$oUDSet = new DBObjectSet($oUDSearch);
|
||||
if ($oUDSet->Count() > 0)
|
||||
{
|
||||
// Assuming there is at most one couple {user, menu}!
|
||||
$oUserDashboard = $oUDSet->Fetch();
|
||||
$sDashboardDefinition = $oUserDashboard->Get('contents');
|
||||
$bCustomized = true;
|
||||
|
||||
}
|
||||
$oDashboard = new RuntimeDashboard($this->sMenuId);
|
||||
$oDashboard->FromXml($sDashboardDefinition);
|
||||
$oDashboard->SetCustomFlag($bCustomized);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oDashboard = null;
|
||||
}
|
||||
return $oDashboard;
|
||||
}
|
||||
|
||||
public function RenderContent(WebPage $oPage, $aExtraParams = array())
|
||||
{
|
||||
$oDashboard = $this->GetDashboard();
|
||||
if ($oDashboard != null)
|
||||
{
|
||||
$oDashboard->Render($oPage, false, $aExtraParams);
|
||||
|
||||
$bEdit = utils::ReadParam('edit', false);
|
||||
if ($bEdit)
|
||||
{
|
||||
$sId = addslashes($this->sMenuId);
|
||||
$oPage->add_ready_script("EditDashboard('$sId');");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$oPage->p("Error: failed to load dashboard file: '{$this->sDashboardFile}'");
|
||||
}
|
||||
}
|
||||
|
||||
public function RenderEditor(WebPage $oPage)
|
||||
{
|
||||
$oDashboard = $this->GetDashboard();
|
||||
if ($oDashboard != null)
|
||||
{
|
||||
$oDashboard->RenderEditor($oPage);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oPage->p("Error: failed to load dashboard file: '{$this->sDashboardFile}'");
|
||||
}
|
||||
}
|
||||
|
||||
public function AddDashlet($oDashlet)
|
||||
{
|
||||
$oDashboard = $this->GetDashboard();
|
||||
if ($oDashboard != null)
|
||||
{
|
||||
$oDashboard->AddDashlet($oDashlet);
|
||||
$oDashboard->Save();
|
||||
}
|
||||
else
|
||||
{
|
||||
$oPage->p("Error: failed to load dashboard file: '{$this->sDashboardFile}'");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -30,125 +30,30 @@ require_once(APPROOT."/application/webpage.class.inc.php");
|
||||
class NiceWebPage extends WebPage
|
||||
{
|
||||
var $m_aReadyScripts;
|
||||
var $m_sRootUrl;
|
||||
|
||||
public function __construct($s_title)
|
||||
{
|
||||
parent::__construct($s_title);
|
||||
$this->m_aReadyScripts = array();
|
||||
$this->add_linked_script("../js/jquery-1.7.1.min.js");
|
||||
$this->add_linked_stylesheet('../css/ui-lightness/jquery-ui-1.8.17.custom.css');
|
||||
$this->add_linked_script('../js/jquery-ui-1.8.17.custom.min.js');
|
||||
$this->add_linked_script("../js/jquery-1.4.2.min.js");
|
||||
//$this->add_linked_script("../js/jquery.history_remote.pack.js");
|
||||
$this->add_linked_stylesheet('../css/ui-lightness/jquery-ui-1.8.2.custom.css');
|
||||
$this->add_linked_script('../js/jquery-ui-1.8.2.custom.min.js');
|
||||
//$this->add_linked_script("../js/ui.resizable.js");
|
||||
// $this->add_linked_script("../js/ui.tabs.js");
|
||||
$this->add_linked_script("../js/hovertip.js");
|
||||
// table sorting
|
||||
$this->add_linked_script("../js/jquery.tablesorter.min.js");
|
||||
$this->add_linked_script("../js/jquery.tablesorter.pager.js");
|
||||
$this->add_linked_script("../js/jquery.tablehover.js");
|
||||
$this->add_ready_script(
|
||||
<<< EOF
|
||||
//add new widget called TruncatedList to properly display truncated lists when they are sorted
|
||||
$.tablesorter.addWidget({
|
||||
// give the widget a id
|
||||
id: "truncatedList",
|
||||
// format is called when the on init and when a sorting has finished
|
||||
format: function(table)
|
||||
{
|
||||
// Check if there is a "truncated" line
|
||||
this.truncatedList = false;
|
||||
if ($("tr td.truncated",table).length > 0)
|
||||
{
|
||||
this.truncatedList = true;
|
||||
}
|
||||
if (this.truncatedList)
|
||||
{
|
||||
$("tr td",table).removeClass('truncated');
|
||||
$("tr:last td",table).addClass('truncated');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$.tablesorter.addWidget({
|
||||
// give the widget a id
|
||||
id: "myZebra",
|
||||
// format is called when the on init and when a sorting has finished
|
||||
format: function(table)
|
||||
{
|
||||
// Replace the 'red even' lines by 'red_even' since most browser do not support 2 classes selector in CSS, etc..
|
||||
$("tbody tr:even",table).addClass('even');
|
||||
$("tbody tr.red:even",table).removeClass('red').removeClass('even').addClass('red_even');
|
||||
$("tbody tr.orange:even",table).removeClass('orange').removeClass('even').addClass('orange_even');
|
||||
$("tbody tr.green:even",table).removeClass('green').removeClass('even').addClass('green_even');
|
||||
// In case we sort again the table, we need to remove the added 'even' classes on odd rows
|
||||
$("tbody tr:odd",table).removeClass('even');
|
||||
$("tbody tr.red_even:odd",table).removeClass('even').removeClass('red_even').addClass('red');
|
||||
$("tbody tr.orange_even:odd",table).removeClass('even').removeClass('orange_even').addClass('orange');
|
||||
$("tbody tr.green_even:odd",table).removeClass('even').removeClass('green_even').addClass('green');
|
||||
}
|
||||
});
|
||||
$("table.listResults").tableHover(); // hover tables
|
||||
EOF
|
||||
);
|
||||
// $this->add_linked_script("../js/jqModal.js");
|
||||
$this->add_linked_stylesheet("../css/light-grey.css");
|
||||
|
||||
$this->m_sRootUrl = $this->GetAbsoluteUrlAppRoot();
|
||||
$sAbsURLAppRoot = addslashes($this->m_sRootUrl);
|
||||
$sAbsURLModulesRoot = addslashes($this->GetAbsoluteUrlModulesRoot());
|
||||
|
||||
$sAppContext = addslashes($this->GetApplicationContext());
|
||||
|
||||
$this->add_script(
|
||||
<<<EOF
|
||||
function GetAbsoluteUrlAppRoot()
|
||||
{
|
||||
return '$sAbsURLAppRoot';
|
||||
}
|
||||
|
||||
function GetAbsoluteUrlModulesRoot()
|
||||
{
|
||||
return '$sAbsURLModulesRoot';
|
||||
}
|
||||
function AddAppContext(sURL)
|
||||
{
|
||||
var sContext = '$sAppContext';
|
||||
if (sContext.length > 0)
|
||||
{
|
||||
if (sURL.indexOf('?') == -1)
|
||||
{
|
||||
return sURL+'?'+sContext;
|
||||
}
|
||||
return sURL+'&'+sContext;
|
||||
}
|
||||
return sURL;
|
||||
}
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
public function SetRootUrl($sRootUrl)
|
||||
{
|
||||
$this->m_sRootUrl = $sRootUrl;
|
||||
// $this->add_linked_stylesheet("../js/themes/light/light.tabs.css");
|
||||
//$this->add_linked_stylesheet("../css/jquery.tabs-ie.css", "lte IE 7");
|
||||
// $this->add_linked_stylesheet("../css/jqModal.css");
|
||||
$this->add_ready_script(' window.setTimeout(hovertipInit, 1);');
|
||||
}
|
||||
|
||||
|
||||
public function small_p($sText)
|
||||
{
|
||||
$this->add("<p style=\"font-size:smaller\">$sText</p>\n");
|
||||
}
|
||||
|
||||
public function GetAbsoluteUrlAppRoot()
|
||||
{
|
||||
return utils::GetAbsoluteUrlAppRoot();
|
||||
}
|
||||
|
||||
public function GetAbsoluteUrlModulesRoot()
|
||||
{
|
||||
return utils::GetAbsoluteUrlModulesRoot();
|
||||
}
|
||||
|
||||
function GetApplicationContext()
|
||||
{
|
||||
$oAppContext = new ApplicationContext();
|
||||
return $oAppContext->GetForLink();
|
||||
}
|
||||
}
|
||||
|
||||
// By Rom, used by CSVImport and Advanced search
|
||||
public function MakeClassesSelect($sName, $sDefaultValue, $iWidthPx, $iActionCode = null)
|
||||
@@ -195,7 +100,6 @@ EOF
|
||||
*/
|
||||
public function output()
|
||||
{
|
||||
$this->set_base($this->m_sRootUrl.'pages/');
|
||||
if (count($this->m_aReadyScripts)>0)
|
||||
{
|
||||
$this->add_script("\$(document).ready(function() {\n".implode("\n", $this->m_aReadyScripts)."\n});");
|
||||
|
||||
@@ -60,7 +60,6 @@ class PortalWebPage extends NiceWebPage
|
||||
$this->add_linked_stylesheet("../css/jquery.treeview.css");
|
||||
$this->add_linked_stylesheet("../css/jquery.autocomplete.css");
|
||||
$sAbsURLAppRoot = addslashes(utils::GetAbsoluteUrlAppRoot()); // Pass it to Javascript scripts
|
||||
$sAbsURLModulesRoot = addslashes(utils::GetAbsoluteUrlModulesRoot()); // Pass it to Javascript scripts
|
||||
$oAppContext = new ApplicationContext();
|
||||
$sAppContext = addslashes($oAppContext->GetForLink());
|
||||
if ($sAlternateStyleSheet != '')
|
||||
@@ -173,11 +172,6 @@ EOF
|
||||
return '$sAbsURLAppRoot';
|
||||
}
|
||||
|
||||
function GetAbsoluteUrlModulesRoot()
|
||||
{
|
||||
return '$sAbsURLModulesRoot';
|
||||
}
|
||||
|
||||
function AddAppContext(sURL)
|
||||
{
|
||||
var sContext = '$sAppContext';
|
||||
@@ -218,8 +212,10 @@ EOF
|
||||
}
|
||||
EOF
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
// For Wizard helper to process the ajax replies
|
||||
$this->add('<div id="ajax_content"></div>');
|
||||
}
|
||||
|
||||
public function SetCurrentTab($sTabLabel = '')
|
||||
{
|
||||
@@ -279,13 +275,9 @@ EOF
|
||||
{
|
||||
// Home-made and very limited display of an object set
|
||||
|
||||
//
|
||||
//$oSet->Seek(0);// juste pour que le warning soit moins crado
|
||||
//$oSet->Fetch();// juste pour que le warning soit moins crado
|
||||
//
|
||||
|
||||
$this->add("<div id=\"listOf$sClass\">\n");
|
||||
cmdbAbstractObject::DisplaySet($this, $oSet, array('currentId' => $this->GetUniqueId()."$sClass", 'menu' => false, 'zlist' => false, 'extra_fields' => implode(',', $aZList)));
|
||||
$sUniqueId = $sClass.$this->GetUniqueId();
|
||||
$this->add("<div id=\"$sUniqueId\">\n"); // The id here MUST be the same as currentId, otherwise the pagination will be broken
|
||||
cmdbAbstractObject::DisplaySet($this, $oSet, array('currentId' => $sUniqueId, 'menu' => false, 'zlist' => false, 'extra_fields' => implode(',', $aZList)));
|
||||
$this->add("</div>\n");
|
||||
}
|
||||
else
|
||||
|
||||
@@ -25,24 +25,7 @@
|
||||
|
||||
require_once(APPROOT.'/core/cmdbobject.class.inc.php');
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
session_name('itop-'.md5(APPROOT));
|
||||
session_start();
|
||||
if (isset($_REQUEST['switch_env']))
|
||||
{
|
||||
$sEnv = $_REQUEST['switch_env'];
|
||||
$_SESSION['itop_env'] = $sEnv;
|
||||
// TODO: reset the credentials as well ??
|
||||
}
|
||||
else if (isset($_SESSION['itop_env']))
|
||||
{
|
||||
$sEnv = $_SESSION['itop_env'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$sEnv = ITOP_DEFAULT_ENV;
|
||||
$_SESSION['itop_env'] = ITOP_DEFAULT_ENV;
|
||||
}
|
||||
$sConfigFile = APPCONF.$sEnv.'/'.ITOP_CONFIG_FILE;
|
||||
MetaModel::Startup($sConfigFile);
|
||||
|
||||
MetaModel::Startup(ITOP_CONFIG_FILE);
|
||||
|
||||
?>
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
<div style="width:100%;background: #fff url(../images/welcome.jpg) top left no-repeat;">
|
||||
<style>
|
||||
.welcome_popup_cell {
|
||||
.dashboard {
|
||||
vertical-align:top;
|
||||
width:50%;
|
||||
border:0px solid #000;
|
||||
background-color:#F9F9F1;
|
||||
padding:10px;
|
||||
text-align:left;
|
||||
font-size:10pt;
|
||||
}
|
||||
.dashboard2 {
|
||||
vertical-align:top;
|
||||
width:50%;
|
||||
border:0px solid #000;
|
||||
@@ -8,7 +17,15 @@ border:0px solid #000;
|
||||
padding:5px;
|
||||
text-align:left;
|
||||
}
|
||||
tr td.welcome_popup_cell, tr td.welcome_popup_cell ul {
|
||||
|
||||
td.dashboard li {
|
||||
margin-top: 5px;
|
||||
display: list-item;
|
||||
}
|
||||
td div.display_block {
|
||||
padding:0;
|
||||
}
|
||||
tr td.dashboard2, tr td.dashboard2 ul {
|
||||
font-size:10pt;
|
||||
}
|
||||
</style>
|
||||
@@ -18,10 +35,10 @@ font-size:10pt;
|
||||
<p></p>
|
||||
<table border="0" style="padding:10px;border-spacing: 10px;width:100%">
|
||||
<tr>
|
||||
<td class="welcome_popup_cell">
|
||||
<td class="dashboard2">
|
||||
<itopstring>UI:WelcomeMenu:LeftBlock</itopstring>
|
||||
</td>
|
||||
<td class="welcome_popup_cell">
|
||||
<td class="dashboard2">
|
||||
<itopstring>UI:WelcomeMenu:RightBlock</itopstring>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -323,7 +323,7 @@ EOF
|
||||
/**
|
||||
* Search for objects to be selected
|
||||
* @param WebPage $oP The page used for the output (usually an AjaxWebPage)
|
||||
* @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of m_sRemoteClass
|
||||
* @param string $sRemoteClass Name of the "remote" class to perform the search on, must be a derived class of sTargetClass
|
||||
* @param Array $aAlreadyLinkedIds List of IDs of objects of "remote" class already linked, to be filtered out of the search
|
||||
*/
|
||||
public function SearchObjectsToSelect(WebPage $oP, $sFilter, $sRemoteClass = '', $oObj = null)
|
||||
@@ -334,10 +334,25 @@ EOF
|
||||
}
|
||||
try
|
||||
{
|
||||
$oFilter = DBObjectSearch::FromOQL($sFilter);
|
||||
if ($sRemoteClass != $this->sTargetClass)
|
||||
{
|
||||
//$oBaseClassFilter = DBObjectSearch::FromOQL($sFilter);
|
||||
//$oFilter = new DBObjectSearch($sRemoteClass);
|
||||
//$oFilter->AddConditionExpression($oBaseClassFilter->GetCriteria());
|
||||
//$oFilter->TransferConditionExpression($oBaseClassFilter, array());
|
||||
//$oFilter->TransferConditionExpression($oBaseClassFilter, array($this->sTargetClass => array('*' => $sRemoteClass.'_'.strtolower($this->sTargetClass))));
|
||||
$sFilter = str_replace(" $this->sTargetClass ", " $sRemoteClass ", $sFilter);
|
||||
$sFilter = str_replace("`$this->sTargetClass`", "`$sRemoteClass`", $sFilter);
|
||||
$oFilter = DBObjectSearch::FromOQL($sFilter);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oFilter = DBObjectSearch::FromOQL($sFilter);
|
||||
}
|
||||
//$oP->p($oFilter->ToOQL());
|
||||
$oFilter->SetModifierProperty('UserRightsGetSelectFilter', 'bSearchMode', $this->bSearchMode);
|
||||
$oBlock = new DisplayBlock($oFilter, 'list', false, array('query_params' => array('this' => $oObj)));
|
||||
$oBlock->Display($oP, $this->iId.'_results', array('this' => $oObj, 'cssCount'=> '#count_'.$this->iId, 'menu' => false, 'selection_mode' => true, 'selection_type' => 'single', 'table_id' => 'select_'.$this->sAttCode)); // Don't display the 'Actions' menu on the results
|
||||
$oBlock->Display($oP, $this->iId.'_results', array('this' => $oObj, 'cssCount'=> '#count_'.$this->iId, 'menu' => false, 'selection_mode' => true, 'selection_type' => 'single')); // Don't display the 'Actions' menu on the results
|
||||
}
|
||||
catch(MissingQueryArgument $e)
|
||||
{
|
||||
|
||||
@@ -146,7 +146,7 @@ class UILinksWidget
|
||||
$sFieldId = $this->m_iInputId.'_'.$sFieldCode.'['.$linkObjOrId.']';
|
||||
$sSafeId = self::MakeID($sFieldId);
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sLinkedClass, $sFieldCode);
|
||||
$aRow[$sFieldCode] = cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, $oNewLinkObj->Get($sFieldCode) /* TO DO/ call GetDefaultValue($oObject->ToArgs()) */, '' /* DisplayValue */, $sSafeId /* id */, $sNameSuffix, 0, $aArgs);
|
||||
$aRow[$sFieldCode] = cmdbAbstractObject::GetFormElementForField($oP, $this->m_sLinkedClass, $sFieldCode, $oAttDef, '' /* TO DO/ call GetDefaultValue($oObject->ToArgs()) */, '' /* DisplayValue */, $sSafeId /* id */, $sNameSuffix, 0, $aArgs);
|
||||
$aFieldsMap[$sFieldCode] = $sSafeId;
|
||||
}
|
||||
$sState = '';
|
||||
@@ -202,7 +202,7 @@ EOF
|
||||
|
||||
protected function MakeID($sName)
|
||||
{
|
||||
return str_replace(array('[', ']', '-'), '_', $sName);
|
||||
return str_replace(array('[', ']'), '_', $sName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -405,7 +405,7 @@ EOF
|
||||
}
|
||||
$oSet = new CMDBObjectSet($oFilter);
|
||||
$oBlock = new DisplayBlock($oFilter, 'list', false);
|
||||
$oBlock->Display($oP, "ResultsToAdd_{$this->m_sAttCode}", array('menu' => false, 'cssCount'=> '#count_'.$this->m_sAttCode.$this->m_sNameSuffix , 'selection_mode' => true, 'table_id' => 'add_'.$this->m_sAttCode)); // Don't display the 'Actions' menu on the results
|
||||
$oBlock->Display($oP, "ResultsToAdd_{$this->m_sAttCode}", array('menu' => false, 'cssCount'=> '#count_'.$this->m_sAttCode.$this->m_sNameSuffix , 'selection_mode' => true)); // Don't display the 'Actions' menu on the results
|
||||
}
|
||||
|
||||
public function DoAddObjects(WebPage $oP, $oFullSetFilter, $oCurrentObj)
|
||||
|
||||
@@ -104,7 +104,7 @@ class UILinksWizard
|
||||
var nbChecked = $('.selection:checked').length;
|
||||
if (nbChecked > 0)
|
||||
{
|
||||
$('#btnRemove').removeAttr('disabled');
|
||||
$('#btnRemove').attr('disabled','');
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
* Store and retrieve user custom dashboards
|
||||
*
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
require_once(APPROOT.'/core/dbobject.class.php');
|
||||
|
||||
/**
|
||||
* This class is used to store, in a persistent manner, a dashboard edited by a user
|
||||
*/
|
||||
class UserDashboard extends DBObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "user_id",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_app_dashboards",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("targetclass"=>"User", "allowed_values"=>null, "sql"=>"user_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("menu_code", array("allowed_values"=>null, "sql"=>"menu_code", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("contents", array("allowed_values"=>null, "sql"=>"contents", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Overloading this function here to secure a fix done right before the release
|
||||
* The real fix should be to implement this verb in DBObject
|
||||
*/
|
||||
public function DBDeleteTracked(CMDBChange $oChange, $bSkipStrongSecurity = null, &$oDeletionPlan = null)
|
||||
{
|
||||
$this->DBDelete($oDeletionPlan);
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -77,42 +77,6 @@ class appUserPreferences extends DBObject
|
||||
self::Save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the value for a given preference (or list of preferences that matches a pattern), and updates the database
|
||||
* @param string $sPattern Code/Pattern of the properties/preferences to reset
|
||||
* @param boolean $bPattern Whether or not the supplied code is a PCRE pattern
|
||||
*/
|
||||
static function UnsetPref($sCodeOrPattern, $bPattern = false)
|
||||
{
|
||||
if (self::$oUserPrefs == null)
|
||||
{
|
||||
self::Load();
|
||||
}
|
||||
$aPrefs = self::$oUserPrefs->Get('preferences');
|
||||
if ($bPattern)
|
||||
{
|
||||
// the supplied code is a pattern, clear all preferences that match
|
||||
foreach($aPrefs as $sKey => $void)
|
||||
{
|
||||
if (preg_match($sCodeOrPattern, $sKey))
|
||||
{
|
||||
unset($aPrefs[$sKey]);
|
||||
}
|
||||
}
|
||||
self::$oUserPrefs->Set('preferences', $aPrefs);
|
||||
}
|
||||
else
|
||||
{
|
||||
unset($aPrefs[$sCode]);
|
||||
self::$oUserPrefs->Set('preferences', $aPrefs);
|
||||
}
|
||||
// Save only if needed
|
||||
if (self::$oUserPrefs->IsModified())
|
||||
{
|
||||
self::Save();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this function to get all the preferences for the user, packed as a JSON object
|
||||
* @return string JSON representation of the preferences
|
||||
|
||||
@@ -26,9 +26,7 @@
|
||||
require_once(APPROOT.'/core/config.class.inc.php');
|
||||
require_once(APPROOT.'/application/transaction.class.inc.php');
|
||||
|
||||
define('ITOP_CONFIG_FILE', 'config-itop.php');
|
||||
define('ITOP_DEFAULT_CONFIG_FILE', APPCONF.ITOP_DEFAULT_ENV.'/'.ITOP_CONFIG_FILE);
|
||||
|
||||
define('ITOP_CONFIG_FILE', APPROOT.'/config-itop.php');
|
||||
define('SERVER_NAME_PLACEHOLDER', '$SERVER_NAME$');
|
||||
|
||||
class FileUploadException extends Exception
|
||||
@@ -42,7 +40,8 @@ class FileUploadException extends Exception
|
||||
*/
|
||||
class utils
|
||||
{
|
||||
private static $oConfig = null;
|
||||
private static $m_sConfigFile = ITOP_CONFIG_FILE;
|
||||
private static $m_oConfig = null;
|
||||
private static $m_bCASClient = false;
|
||||
|
||||
// Parameters loaded from a file, parameters of the page/command line still have precedence
|
||||
@@ -210,7 +209,6 @@ class utils
|
||||
$retValue = filter_var($value, FILTER_SANITIZE_SPECIAL_CHARS);
|
||||
break;
|
||||
|
||||
case 'context_param':
|
||||
case 'parameter':
|
||||
case 'field_name':
|
||||
if (is_array($value))
|
||||
@@ -237,15 +235,12 @@ class utils
|
||||
case 'field_name':
|
||||
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP, array("options"=>array("regexp"=>'/^[A-Za-z0-9_]+(->[A-Za-z0-9_]+)*$/'))); // att_code or att_code->name or AttCode->Name or AttCode->Key2->Name
|
||||
break;
|
||||
|
||||
case 'context_param':
|
||||
$retValue = filter_var($value, FILTER_VALIDATE_REGEXP, array("options"=>array("regexp"=>'/^[ A-Za-z0-9_=%:+-]*$/')));
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
case 'raw_data':
|
||||
$retValue = $value;
|
||||
@@ -463,30 +458,13 @@ class utils
|
||||
// http://www.spaweditor.com/scripts/regex/index.php
|
||||
}
|
||||
|
||||
static public function GetConfig()
|
||||
{
|
||||
if (self::$oConfig == null)
|
||||
{
|
||||
$sConfigFile = self::GetConfigFilePath();
|
||||
if (file_exists($sConfigFile))
|
||||
{
|
||||
self::$oConfig = new Config($sConfigFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
// When executing the setup, the config file may be still missing
|
||||
self::$oConfig = new Config();
|
||||
}
|
||||
}
|
||||
return self::$oConfig;
|
||||
}
|
||||
/**
|
||||
* Returns the absolute URL to the application root path
|
||||
* @return string The absolute URL to the application root, without the first slash
|
||||
* Returns the absolute URL to the server's root path
|
||||
* @return string The absolute URL to the server's root, without the first slash
|
||||
*/
|
||||
static public function GetAbsoluteUrlAppRoot()
|
||||
{
|
||||
$sUrl = self::GetConfig()->Get('app_root_url');
|
||||
$sUrl = MetaModel::GetConfig()->Get('app_root_url');
|
||||
if (strpos($sUrl, SERVER_NAME_PLACEHOLDER) > -1)
|
||||
{
|
||||
if (isset($_SERVER['SERVER_NAME']))
|
||||
@@ -570,6 +548,17 @@ class utils
|
||||
return $sAppRootUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute URL to the modules root path
|
||||
* Hardcoded here for compatibility with iTop 2.0 modules
|
||||
* @return string The absolute URL to the modules
|
||||
*/
|
||||
static public function GetAbsoluteUrlModulesRoot()
|
||||
{
|
||||
$sUrl = self::GetAbsoluteUrlAppRoot().'modules/';
|
||||
return $sUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether or not log off operation is supported.
|
||||
* Actually in only one case:
|
||||
@@ -606,10 +595,10 @@ class utils
|
||||
*/
|
||||
static function InitCASClient()
|
||||
{
|
||||
$sCASIncludePath = self::GetConfig()->Get('cas_include_path');
|
||||
$sCASIncludePath = MetaModel::GetConfig()->Get('cas_include_path');
|
||||
include_once($sCASIncludePath.'/CAS.php');
|
||||
|
||||
$bCASDebug = self::GetConfig()->Get('cas_debug');
|
||||
$bCASDebug = MetaModel::GetConfig()->Get('cas_debug');
|
||||
if ($bCASDebug)
|
||||
{
|
||||
phpCAS::setDebug(APPROOT.'/error.log');
|
||||
@@ -618,13 +607,13 @@ class utils
|
||||
if (!self::$m_bCASClient)
|
||||
{
|
||||
// Initialize phpCAS
|
||||
$sCASVersion = self::GetConfig()->Get('cas_version');
|
||||
$sCASHost = self::GetConfig()->Get('cas_host');
|
||||
$iCASPort = self::GetConfig()->Get('cas_port');
|
||||
$sCASContext = self::GetConfig()->Get('cas_context');
|
||||
$sCASVersion = MetaModel::GetConfig()->Get('cas_version');
|
||||
$sCASHost = MetaModel::GetConfig()->Get('cas_host');
|
||||
$iCASPort = MetaModel::GetConfig()->Get('cas_port');
|
||||
$sCASContext = MetaModel::GetConfig()->Get('cas_context');
|
||||
phpCAS::client($sCASVersion, $sCASHost, $iCASPort, $sCASContext, false /* session already started */);
|
||||
self::$m_bCASClient = true;
|
||||
$sCASCACertPath = self::GetConfig()->Get('cas_server_ca_cert_path');
|
||||
$sCASCACertPath = MetaModel::GetConfig()->Get('cas_server_ca_cert_path');
|
||||
if (empty($sCASCACertPath))
|
||||
{
|
||||
// If no certificate authority is provided, do not attempt to validate
|
||||
@@ -669,7 +658,7 @@ class utils
|
||||
throw new Exception("The PHP exec() function has been disabled on this server");
|
||||
}
|
||||
|
||||
$sPHPExec = trim(self::GetConfig()->Get('php_path'));
|
||||
$sPHPExec = trim(MetaModel::GetConfig()->Get('php_path'));
|
||||
if (strlen($sPHPExec) == 0)
|
||||
{
|
||||
throw new Exception("The path to php must not be empty. Please set a value for 'php_path' in your configuration file.");
|
||||
@@ -730,85 +719,6 @@ class utils
|
||||
return array($iRes, $aOutput);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current environment
|
||||
*/
|
||||
public static function GetCurrentEnvironment()
|
||||
{
|
||||
if (isset($_SESSION['itop_env']))
|
||||
{
|
||||
return $_SESSION['itop_env'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return ITOP_DEFAULT_ENV;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the "Back" button to go out of the current environment
|
||||
*/
|
||||
public static function GetEnvironmentBackButton()
|
||||
{
|
||||
if (isset($_SESSION['itop_return_env']))
|
||||
{
|
||||
if (isset($_SESSION['itop_return_url']))
|
||||
{
|
||||
$sReturnUrl = $_SESSION['itop_return_url'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$sReturnUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?switch_env='.$_SESSION['itop_return_env'];
|
||||
}
|
||||
return ' <button onclick="window;location.href=\''.addslashes($sReturnUrl).'\'">'.Dict::S('UI:Button:Back').'</button>';
|
||||
}
|
||||
else
|
||||
{
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the "Back" button to go out of the current environment
|
||||
*/
|
||||
public static function GetPopupMenuItems($oPage, $iMenuId, $param, &$aActions)
|
||||
{
|
||||
foreach (MetaModel::EnumPlugins('iPopupMenuExtension') as $oExtensionInstance)
|
||||
{
|
||||
foreach($oExtensionInstance->EnumItems($iMenuId, $param) as $oMenuItem)
|
||||
{
|
||||
if (is_object($oMenuItem))
|
||||
{
|
||||
$aActions[$oMenuItem->GetUID()] = $oMenuItem->GetMenuItem();
|
||||
|
||||
foreach($oMenuItem->GetLinkedScripts() as $sLinkedScript)
|
||||
{
|
||||
$oPage->add_linked_script($sLinkedScript);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get target configuration file name (including full path)
|
||||
*/
|
||||
public static function GetConfigFilePath($sEnvironment = null)
|
||||
{
|
||||
if (is_null($sEnvironment))
|
||||
{
|
||||
$sEnvironment = self::GetCurrentEnvironment();
|
||||
}
|
||||
return APPCONF.$sEnvironment.'/'.ITOP_CONFIG_FILE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute URL to the modules root path
|
||||
* @return string ...
|
||||
*/
|
||||
static public function GetAbsoluteUrlModulesRoot()
|
||||
{
|
||||
$sUrl = self::GetAbsoluteUrlAppRoot().'env-'.self::GetCurrentEnvironment().'/';
|
||||
return $sUrl;
|
||||
}
|
||||
}
|
||||
?>
|
||||
?>
|
||||
|
||||
@@ -23,22 +23,6 @@
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Generic interface common to CLI and Web pages
|
||||
*/
|
||||
Interface Page
|
||||
{
|
||||
public function output();
|
||||
public function add($sText);
|
||||
public function p($sText);
|
||||
public function pre($sText);
|
||||
public function add_comment($sText);
|
||||
public function table($aConfig, $aData, $aParams = array());
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Simple helper class to ease the production of HTML pages
|
||||
*
|
||||
@@ -50,7 +34,7 @@ Interface Page
|
||||
* $oPage->p("Hello World !");
|
||||
* $oPage->output();
|
||||
*/
|
||||
class WebPage implements Page
|
||||
class WebPage
|
||||
{
|
||||
protected $s_title;
|
||||
protected $s_content;
|
||||
@@ -141,13 +125,6 @@ class WebPage implements Page
|
||||
$this->add('<pre>'.$s_html.'</pre>');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a comment
|
||||
*/
|
||||
public function add_comment($sText)
|
||||
{
|
||||
$this->add('<!--'.$sText.'-->');
|
||||
}
|
||||
/**
|
||||
* Add a paragraph to the body of the page
|
||||
*/
|
||||
@@ -604,36 +581,5 @@ class WebPage implements Page
|
||||
$this->a_OutputOptions[$sFormat][$sOptionName] = $sValue;
|
||||
}
|
||||
}
|
||||
|
||||
public function RenderPopupMenuItems($aActions, $aFavoriteActions = array())
|
||||
{
|
||||
$sPrevUrl = '';
|
||||
$sHtml = '';
|
||||
foreach ($aActions as $aAction)
|
||||
{
|
||||
$sClass = isset($aAction['class']) ? " class=\"{$aAction['class']}\"" : "";
|
||||
$sOnClick = isset($aAction['onclick']) ? " onclick=\"{$aAction['onclick']}\"" : "";
|
||||
if (empty($aAction['url']))
|
||||
{
|
||||
if ($sPrevUrl != '') // Don't output consecutively two separators...
|
||||
{
|
||||
$sHtml .= "<li>{$aAction['label']}</li>";
|
||||
}
|
||||
$sPrevUrl = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sHtml .= "<li><a href=\"{$aAction['url']}\"$sClass $sOnClick>{$aAction['label']}</a></li>";
|
||||
$sPrevUrl = $aAction['url'];
|
||||
}
|
||||
}
|
||||
$sHtml .= "</ul></li></ul></div>";
|
||||
foreach(array_reverse($aFavoriteActions) as $aAction)
|
||||
{
|
||||
$sHtml .= "<div class=\"actions_button\"><a href='{$aAction['url']}'>{$aAction['label']}</a></div>";
|
||||
}
|
||||
|
||||
return $sHtml;
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -76,7 +76,7 @@ class WizardHelper
|
||||
if ( isset($aLinkedObject[$sLinkedAttCode]) && ($aLinkedObject[$sLinkedAttCode] !== null) )
|
||||
{
|
||||
$sLinkedAttDef = MetaModel::GetAttributeDef($sLinkedClass, $sLinkedAttCode);
|
||||
if (($sLinkedAttDef->IsExternalKey()) && ($aLinkedObject[$sLinkedAttCode] != '') && ($aLinkedObject[$sLinkedAttCode] > 0) )
|
||||
if (($sLinkedAttDef->IsExternalKey()) && ($aLinkedObject[$sLinkedAttCode] != '') && ($aLinkedObject[$sLinkedAttCode] != 0) )
|
||||
{
|
||||
// For external keys: load the target object so that external fields
|
||||
// get filled too
|
||||
@@ -108,7 +108,7 @@ class WizardHelper
|
||||
$oObj->Set($sAttCode, $oDocument);
|
||||
}
|
||||
}
|
||||
else if (($oAttDef->IsExternalKey()) && (!empty($value)) && ($value > 0) )
|
||||
else if (($oAttDef->IsExternalKey()) && (!empty($value)) )
|
||||
{
|
||||
// For external keys: load the target object so that external fields
|
||||
// get filled too
|
||||
@@ -260,7 +260,7 @@ class WizardHelper
|
||||
foreach($aLinkObj as $sAttCode => $value)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sLinkClass, $sAttCode);
|
||||
if (($oAttDef->IsExternalKey()) && ($value != '') && ($value > 0))
|
||||
if (($oAttDef->IsExternalKey()) && ($value != '') )
|
||||
{
|
||||
// For external keys: load the target object so that external fields
|
||||
// get filled too
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
<?php
|
||||
|
||||
define('APPROOT', dirname(__FILE__).'/');
|
||||
define('APPCONF', APPROOT.'conf/');
|
||||
define('ITOP_DEFAULT_ENV', 'production');
|
||||
|
||||
define('MODULESROOT', APPROOT.'modules/');
|
||||
if (function_exists('microtime'))
|
||||
{
|
||||
$fItopStarted = microtime(true);
|
||||
|
||||
@@ -276,6 +276,7 @@ class ActionEmail extends ActionNotification
|
||||
protected function _DoExecute($oTrigger, $aContextArgs, &$oLog)
|
||||
{
|
||||
$sPreviousUrlMaker = ApplicationContext::SetUrlMakerClass();
|
||||
$aHeaders = array();
|
||||
try
|
||||
{
|
||||
$this->m_iRecipients = 0;
|
||||
@@ -295,8 +296,9 @@ class ActionEmail extends ActionNotification
|
||||
$sBody = MetaModel::ApplyParams($this->Get('body'), $aContextArgs);
|
||||
|
||||
$oObj = $aContextArgs['this->object()'];
|
||||
$sMessageId = sprintf('iTop_%s_%d_%f@%s.openitop.org', get_class($oObj), $oObj->GetKey(), microtime(true /* get as float*/), MetaModel::GetEnvironmentId());
|
||||
$sReference = '<'.$sMessageId.'>';
|
||||
$sMessageId = sprintf('<iTop_%s_%d_%f@%s.openitop.org>', get_class($oObj), $oObj->GetKey(), microtime(true /* get as float*/), MetaModel::GetConfig()->Get('session_name'));
|
||||
$sReference = $sMessageId;
|
||||
$aHeaders['Message-ID'] = $sMessageId;
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
@@ -318,7 +320,7 @@ class ActionEmail extends ActionNotification
|
||||
if (isset($sBody)) $oLog->Set('body', $sBody);
|
||||
}
|
||||
|
||||
$oEmail = new EMail();
|
||||
$oEmail = new EMail('', '', '', $aHeaders);
|
||||
|
||||
if ($this->IsBeingTested())
|
||||
{
|
||||
@@ -341,7 +343,6 @@ class ActionEmail extends ActionNotification
|
||||
$oEmail->SetRecipientTO($this->Get('test_recipient'));
|
||||
$oEmail->SetRecipientFrom($this->Get('test_recipient'));
|
||||
$oEmail->SetReferences($sReference);
|
||||
$oEmail->SetMessageId($sMessageId);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -353,7 +354,6 @@ class ActionEmail extends ActionNotification
|
||||
$oEmail->SetRecipientFrom($sFrom);
|
||||
$oEmail->SetRecipientReplyTo($sReplyTo);
|
||||
$oEmail->SetReferences($sReference);
|
||||
$oEmail->SetMessageId($sMessageId);
|
||||
}
|
||||
|
||||
if (empty($this->m_aMailErrors))
|
||||
|
||||
@@ -140,7 +140,8 @@ class AsyncSendEmail extends AsyncTask
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeText("to", array("allowed_values"=>null, "sql"=>"to", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("subject", array("allowed_values"=>null, "sql"=>"subject", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeLongText("message", array("allowed_values"=>null, "sql"=>"message", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeLongText("body", array("allowed_values"=>null, "sql"=>"body", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("header", array("allowed_values"=>null, "sql"=>"header", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
// MetaModel::Init_SetZListItems('details', array('name', 'description', 'status', 'test_recipient', 'from', 'reply_to', 'to', 'cc', 'bcc', 'subject', 'body', 'importance', 'trigger_list')); // Attributes to be displayed for the complete details
|
||||
@@ -150,26 +151,31 @@ class AsyncSendEmail extends AsyncTask
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
|
||||
static public function AddToQueue(EMail $oEMail, $oLog)
|
||||
static public function AddToQueue($sTo, $sSubject, $sBody, $aHeaders, $oLog)
|
||||
{
|
||||
$oNew = MetaModel::NewObject(__class__);
|
||||
if ($oLog)
|
||||
{
|
||||
$oNew->Set('event_id', $oLog->GetKey());
|
||||
}
|
||||
$oNew->Set('to', $oEMail->GetRecipientTO(true /* string */));
|
||||
$oNew->Set('subject', $oEMail->GetSubject());
|
||||
|
||||
$sMessage = serialize($oEMail);
|
||||
$oNew->Set('message', $sMessage);
|
||||
$oNew->Set('to', $sTo);
|
||||
$oNew->Set('subject', $sSubject);
|
||||
$oNew->Set('body', $sBody);
|
||||
$sHeaders = serialize($aHeaders);
|
||||
$oNew->Set('header', $sHeaders);
|
||||
$oNew->DBInsert();
|
||||
}
|
||||
|
||||
public function DoProcess()
|
||||
{
|
||||
$sMessage = $this->Get('message');
|
||||
$oEMail = unserialize($sMessage);
|
||||
$iRes = $oEMail->Send($aIssues, true /* force synchro !!!!! */);
|
||||
$sTo = $this->Get('to');
|
||||
$sSubject = $this->Get('subject');
|
||||
$sBody = $this->Get('body');
|
||||
$sHeaders = $this->Get('header');
|
||||
$aHeaders = unserialize($sHeaders);
|
||||
|
||||
$oEmail = new EMail($sTo, $sSubject, $sBody, $aHeaders);
|
||||
$iRes = $oEmail->Send($aIssues, true /* force synchro !!!!! */);
|
||||
switch ($iRes)
|
||||
{
|
||||
case EMAIL_SEND_OK:
|
||||
@@ -183,4 +189,4 @@ class AsyncSendEmail extends AsyncTask
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
?>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -914,7 +914,7 @@ class BulkChange
|
||||
$bLimitExceeded = true;
|
||||
if (!$bShowAll)
|
||||
{
|
||||
$iMaxObjects = appUserPreferences::GetPref('default_page_size', MetaModel::GetConfig()->GetMinDisplayLimit());
|
||||
$iMaxObjects = MetaModel::GetConfig()->GetMinDisplayLimit();
|
||||
$oBulkChanges->SetLimit($iMaxObjects);
|
||||
}
|
||||
}
|
||||
@@ -923,7 +923,7 @@ class BulkChange
|
||||
$aDetails = array();
|
||||
while ($oChange = $oBulkChanges->Fetch())
|
||||
{
|
||||
$sDate = '<a href="csvimport.php?step=10&changeid='.$oChange->GetKey().'&'.$oAppContext->GetForLink().'">'.$oChange->Get('date').'</a>';
|
||||
$sDate = '<a href="?step=10&changeid='.$oChange->GetKey().'&'.$oAppContext->GetForLink().'">'.$oChange->Get('date').'</a>';
|
||||
$sUser = $oChange->GetUserName();
|
||||
if (preg_match('/^(.*)\\(CSV\\)$/i', $oChange->Get('userinfo'), $aMatches))
|
||||
{
|
||||
|
||||
@@ -200,6 +200,9 @@ class CMDBChangeOpSetAttributeScalar extends CMDBChangeOpSetAttribute
|
||||
*/
|
||||
public function GetDescription()
|
||||
{
|
||||
// Temporary, until we change the options of GetDescription() -needs a more global revision
|
||||
$bIsHtml = true;
|
||||
|
||||
$sResult = '';
|
||||
$oTargetObjectClass = $this->Get('objclass');
|
||||
$oTargetObjectKey = $this->Get('objkey');
|
||||
@@ -215,7 +218,76 @@ class CMDBChangeOpSetAttributeScalar extends CMDBChangeOpSetAttribute
|
||||
$sAttName = $oAttDef->GetLabel();
|
||||
$sNewValue = $this->Get('newvalue');
|
||||
$sOldValue = $this->Get('oldvalue');
|
||||
$sResult = $oAttDef->GetAsHTMLForHistory($sOldValue, $sNewValue);
|
||||
if ($oAttDef instanceof AttributeEnum)
|
||||
{
|
||||
// translate the enum values
|
||||
$sOldValue = $oAttDef->GetAsHTML($sOldValue);
|
||||
$sNewValue = $oAttDef->GetAsHTML($sNewValue);
|
||||
if (strlen($sOldValue) == 0)
|
||||
{
|
||||
$sResult = Dict::Format('Change:AttName_SetTo', $sAttName, $sNewValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sResult = Dict::Format('Change:AttName_SetTo_NewValue_PreviousValue_OldValue', $sAttName, $sNewValue, $sOldValue);
|
||||
}
|
||||
}
|
||||
elseif ( (($oAttDef->GetType() == 'String') || ($oAttDef->GetType() == 'Text')) &&
|
||||
(strlen($sNewValue) > strlen($sOldValue)) )
|
||||
{
|
||||
// Check if some text was not appended to the field
|
||||
if (substr($sNewValue,0, strlen($sOldValue)) == $sOldValue) // Text added at the end
|
||||
{
|
||||
$sDelta = substr($sNewValue, strlen($sOldValue));
|
||||
$sResult = Dict::Format('Change:Text_AppendedTo_AttName', $sDelta, $sAttName);
|
||||
}
|
||||
else if (substr($sNewValue, -strlen($sOldValue)) == $sOldValue) // Text added at the beginning
|
||||
{
|
||||
$sDelta = substr($sNewValue, 0, strlen($sNewValue) - strlen($sOldValue));
|
||||
$sResult = Dict::Format('Change:Text_AppendedTo_AttName', $sDelta, $sAttName);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strlen($sOldValue) == 0)
|
||||
{
|
||||
$sResult = Dict::Format('Change:AttName_SetTo', $sAttName, $sNewValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sResult = Dict::Format('Change:AttName_SetTo_NewValue_PreviousValue_OldValue', $sAttName, $sNewValue, $sOldValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif($bIsHtml && $oAttDef->IsExternalKey())
|
||||
{
|
||||
$sTargetClass = $oAttDef->GetTargetClass();
|
||||
$sFrom = MetaModel::GetHyperLink($sTargetClass, $sOldValue);
|
||||
$sTo = MetaModel::GetHyperLink($sTargetClass, $sNewValue);
|
||||
$sResult = "$sAttName set to $sTo (previous: $sFrom)";
|
||||
if (strlen($sFrom) == 0)
|
||||
{
|
||||
$sResult = Dict::Format('Change:AttName_SetTo', $sAttName, $sTo);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sResult = Dict::Format('Change:AttName_SetTo_NewValue_PreviousValue_OldValue', $sAttName, $sTo, $sFrom);
|
||||
}
|
||||
}
|
||||
elseif ($oAttDef instanceOf AttributeBlob)
|
||||
{
|
||||
$sResult = "#@# Issue... found an attribute for which other type of tracking should be made";
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strlen($sOldValue) == 0)
|
||||
{
|
||||
$sResult = Dict::Format('Change:AttName_SetTo', $sAttName, $sNewValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sResult = Dict::Format('Change:AttName_SetTo_NewValue_PreviousValue_OldValue', $sAttName, $sNewValue, $sOldValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $sResult;
|
||||
}
|
||||
|
||||
@@ -133,18 +133,8 @@ abstract class CMDBObject extends DBObject
|
||||
foreach ($aValues as $sAttCode=> $value)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
|
||||
if ($oAttDef->IsExternalField()) continue; // #@# temporary
|
||||
if ($oAttDef->IsLinkSet()) continue; // #@# temporary
|
||||
|
||||
if (array_key_exists($sAttCode, $aOrigValues))
|
||||
{
|
||||
$original = $aOrigValues[$sAttCode];
|
||||
}
|
||||
else
|
||||
{
|
||||
$original = null;
|
||||
}
|
||||
|
||||
if ($oAttDef instanceOf AttributeOneWayPassword)
|
||||
{
|
||||
// One Way encrypted passwords' history is stored -one way- encrypted
|
||||
@@ -154,7 +144,11 @@ abstract class CMDBObject extends DBObject
|
||||
$oMyChangeOp->Set("objkey", $this->GetKey());
|
||||
$oMyChangeOp->Set("attcode", $sAttCode);
|
||||
|
||||
if (is_null($original))
|
||||
if (array_key_exists($sAttCode, $aOrigValues))
|
||||
{
|
||||
$original = $aOrigValues[$sAttCode];
|
||||
}
|
||||
else
|
||||
{
|
||||
$original = '';
|
||||
}
|
||||
@@ -170,7 +164,11 @@ abstract class CMDBObject extends DBObject
|
||||
$oMyChangeOp->Set("objkey", $this->GetKey());
|
||||
$oMyChangeOp->Set("attcode", $sAttCode);
|
||||
|
||||
if (is_null($original))
|
||||
if (array_key_exists($sAttCode, $aOrigValues))
|
||||
{
|
||||
$original = $aOrigValues[$sAttCode];
|
||||
}
|
||||
else
|
||||
{
|
||||
$original = '';
|
||||
}
|
||||
@@ -186,40 +184,17 @@ abstract class CMDBObject extends DBObject
|
||||
$oMyChangeOp->Set("objkey", $this->GetKey());
|
||||
$oMyChangeOp->Set("attcode", $sAttCode);
|
||||
|
||||
if (is_null($original))
|
||||
if (array_key_exists($sAttCode, $aOrigValues))
|
||||
{
|
||||
$original = $aOrigValues[$sAttCode];
|
||||
}
|
||||
else
|
||||
{
|
||||
$original = new ormDocument();
|
||||
}
|
||||
$oMyChangeOp->Set("prevdata", $original);
|
||||
$iId = $oMyChangeOp->DBInsertNoReload();
|
||||
}
|
||||
elseif ($oAttDef instanceOf AttributeStopWatch)
|
||||
{
|
||||
// Stop watches - record changes for sub items only (they are visible, the rest is not visible)
|
||||
//
|
||||
if (is_null($original))
|
||||
{
|
||||
$original = new OrmStopWatch();
|
||||
}
|
||||
foreach ($oAttDef->ListSubItems() as $sSubItemAttCode => $oSubItemAttDef)
|
||||
{
|
||||
$item_value = $oSubItemAttDef->GetValue($value);
|
||||
$item_original = $oSubItemAttDef->GetValue($original);
|
||||
|
||||
if ($item_value != $item_original)
|
||||
{
|
||||
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttributeScalar");
|
||||
$oMyChangeOp->Set("change", $oChange->GetKey());
|
||||
$oMyChangeOp->Set("objclass", get_class($this));
|
||||
$oMyChangeOp->Set("objkey", $this->GetKey());
|
||||
$oMyChangeOp->Set("attcode", $sSubItemAttCode);
|
||||
|
||||
$oMyChangeOp->Set("oldvalue", $item_original);
|
||||
$oMyChangeOp->Set("newvalue", $item_value);
|
||||
$iId = $oMyChangeOp->DBInsertNoReload();
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif ($oAttDef instanceOf AttributeCaseLog)
|
||||
{
|
||||
$oMyChangeOp = MetaModel::NewObject("CMDBChangeOpSetAttributeCaseLog");
|
||||
@@ -240,9 +215,17 @@ abstract class CMDBObject extends DBObject
|
||||
$oMyChangeOp->Set("objkey", $this->GetKey());
|
||||
$oMyChangeOp->Set("attcode", $sAttCode);
|
||||
|
||||
if (!is_null($original) && ($original instanceof ormCaseLog))
|
||||
if (array_key_exists($sAttCode, $aOrigValues))
|
||||
{
|
||||
$original = $original->GetText();
|
||||
$original = $aOrigValues[$sAttCode];
|
||||
if ($original instanceof ormCaseLog)
|
||||
{
|
||||
$original = $original->GetText();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$original = null;
|
||||
}
|
||||
$oMyChangeOp->Set("prevdata", $original);
|
||||
$iId = $oMyChangeOp->DBInsertNoReload();
|
||||
@@ -256,7 +239,16 @@ abstract class CMDBObject extends DBObject
|
||||
$oMyChangeOp->Set("objclass", get_class($this));
|
||||
$oMyChangeOp->Set("objkey", $this->GetKey());
|
||||
$oMyChangeOp->Set("attcode", $sAttCode);
|
||||
$oMyChangeOp->Set("oldvalue", $original);
|
||||
|
||||
if (array_key_exists($sAttCode, $aOrigValues))
|
||||
{
|
||||
$sOriginalValue = $aOrigValues[$sAttCode];
|
||||
}
|
||||
else
|
||||
{
|
||||
$sOriginalValue = 'undefined';
|
||||
}
|
||||
$oMyChangeOp->Set("oldvalue", $sOriginalValue);
|
||||
$oMyChangeOp->Set("newvalue", $value);
|
||||
$iId = $oMyChangeOp->DBInsertNoReload();
|
||||
}
|
||||
|
||||
@@ -24,14 +24,13 @@
|
||||
*/
|
||||
|
||||
require_once('MyHelpers.class.inc.php');
|
||||
require_once(APPROOT.'core/kpi.class.inc.php');
|
||||
|
||||
class MySQLException extends CoreException
|
||||
{
|
||||
public function __construct($sIssue, $aContext)
|
||||
{
|
||||
$aContext['mysql_error'] = CMDBSource::GetError();
|
||||
$aContext['mysql_errno'] = CMDBSource::GetErrNo();;
|
||||
$aContext['mysql_error'] = mysql_error();
|
||||
$aContext['mysql_errno'] = mysql_errno();
|
||||
parent::__construct($sIssue, $aContext);
|
||||
}
|
||||
}
|
||||
@@ -57,13 +56,13 @@ class CMDBSource
|
||||
self::$m_sDBUser = $sUser;
|
||||
self::$m_sDBPwd = $sPwd;
|
||||
self::$m_sDBName = $sSource;
|
||||
if (!self::$m_resDBLink = @mysqli_connect($sServer, $sUser, $sPwd))
|
||||
if (!self::$m_resDBLink = mysql_connect($sServer, $sUser, $sPwd))
|
||||
{
|
||||
throw new MySQLException('Could not connect to the DB server', array('host'=>$sServer, 'user'=>$sUser));
|
||||
}
|
||||
if (!empty($sSource))
|
||||
{
|
||||
if (!((bool)mysqli_query(self::$m_resDBLink, "USE $sSource")))
|
||||
if (!mysql_select_db($sSource, self::$m_resDBLink))
|
||||
{
|
||||
throw new MySQLException('Could not select DB', array('host'=>$sServer, 'user'=>$sUser, 'db_name'=>$sSource));
|
||||
}
|
||||
@@ -119,7 +118,7 @@ class CMDBSource
|
||||
{
|
||||
// In case we don't have rights to enumerate the databases
|
||||
// Let's try to connect directly
|
||||
return @((bool)mysqli_query(self::$m_resDBLink, "USE $sSource"));
|
||||
return @mysql_select_db($sSource, self::$m_resDBLink);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -132,7 +131,7 @@ class CMDBSource
|
||||
|
||||
public static function SelectDB($sSource)
|
||||
{
|
||||
if (!((bool)mysqli_query(self::$m_resDBLink, "USE $sSource")))
|
||||
if (!mysql_select_db($sSource, self::$m_resDBLink))
|
||||
{
|
||||
throw new MySQLException('Could not select DB', array('db_name'=>$sSource));
|
||||
}
|
||||
@@ -172,30 +171,6 @@ class CMDBSource
|
||||
return $res;
|
||||
}
|
||||
|
||||
public static function GetErrNo()
|
||||
{
|
||||
if (self::$m_resDBLink)
|
||||
{
|
||||
return mysqli_errno(self::$m_resDBLink);
|
||||
}
|
||||
else
|
||||
{
|
||||
return mysqli_connect_errno();
|
||||
}
|
||||
}
|
||||
|
||||
public static function GetError()
|
||||
{
|
||||
if (self::$m_resDBLink)
|
||||
{
|
||||
return mysqli_error(self::$m_resDBLink);
|
||||
}
|
||||
else
|
||||
{
|
||||
return mysqli_connect_error();
|
||||
}
|
||||
}
|
||||
|
||||
public static function DBHost() {return self::$m_sDBHost;}
|
||||
public static function DBUser() {return self::$m_sDBUser;}
|
||||
public static function DBPwd() {return self::$m_sDBPwd;}
|
||||
@@ -233,7 +208,7 @@ class CMDBSource
|
||||
// Quote if not a number or a numeric string
|
||||
if ($bAlways || is_string($value))
|
||||
{
|
||||
$value = $cQuoteStyle . mysqli_real_escape_string(self::$m_resDBLink, $value) . $cQuoteStyle;
|
||||
$value = $cQuoteStyle . mysql_real_escape_string($value, self::$m_resDBLink) . $cQuoteStyle;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
@@ -247,7 +222,7 @@ class CMDBSource
|
||||
// $sSQLQuery .= MyHelpers::MakeSQLComment($aTraceInf);
|
||||
|
||||
$oKPI = new ExecutionKPI();
|
||||
$result = mysqli_query(self::$m_resDBLink, $sSQLQuery);
|
||||
$result = mysql_query($sSQLQuery, self::$m_resDBLink);
|
||||
if (!$result)
|
||||
{
|
||||
throw new MySQLException('Failed to issue SQL query', array('query' => $sSQLQuery));
|
||||
@@ -261,21 +236,15 @@ class CMDBSource
|
||||
{
|
||||
$sSQL = "SHOW TABLE STATUS LIKE '$sTable'";
|
||||
$result = self::Query($sSQL);
|
||||
$aRow = mysqli_fetch_assoc($result);
|
||||
$aRow = mysql_fetch_assoc($result);
|
||||
$iNextInsertId = $aRow['Auto_increment'];
|
||||
return $iNextInsertId;
|
||||
}
|
||||
|
||||
public static function GetInsertId()
|
||||
{
|
||||
$iRes = mysqli_insert_id(self::$m_resDBLink);
|
||||
if (is_null($iRes))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return $iRes;
|
||||
return mysql_insert_id(self::$m_resDBLink);
|
||||
}
|
||||
|
||||
public static function InsertInto($sSQLQuery)
|
||||
{
|
||||
if (self::Query($sSQLQuery))
|
||||
@@ -292,37 +261,37 @@ class CMDBSource
|
||||
|
||||
public static function QueryToScalar($sSql)
|
||||
{
|
||||
$result = mysqli_query(self::$m_resDBLink, $sSql);
|
||||
$result = mysql_query($sSql, self::$m_resDBLink);
|
||||
if (!$result)
|
||||
{
|
||||
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql));
|
||||
}
|
||||
if ($aRow = mysqli_fetch_array($result, MYSQLI_BOTH))
|
||||
if ($aRow = mysql_fetch_array($result, MYSQL_BOTH))
|
||||
{
|
||||
$res = $aRow[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
mysqli_free_result($result);
|
||||
mysql_free_result($result);
|
||||
throw new MySQLException('Found no result for query', array('query' => $sSql));
|
||||
}
|
||||
mysqli_free_result($result);
|
||||
mysql_free_result($result);
|
||||
return $res;
|
||||
}
|
||||
|
||||
public static function QueryToArray($sSql)
|
||||
{
|
||||
$aData = array();
|
||||
$result = mysqli_query(self::$m_resDBLink, $sSql);
|
||||
$result = mysql_query($sSql, self::$m_resDBLink);
|
||||
if (!$result)
|
||||
{
|
||||
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql));
|
||||
}
|
||||
while ($aRow = mysqli_fetch_array($result, MYSQLI_BOTH))
|
||||
while ($aRow = mysql_fetch_array($result, MYSQL_BOTH))
|
||||
{
|
||||
$aData[] = $aRow;
|
||||
}
|
||||
mysqli_free_result($result);
|
||||
mysql_free_result($result);
|
||||
return $aData;
|
||||
}
|
||||
|
||||
@@ -340,7 +309,7 @@ class CMDBSource
|
||||
public static function ExplainQuery($sSql)
|
||||
{
|
||||
$aData = array();
|
||||
$result = mysqli_query(self::$m_resDBLink, "EXPLAIN $sSql");
|
||||
$result = mysql_query("EXPLAIN $sSql", self::$m_resDBLink);
|
||||
if (!$result)
|
||||
{
|
||||
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql));
|
||||
@@ -349,62 +318,62 @@ class CMDBSource
|
||||
$aNames = self::GetColumns($result);
|
||||
|
||||
$aData[] = $aNames;
|
||||
while ($aRow = mysqli_fetch_array($result, MYSQLI_ASSOC))
|
||||
while ($aRow = mysql_fetch_array($result, MYSQL_ASSOC))
|
||||
{
|
||||
$aData[] = $aRow;
|
||||
}
|
||||
mysqli_free_result($result);
|
||||
mysql_free_result($result);
|
||||
return $aData;
|
||||
}
|
||||
|
||||
public static function TestQuery($sSql)
|
||||
{
|
||||
$result = mysqli_query(self::$m_resDBLink, "EXPLAIN $sSql");
|
||||
$result = mysql_query("EXPLAIN $sSql", self::$m_resDBLink);
|
||||
if (!$result)
|
||||
{
|
||||
return self::GetError();
|
||||
return mysql_error();
|
||||
}
|
||||
|
||||
mysqli_free_result($result);
|
||||
mysql_free_result($result);
|
||||
return '';
|
||||
}
|
||||
|
||||
public static function NbRows($result)
|
||||
{
|
||||
return mysqli_num_rows($result);
|
||||
return mysql_num_rows($result);
|
||||
}
|
||||
|
||||
public static function FetchArray($result)
|
||||
{
|
||||
return mysqli_fetch_array($result, MYSQLI_ASSOC);
|
||||
return mysql_fetch_array($result, MYSQL_ASSOC);
|
||||
}
|
||||
|
||||
public static function GetColumns($result)
|
||||
{
|
||||
$aNames = array();
|
||||
for ($i = 0; $i < (($___mysqli_tmp = mysqli_num_fields($result)) ? $___mysqli_tmp : 0) ; $i++)
|
||||
for ($i = 0; $i < mysql_num_fields($result) ; $i++)
|
||||
{
|
||||
$meta = mysqli_fetch_field_direct($result, $i);
|
||||
if (!$meta)
|
||||
{
|
||||
$meta = mysql_fetch_field($result, $i);
|
||||
if (!$meta)
|
||||
{
|
||||
throw new MySQLException('mysql_fetch_field: No information available', array('query'=>$sSql, 'i'=>$i));
|
||||
}
|
||||
else
|
||||
{
|
||||
$aNames[] = $meta->name;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aNames[] = $meta->name;
|
||||
}
|
||||
}
|
||||
return $aNames;
|
||||
}
|
||||
|
||||
public static function Seek($result, $iRow)
|
||||
{
|
||||
return mysqli_data_seek($result, $iRow);
|
||||
return mysql_data_seek($result, $iRow);
|
||||
}
|
||||
|
||||
public static function FreeResult($result)
|
||||
{
|
||||
return ((mysqli_free_result($result) || (is_object($result) && (get_class($result) == "mysqli_result"))) ? true : false);
|
||||
return mysql_free_result($result);
|
||||
}
|
||||
|
||||
public static function IsTable($sTable)
|
||||
@@ -542,18 +511,18 @@ class CMDBSource
|
||||
public static function DumpTable($sTable)
|
||||
{
|
||||
$sSql = "SELECT * FROM `$sTable`";
|
||||
$result = mysqli_query(self::$m_resDBLink, $sSql);
|
||||
$result = mysql_query($sSql, self::$m_resDBLink);
|
||||
if (!$result)
|
||||
{
|
||||
throw new MySQLException('Failed to issue SQL query', array('query' => $sSql));
|
||||
}
|
||||
|
||||
$aRows = array();
|
||||
while ($aRow = mysqli_fetch_array($result, MYSQLI_ASSOC))
|
||||
while ($aRow = mysql_fetch_array($result, MYSQL_ASSOC))
|
||||
{
|
||||
$aRows[] = $aRow;
|
||||
}
|
||||
mysqli_free_result($result);
|
||||
mysql_free_result($result);
|
||||
return $aRows;
|
||||
}
|
||||
|
||||
@@ -591,12 +560,12 @@ class CMDBSource
|
||||
}
|
||||
|
||||
$aRes = array();
|
||||
while ($aRow = mysqli_fetch_array($result, MYSQLI_NUM))
|
||||
while ($aRow = mysql_fetch_array($result, MYSQL_NUM))
|
||||
{
|
||||
// so far, only one column...
|
||||
$aRes[] = implode('/', $aRow);
|
||||
}
|
||||
mysqli_free_result($result);
|
||||
mysql_free_result($result);
|
||||
// so far, only one line...
|
||||
return implode(', ', $aRes);
|
||||
}
|
||||
@@ -616,14 +585,14 @@ class CMDBSource
|
||||
throw new CoreException("Current user not allowed to check the status", array('mysql_error' => $e->getMessage()));
|
||||
}
|
||||
|
||||
if (mysqli_num_rows($result) == 0)
|
||||
if (mysql_num_rows($result) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Returns one single row anytime
|
||||
$aRow = mysqli_fetch_array($result, MYSQLI_ASSOC);
|
||||
mysqli_free_result($result);
|
||||
$aRow = mysql_fetch_array($result, MYSQL_ASSOC);
|
||||
mysql_free_result($result);
|
||||
|
||||
if (!isset($aRow['Slave_IO_Running']))
|
||||
{
|
||||
|
||||
@@ -1,121 +0,0 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
* Any extension to compute things like a stop watch deadline or working hours
|
||||
*
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
/**
|
||||
* Metric computing for stop watches
|
||||
*/
|
||||
interface iMetricComputer
|
||||
{
|
||||
public static function GetDescription();
|
||||
public function ComputeMetric($oObject);
|
||||
}
|
||||
|
||||
/**
|
||||
* Working time computing for stop watches
|
||||
*/
|
||||
interface iWorkingTimeComputer
|
||||
{
|
||||
public static function GetDescription();
|
||||
|
||||
/**
|
||||
* Get the date/time corresponding to a given delay in the future from the present
|
||||
* considering only the valid (open) hours for a specified object
|
||||
* @param $oObject DBObject The object for which to compute the deadline
|
||||
* @param $iDuration integer The duration (in seconds) in the future
|
||||
* @param $oStartDate DateTime The starting point for the computation
|
||||
* @return DateTime The date/time for the deadline
|
||||
*/
|
||||
public function GetDeadline($oObject, $iDuration, DateTime $oStartDate);
|
||||
|
||||
/**
|
||||
* Get duration (considering only open hours) elapsed bewteen two given DateTimes
|
||||
* @param $oObject DBObject The object for which to compute the duration
|
||||
* @param $oStartDate DateTime The starting point for the computation (default = now)
|
||||
* @param $oEndDate DateTime The ending point for the computation (default = now)
|
||||
* @return integer The duration (number of seconds) of open hours elapsed between the two dates
|
||||
*/
|
||||
public function GetOpenDuration($oObject, DateTime $oStartDate, DateTime $oEndDate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Default implementation oof deadline computing: NO deadline
|
||||
*/
|
||||
class DefaultMetricComputer implements iMetricComputer
|
||||
{
|
||||
public static function GetDescription()
|
||||
{
|
||||
return "Null";
|
||||
}
|
||||
|
||||
public function ComputeMetric($oObject)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Default implementation of working time computing
|
||||
*/
|
||||
class DefaultWorkingTimeComputer implements iWorkingTimeComputer
|
||||
{
|
||||
public static function GetDescription()
|
||||
{
|
||||
return "24x7, no holidays";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the date/time corresponding to a given delay in the future from the present
|
||||
* considering only the valid (open) hours for a specified object
|
||||
* @param $oObject DBObject The object for which to compute the deadline
|
||||
* @param $iDuration integer The duration (in seconds) in the future
|
||||
* @param $oStartDate DateTime The starting point for the computation
|
||||
* @return DateTime The date/time for the deadline
|
||||
*/
|
||||
public function GetDeadline($oObject, $iDuration, DateTime $oStartDate)
|
||||
{
|
||||
//echo "GetDeadline - default: ".$oStartDate->format('Y-m-d H:i:s')." + $iDuration<br/>\n";
|
||||
// Default implementation: 24x7, no holidays: to compute the deadline, just add
|
||||
// the specified duration to the given date/time
|
||||
$oResult = clone $oStartDate;
|
||||
$oResult->modify('+'.$iDuration.' seconds');
|
||||
return $oResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get duration (considering only open hours) elapsed bewteen two given DateTimes
|
||||
* @param $oObject DBObject The object for which to compute the duration
|
||||
* @param $oStartDate DateTime The starting point for the computation (default = now)
|
||||
* @param $oEndDate DateTime The ending point for the computation (default = now)
|
||||
* @return integer The duration (number of seconds) of open hours elapsed between the two dates
|
||||
*/
|
||||
public function GetOpenDuration($oObject, DateTime $oStartDate, DateTime $oEndDate)
|
||||
{
|
||||
//echo "GetOpenDuration - default: ".$oStartDate->format('Y-m-d H:i:s')." to ".$oEndDate->format('Y-m-d H:i:s')."<br/>\n";
|
||||
return abs($oEndDate->format('U') - $oStartDate->format('U'));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
@@ -84,14 +84,6 @@ class Config
|
||||
// New way to store the settings !
|
||||
//
|
||||
protected $m_aSettings = array(
|
||||
'app_env_label' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'Label displayed to describe the current application environnment, defaults to the environment name (e.g. "production")',
|
||||
'default' => '',
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'app_root_url' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'Root URL used for navigating within the application, or from an email to the application (you can put $SERVER_NAME$ as a placeholder for the server\'s name)',
|
||||
@@ -205,6 +197,14 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'csv_import_history_display' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Display the history tab in the import wizard',
|
||||
'default' => true,
|
||||
'value' => true,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'access_mode' => array(
|
||||
'type' => 'integer',
|
||||
'description' => 'Combination of flags (ACCESS_USER_WRITE | ACCESS_ADMIN_WRITE, or ACCESS_FULL)',
|
||||
@@ -301,54 +301,6 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'email_transport' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'Mean to send emails: PHPMail (uses the function mail()) or SMTP (implements the client protocole)',
|
||||
'default' => "PHPMail",
|
||||
'value' => "PHPMail",
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'email_transport_smtp.host' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'host name or IP address (optional)',
|
||||
'default' => "localhost",
|
||||
'value' => "localhost",
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'email_transport_smtp.port' => array(
|
||||
'type' => 'integer',
|
||||
'description' => 'port number (optional)',
|
||||
'default' => 25,
|
||||
'value' => 25,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'email_transport_smtp.encryption' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'tls or ssl (optional)',
|
||||
'default' => "",
|
||||
'value' => "",
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'email_transport_smtp.username' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'Authentication user (optional)',
|
||||
'default' => "",
|
||||
'value' => "",
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'email_transport_smtp.password' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'Authentication password (optional)',
|
||||
'default' => "",
|
||||
'value' => "",
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'apc_cache.enabled' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'If set, the APC cache is allowed (the PHP extension must also be active)',
|
||||
@@ -519,24 +471,15 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
'synchro_prevent_delete_all' => array(
|
||||
'type' => 'bool',
|
||||
'description' => 'Stop the synchro if all the replicas of a data source become obsolete at the same time.',
|
||||
'complex_actions_limit' => array(
|
||||
'type' => 'integer',
|
||||
'description' => 'Display the "actions" menu items that require long computation only if the list of objects is contains less objects than this number (0 means no limit)',
|
||||
// examples... not used
|
||||
'default' => true,
|
||||
'value' => true,
|
||||
'default' => 50,
|
||||
'value' => 50,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
),
|
||||
'source_dir' => array(
|
||||
'type' => 'string',
|
||||
'description' => 'Source directory for the datamodel files. (which gets compiled to env-production).',
|
||||
// examples... not used
|
||||
'default' => 'datamodels/latest',
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
),
|
||||
);
|
||||
|
||||
public function IsProperty($sPropCode)
|
||||
@@ -595,8 +538,8 @@ class Config
|
||||
protected $m_bLogNotification;
|
||||
protected $m_bLogIssue;
|
||||
protected $m_bLogWebService;
|
||||
protected $m_bLogKPIDuration; // private setting
|
||||
protected $m_bLogKPIMemory; // private setting
|
||||
protected $m_bLogKpiDuration; // private setting
|
||||
protected $m_bLogKpiMemory; // private setting
|
||||
protected $m_bDebugQueries; // private setting
|
||||
protected $m_bQueryCacheEnabled; // private setting
|
||||
|
||||
@@ -653,20 +596,14 @@ class Config
|
||||
*/
|
||||
protected $m_aCharsets;
|
||||
|
||||
public function __construct($sConfigFile = null, $bLoadConfig = true)
|
||||
public function __construct($sConfigFile, $bLoadConfig = true)
|
||||
{
|
||||
$this->m_sFile = $sConfigFile;
|
||||
if (is_null($sConfigFile))
|
||||
{
|
||||
$bLoadConfig = false;
|
||||
}
|
||||
|
||||
$this->m_aAppModules = array(
|
||||
// Some default modules, always present can be move to an official iTop Module later if needed
|
||||
'application/transaction.class.inc.php',
|
||||
'application/menunode.class.inc.php',
|
||||
'application/user.preferences.class.inc.php',
|
||||
'application/user.dashboard.class.inc.php',
|
||||
'application/audit.rule.class.inc.php',
|
||||
'application/query.class.inc.php',
|
||||
// Romain - That's dirty, because those classes are in fact part of the core
|
||||
@@ -726,12 +663,10 @@ class Config
|
||||
$this->Verify();
|
||||
}
|
||||
|
||||
// Application root url: set a default value, then normalize it
|
||||
/*
|
||||
* Does not work in CLI/unattended mode
|
||||
$sAppRootUrl = trim($this->Get('app_root_url'));
|
||||
// Application root url: set a default value, then normalize it
|
||||
$sAppRootUrl = trim($this->Get('app_root_url'));
|
||||
if (strlen($sAppRootUrl) == 0)
|
||||
{
|
||||
{
|
||||
$sAppRootUrl = utils::GetDefaultUrlAppRoot();
|
||||
}
|
||||
if (substr($sAppRootUrl, -1, 1) != '/')
|
||||
@@ -739,7 +674,6 @@ class Config
|
||||
$sAppRootUrl .= '/';
|
||||
}
|
||||
$this->Set('app_root_url', $sAppRootUrl);
|
||||
*/
|
||||
}
|
||||
|
||||
protected function CheckFile($sPurpose, $sFileName)
|
||||
@@ -1161,17 +1095,13 @@ class Config
|
||||
{
|
||||
$this->m_aCharsets[$sIconvCode] = $sDisplayName;
|
||||
}
|
||||
|
||||
public function FileIsWritable()
|
||||
{
|
||||
return is_writable($this->m_sFile);
|
||||
}
|
||||
public function GetLoadedFile()
|
||||
{
|
||||
if (is_null($this->m_sFile))
|
||||
{
|
||||
return '';
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->m_sFile;
|
||||
}
|
||||
return $this->m_sFile;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1254,98 +1184,64 @@ class Config
|
||||
fwrite($hFile, "<?php\n");
|
||||
fwrite($hFile, "\n/**\n");
|
||||
fwrite($hFile, " *\n");
|
||||
fwrite($hFile, " * Configuration file, generated by the ".ITOP_APPLICATION." configuration wizard\n");
|
||||
fwrite($hFile, " * phpMyORM configuration file, generated by the iTop configuration wizard\n");
|
||||
fwrite($hFile, " *\n");
|
||||
fwrite($hFile, " * The file is used in MetaModel::LoadConfig() which does all the necessary initialization job\n");
|
||||
fwrite($hFile, " *\n");
|
||||
fwrite($hFile, " */\n");
|
||||
fwrite($hFile, "\n");
|
||||
|
||||
$aConfigSettings = $this->m_aSettings;
|
||||
|
||||
// Old fashioned boolean settings
|
||||
$aBoolValues = array(
|
||||
'log_global' => $this->m_bLogGlobal,
|
||||
'log_notification' => $this->m_bLogNotification,
|
||||
'log_issue' => $this->m_bLogIssue,
|
||||
'log_web_service' => $this->m_bLogWebService,
|
||||
'secure_connection_required' => $this->m_bSecureConnectionRequired,
|
||||
);
|
||||
foreach($aBoolValues as $sKey => $bValue)
|
||||
{
|
||||
$aConfigSettings[$sKey] = array(
|
||||
'show_in_conf_sample' => true,
|
||||
'type' => 'bool',
|
||||
'value' => $bValue,
|
||||
);
|
||||
}
|
||||
|
||||
// Old fashioned non boolean values
|
||||
$aOtherValues = array(
|
||||
'db_host' => $this->m_sDBHost,
|
||||
'db_user' => $this->m_sDBUser,
|
||||
'db_pwd' => $this->m_sDBPwd,
|
||||
'db_name' => $this->m_sDBName,
|
||||
'db_subname' => $this->m_sDBSubname,
|
||||
'db_character_set' => $this->m_sDBCharacterSet,
|
||||
'db_collation' => $this->m_sDBCollation,
|
||||
'default_language' => $this->m_sDefaultLanguage,
|
||||
'allowed_login_types' => $this->m_sAllowedLoginTypes,
|
||||
'encryption_key' => $this->m_sEncryptionKey,
|
||||
'csv_import_charsets' => $this->m_aCharsets,
|
||||
);
|
||||
foreach($aOtherValues as $sKey => $value)
|
||||
{
|
||||
$aConfigSettings[$sKey] = array(
|
||||
'show_in_conf_sample' => true,
|
||||
'type' => is_string($value) ? 'string' : 'mixed',
|
||||
'value' => $value,
|
||||
);
|
||||
}
|
||||
|
||||
ksort($aConfigSettings);
|
||||
fwrite($hFile, "\$MySettings = array(\n");
|
||||
foreach($aConfigSettings as $sPropCode => $aSettingInfo)
|
||||
foreach($this->m_aSettings as $sPropCode => $aSettingInfo)
|
||||
{
|
||||
if ($aSettingInfo['show_in_conf_sample'])
|
||||
{
|
||||
$sType = $aSettingInfo['type'];
|
||||
$sType = $this->m_aSettings[$sPropCode]['type'];
|
||||
switch($sType)
|
||||
{
|
||||
case 'bool':
|
||||
$sSeenAs = $aSettingInfo['value'] ? 'true' : 'false';
|
||||
$sSeenAs = $aSettingInfo['value'] ? '1' : '0';
|
||||
break;
|
||||
default:
|
||||
$sSeenAs = self::PrettyVarExport($aSettingInfo['value'], "\t");
|
||||
}
|
||||
fwrite($hFile, "\n");
|
||||
if (isset($aSettingInfo['description']))
|
||||
{
|
||||
fwrite($hFile, "\t// $sPropCode: {$aSettingInfo['description']}\n");
|
||||
}
|
||||
if (isset($aSettingInfo['default']))
|
||||
{
|
||||
$default = $aSettingInfo['default'];
|
||||
if ($aSettingInfo['type'] == 'bool')
|
||||
{
|
||||
$default = $default ? 'true' : 'false';
|
||||
}
|
||||
fwrite($hFile, "\t//\tdefault: ".self::PrettyVarExport($aSettingInfo['default'],"\t//\t\t", true)."\n");
|
||||
$sSeenAs = "'".addslashes($aSettingInfo['value'])."'";
|
||||
}
|
||||
fwrite($hFile, "\t'$sPropCode' => $sSeenAs,\n");
|
||||
}
|
||||
}
|
||||
fwrite($hFile, ");\n");
|
||||
|
||||
fwrite($hFile, "\t'db_host' => '{$this->m_sDBHost}',\n");
|
||||
fwrite($hFile, "\t'db_user' => '{$this->m_sDBUser}',\n");
|
||||
fwrite($hFile, "\t'db_pwd' => '".addslashes($this->m_sDBPwd)."',\n");
|
||||
fwrite($hFile, "\t'db_name' => '{$this->m_sDBName}',\n");
|
||||
fwrite($hFile, "\t'db_subname' => '{$this->m_sDBSubname}',\n");
|
||||
fwrite($hFile, "\t'db_character_set' => '{$this->m_sDBCharacterSet}',\n");
|
||||
fwrite($hFile, "\t'db_collation' => '{$this->m_sDBCollation}',\n");
|
||||
fwrite($hFile, "\n");
|
||||
fwrite($hFile, "\t'log_global' => {$this->m_bLogGlobal},\n");
|
||||
fwrite($hFile, "\t'log_notification' => {$this->m_bLogNotification},\n");
|
||||
fwrite($hFile, "\t'log_issue' => {$this->m_bLogIssue},\n");
|
||||
fwrite($hFile, "\t'log_web_service' => {$this->m_bLogWebService},\n");
|
||||
fwrite($hFile, "\t'min_display_limit' => {$this->m_iMinDisplayLimit},\n");
|
||||
fwrite($hFile, "\t'max_display_limit' => {$this->m_iMaxDisplayLimit},\n");
|
||||
fwrite($hFile, "\t'standard_reload_interval' => {$this->m_iStandardReloadInterval},\n");
|
||||
fwrite($hFile, "\t'fast_reload_interval' => {$this->m_iFastReloadInterval},\n");
|
||||
fwrite($hFile, "\t'secure_connection_required' => ".($this->m_bSecureConnectionRequired ? 'true' : 'false').",\n");
|
||||
fwrite($hFile, "\t'default_language' => '{$this->m_sDefaultLanguage}',\n");
|
||||
fwrite($hFile, "\t'allowed_login_types' => '{$this->m_sAllowedLoginTypes}',\n");
|
||||
fwrite($hFile, "\t'encryption_key' => '{$this->m_sEncryptionKey}',\n");
|
||||
$sExport = var_export($this->m_aCharsets, true);
|
||||
fwrite($hFile, "\t'csv_import_charsets' => $sExport,\n");
|
||||
|
||||
fwrite($hFile, ");\n");
|
||||
|
||||
fwrite($hFile, "\n");
|
||||
fwrite($hFile, "/**\n *\n * Modules specific settings\n *\n */\n");
|
||||
fwrite($hFile, "\$MyModuleSettings = array(\n");
|
||||
foreach ($this->m_aModuleSettings as $sModule => $aProperties)
|
||||
{
|
||||
fwrite($hFile, "\t'$sModule' => array (\n");
|
||||
foreach ($aProperties as $sProperty => $value)
|
||||
{
|
||||
$sNiceExport = self::PrettyVarExport($value, "\t\t");
|
||||
fwrite($hFile, "\t\t'$sProperty' => $sNiceExport,\n");
|
||||
$sExport = var_export($value, true);
|
||||
fwrite($hFile, "\t\t'$sProperty' => $sExport,\n");
|
||||
}
|
||||
fwrite($hFile, "\t),\n");
|
||||
}
|
||||
@@ -1416,158 +1312,5 @@ class Config
|
||||
}
|
||||
return $aResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to initialize a configuration from the page arguments
|
||||
*/
|
||||
public function UpdateFromParams($aParamValues, $sModulesDir = null)
|
||||
{
|
||||
if (isset($aParamValues['application_path']))
|
||||
{
|
||||
$this->Set('app_root_url', $aParamValues['application_path']);
|
||||
}
|
||||
if (isset($aParamValues['mode']) && isset($aParamValues['language']))
|
||||
{
|
||||
if (($aParamValues['mode'] == 'install') || $this->GetDefaultLanguage() == '')
|
||||
{
|
||||
$this->SetDefaultLanguage($aParamValues['language']);
|
||||
}
|
||||
}
|
||||
if (isset($aParamValues['db_server']))
|
||||
{
|
||||
$this->SetDBHost($aParamValues['db_server']);
|
||||
$this->SetDBUser($aParamValues['db_user']);
|
||||
$this->SetDBPwd($aParamValues['db_pwd']);
|
||||
$sDBName = $aParamValues['db_name'];
|
||||
if ($sDBName == '')
|
||||
{
|
||||
// Todo - obsolete after the transition to the new setup (2.0) is complete (WARNING: used by the designer)
|
||||
$sDBName = $aParamValues['new_db_name'];
|
||||
}
|
||||
$this->SetDBName($sDBName);
|
||||
$this->SetDBSubname($aParamValues['db_prefix']);
|
||||
}
|
||||
|
||||
if (!is_null($sModulesDir))
|
||||
{
|
||||
if (isset($aParamValues['selected_modules']))
|
||||
{
|
||||
$aSelectedModules = explode(',', $aParamValues['selected_modules']);
|
||||
}
|
||||
else
|
||||
{
|
||||
$aSelectedModules = null;
|
||||
}
|
||||
|
||||
// Initialize the arrays below with default values for the application...
|
||||
$oEmptyConfig = new Config('dummy_file', false); // Do NOT load any config file, just set the default values
|
||||
$aAddOns = $oEmptyConfig->GetAddOns();
|
||||
$aAppModules = $oEmptyConfig->GetAppModules();
|
||||
$aDataModels = $oEmptyConfig->GetDataModels();
|
||||
$aWebServiceCategories = $oEmptyConfig->GetWebServiceCategories();
|
||||
$aDictionaries = $oEmptyConfig->GetDictionaries();
|
||||
// Merge the values with the ones provided by the modules
|
||||
// Make sure when don't load the same file twice...
|
||||
|
||||
$aModules = ModuleDiscovery::GetAvailableModules(APPROOT, $sModulesDir);
|
||||
foreach($aModules as $sModuleId => $aModuleInfo)
|
||||
{
|
||||
list($sModuleName, $sModuleVersion) = ModuleDiscovery::GetModuleName($sModuleId);
|
||||
if (is_null($aSelectedModules) || in_array($sModuleName, $aSelectedModules))
|
||||
{
|
||||
if (isset($aModuleInfo['datamodel']))
|
||||
{
|
||||
$aDataModels = array_unique(array_merge($aDataModels, $aModuleInfo['datamodel']));
|
||||
}
|
||||
if (isset($aModuleInfo['webservice']))
|
||||
{
|
||||
$aWebServiceCategories = array_unique(array_merge($aWebServiceCategories, $aModuleInfo['webservice']));
|
||||
}
|
||||
if (isset($aModuleInfo['dictionary']))
|
||||
{
|
||||
$aDictionaries = array_unique(array_merge($aDictionaries, $aModuleInfo['dictionary']));
|
||||
}
|
||||
if (isset($aModuleInfo['settings']))
|
||||
{
|
||||
foreach($aModuleInfo['settings'] as $sProperty => $value)
|
||||
{
|
||||
list($sName, $sVersion) = ModuleDiscovery::GetModuleName($sModuleId);
|
||||
$this->SetModuleSetting($sName, $sProperty, $value);
|
||||
}
|
||||
}
|
||||
if (isset($aModuleInfo['installer']))
|
||||
{
|
||||
$sModuleInstallerClass = $aModuleInfo['installer'];
|
||||
if (!class_exists($sModuleInstallerClass))
|
||||
{
|
||||
throw new Exception("Wrong installer class: '$sModuleInstallerClass' is not a PHP class - Module: ".$aModuleInfo['label']);
|
||||
}
|
||||
if (!is_subclass_of($sModuleInstallerClass, 'ModuleInstallerAPI'))
|
||||
{
|
||||
throw new Exception("Wrong installer class: '$sModuleInstallerClass' is not derived from 'ModuleInstallerAPI' - Module: ".$aModuleInfo['label']);
|
||||
}
|
||||
$aCallSpec = array($sModuleInstallerClass, 'BeforeWritingConfig');
|
||||
call_user_func_array($aCallSpec, array($this));
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->SetAddOns($aAddOns);
|
||||
$this->SetAppModules($aAppModules);
|
||||
$this->SetDataModels($aDataModels);
|
||||
$this->SetWebServiceCategories($aWebServiceCategories);
|
||||
$this->SetDictionaries($aDictionaries);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper: for an array of string, change the prefix when found
|
||||
*/
|
||||
protected static function ChangePrefix(&$aStrings, $sSearchPrefix, $sNewPrefix)
|
||||
{
|
||||
foreach ($aStrings as &$sFile)
|
||||
{
|
||||
if (substr($sFile, 0, strlen($sSearchPrefix)) == $sSearchPrefix)
|
||||
{
|
||||
$sFile = $sNewPrefix.substr($sFile, strlen($sSearchPrefix));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Quick an dirty way to clone a config file into another environment
|
||||
*/
|
||||
public function ChangeModulesPath($sSourceEnv, $sTargetEnv)
|
||||
{
|
||||
$sSearchPrefix = 'env-'.$sSourceEnv.'/';
|
||||
$sNewPrefix = 'env-'.$sTargetEnv.'/';
|
||||
self::ChangePrefix($this->m_aDataModels, $sSearchPrefix, $sNewPrefix);
|
||||
self::ChangePrefix($this->m_aWebServiceCategories, $sSearchPrefix, $sNewPrefix);
|
||||
self::ChangePrefix($this->m_aDictionaries, $sSearchPrefix, $sNewPrefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pretty format a var_export'ed value so that (if possible) the identation is preserved on every line
|
||||
* @param mixed $value The value to export
|
||||
* @param string $sIdentation The string to use to indent the text
|
||||
* @param bool $bForceIndentation Forces the identation (enven if it breaks/changes an eval, for example to ouput a value inside a comment)
|
||||
* @return string The indented export string
|
||||
*/
|
||||
protected static function PrettyVarExport($value, $sIdentation, $bForceIndentation = false)
|
||||
{
|
||||
$sExport = var_export($value, true);
|
||||
$sNiceExport = trim(preg_replace("/^/m", "\t\t\t", $sExport));
|
||||
if (!$bForceIndentation)
|
||||
{
|
||||
eval('$aImported='.$sNiceExport.';');
|
||||
// Check if adding the identations at the beginning of each line
|
||||
// did not modify the values (in case of a string containing a line break)
|
||||
if($aImported != $value)
|
||||
{
|
||||
$sNiceExport = $sExport;
|
||||
}
|
||||
}
|
||||
return $sNiceExport;
|
||||
}
|
||||
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -80,7 +80,7 @@ abstract class DBObject
|
||||
{
|
||||
$this->m_aCurrValues[$sAttCode] = $oAttDef->GetDefaultValue();
|
||||
$this->m_aOrigValues[$sAttCode] = null;
|
||||
if ($oAttDef->IsExternalField() || ($oAttDef instanceof AttributeFriendlyName))
|
||||
if ($oAttDef->IsExternalField())
|
||||
{
|
||||
// This field has to be read from the DB
|
||||
// Leave the flag unset (optimization)
|
||||
@@ -145,8 +145,8 @@ abstract class DBObject
|
||||
{
|
||||
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode=>$oAttDef)
|
||||
{
|
||||
if (!$oAttDef->LoadInObject()) continue;
|
||||
if (!isset($this->m_aLoadedAtt[$sAttCode]) || !$this->m_aLoadedAtt[$sAttCode])
|
||||
@$bIsLoaded = $this->m_aLoadedAtt[$sAttCode];
|
||||
if ($bIsLoaded !== true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@@ -249,8 +249,6 @@ abstract class DBObject
|
||||
// Skip links (could not be loaded by the mean of this query)
|
||||
if ($oAttDef->IsLinkSet()) continue;
|
||||
|
||||
if (!$oAttDef->LoadInObject()) continue;
|
||||
|
||||
// Note: we assume that, for a given attribute, if it can be loaded,
|
||||
// then one column will be found with an empty suffix, the others have a suffix
|
||||
// Take care: the function isset will return false in case the value is null,
|
||||
@@ -262,14 +260,7 @@ abstract class DBObject
|
||||
$value = $oAttDef->FromSQLToValue($aRow, $sAttRef);
|
||||
|
||||
$this->m_aCurrValues[$sAttCode] = $value;
|
||||
if (is_object($value))
|
||||
{
|
||||
$this->m_aOrigValues[$sAttCode] = clone $value;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->m_aOrigValues[$sAttCode] = $value;
|
||||
}
|
||||
$this->m_aOrigValues[$sAttCode] = $value;
|
||||
$this->m_aLoadedAtt[$sAttCode] = true;
|
||||
}
|
||||
else
|
||||
@@ -322,28 +313,43 @@ abstract class DBObject
|
||||
{
|
||||
throw new CoreUnexpectedValue("Trying to set the value of '$sAttCode', to an object of class '".get_class($value)."', whereas it's an ExtKey to '".$oAttDef->GetTargetClass()."'. Ignored");
|
||||
}
|
||||
|
||||
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sCode => $oDef)
|
||||
{
|
||||
if (($oDef->IsExternalField() || ($oDef instanceof AttributeFriendlyName)) && ($oDef->GetKeyAttCode() == $sAttCode))
|
||||
else
|
||||
{
|
||||
$this->m_aCurrValues[$sAttCode] = $value->GetKey();
|
||||
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sCode => $oDef)
|
||||
{
|
||||
$this->m_aCurrValues[$sCode] = $value->Get($oDef->GetExtAttCode());
|
||||
if ($oDef->IsExternalField() && ($oDef->GetKeyAttCode() == $sAttCode))
|
||||
{
|
||||
$this->m_aCurrValues[$sCode] = $value->Get($oDef->GetExtAttCode());
|
||||
}
|
||||
}
|
||||
$this->m_aCurrValues[$sAttCode.'_friendlyname'] = $value->GetName();
|
||||
}
|
||||
}
|
||||
else
|
||||
else if ($this->m_aCurrValues[$sAttCode] != $value)
|
||||
{
|
||||
// Setting an external key, but no any other information is available...
|
||||
// Invalidate the corresponding fields so that they get reloaded in case they are needed (See Get())
|
||||
// If the external key changed, invalidate all the external fields (and friendly name) related to this external key
|
||||
$this->m_aCurrValues[$sAttCode] = $value;
|
||||
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sCode => $oDef)
|
||||
{
|
||||
if (($oDef->IsExternalField() || ($oDef instanceof AttributeFriendlyName)) && ($oDef->GetKeyAttCode() == $sAttCode))
|
||||
if ($oDef->IsExternalField() && ($oDef->GetKeyAttCode() == $sAttCode))
|
||||
{
|
||||
$this->m_aCurrValues[$sCode] = $oDef->GetDefaultValue();
|
||||
unset($this->m_aLoadedAtt[$sCode]);
|
||||
$this->m_aCurrValues[$sCode] = null;
|
||||
}
|
||||
}
|
||||
$this->m_aCurrValues[$sAttCode.'_friendlyname'] = null;
|
||||
unset($this->m_aLoadedAtt[$sAttCode.'_friendlyname']);
|
||||
}
|
||||
|
||||
// The object has changed, reset caches
|
||||
$this->m_bCheckStatus = null;
|
||||
$this->m_aAsArgs = null;
|
||||
|
||||
// Make sure we do not reload it anymore... before saving it
|
||||
$this->RegisterAsDirty();
|
||||
|
||||
return;
|
||||
}
|
||||
if(!$oAttDef->IsScalar() && !is_object($value))
|
||||
{
|
||||
@@ -367,7 +373,6 @@ abstract class DBObject
|
||||
}
|
||||
|
||||
$realvalue = $oAttDef->MakeRealValue($value, $this);
|
||||
|
||||
$this->m_aCurrValues[$sAttCode] = $realvalue;
|
||||
|
||||
// The object has changed, reset caches
|
||||
@@ -414,73 +419,66 @@ abstract class DBObject
|
||||
|
||||
public function GetStrict($sAttCode)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
|
||||
|
||||
if (!$oAttDef->LoadInObject())
|
||||
if (!array_key_exists($sAttCode, MetaModel::ListAttributeDefs(get_class($this))))
|
||||
{
|
||||
$sParentAttCode = $oAttDef->GetParentAttCode();
|
||||
$parentValue = $this->GetStrict($sParentAttCode);
|
||||
$value = $oAttDef->GetValue($parentValue, $this);
|
||||
throw new CoreException("Unknown attribute code '$sAttCode' for the class ".get_class($this));
|
||||
}
|
||||
else
|
||||
if ($this->m_bIsInDB && !isset($this->m_aLoadedAtt[$sAttCode]))
|
||||
{
|
||||
if (isset($this->m_aLoadedAtt[$sAttCode]))
|
||||
// #@# non-scalar attributes.... handle that differently
|
||||
if (!$this->m_bDirty)
|
||||
{
|
||||
// Standard case... we have the information directly
|
||||
}
|
||||
elseif ($this->m_bIsInDB && !$this->m_bDirty)
|
||||
{
|
||||
// Lazy load (polymorphism): complete by reloading the entire object
|
||||
// #@# non-scalar attributes.... handle that differently?
|
||||
$this->Reload();
|
||||
}
|
||||
elseif ($sAttCode == 'friendlyname')
|
||||
{
|
||||
// The friendly name is not computed and the object is dirty
|
||||
// Todo: implement the computation of the friendly name based on sprintf()
|
||||
//
|
||||
$this->m_aCurrValues[$sAttCode] = '';
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not loaded... is it related to an external key?
|
||||
if ($oAttDef->IsExternalField() || ($oAttDef instanceof AttributeFriendlyName))
|
||||
// If the missing attribute is an external fields (or a friendlyname), try to selectively reload it
|
||||
// from the value of its external key... and reload the related external fields & friendlyname as well
|
||||
$sTargetClass = '';
|
||||
$iCurrKey = 0;
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
|
||||
if ($oAttDef->IsExternalField())
|
||||
{
|
||||
// Let's get the object and compute all of the corresponding attributes
|
||||
// (i.e not only the requested attribute)
|
||||
//
|
||||
$sExtKeyAttCode = $oAttDef->GetKeyAttCode();
|
||||
|
||||
if (($iRemote = $this->Get($sExtKeyAttCode)) && ($iRemote > 0)) // Objects in memory have negative IDs
|
||||
$sKeyAttCode = $oAttDef->GetKeyAttCode();
|
||||
$iCurrKey = $this->m_aCurrValues[$oAttDef->GetKeyAttCode()];
|
||||
$sTargetClass= $oAttDef->GetTargetClass();
|
||||
}
|
||||
else if ($oAttDef instanceof AttributeFriendlyName)
|
||||
{
|
||||
$sKeyAttCode = $oAttDef->GetKeyAttCode();
|
||||
$oKeyAttDef = MetaModel::GetAttributeDef(get_class($this), $sKeyAttCode);
|
||||
$iCurrKey = $this->m_aCurrValues[$oAttDef->GetKeyAttCode()];
|
||||
$sTargetClass = $oKeyAttDef->GetTargetClass();
|
||||
}
|
||||
|
||||
if (($sTargetClass != '') && ($iCurrKey != 0))
|
||||
{
|
||||
$oTargetObj = MetaModel::GetObject($sTargetClass, $iCurrKey, false);
|
||||
if (is_object($oTargetObj))
|
||||
{
|
||||
$oExtKeyAttDef = MetaModel::GetAttributeDef(get_class($this), $sExtKeyAttCode);
|
||||
$oRemote = MetaModel::GetObject($oExtKeyAttDef->GetTargetClass(), $iRemote);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oRemote = null;
|
||||
}
|
||||
|
||||
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sCode => $oDef)
|
||||
{
|
||||
if (($oDef->IsExternalField() || ($oDef instanceof AttributeFriendlyName)) && ($oDef->GetKeyAttCode() == $sExtKeyAttCode))
|
||||
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sCode => $oDef)
|
||||
{
|
||||
if ($oRemote)
|
||||
if ($oDef->IsExternalField() && ($oDef->GetKeyAttCode() == $sKeyAttCode))
|
||||
{
|
||||
$this->m_aCurrValues[$sCode] = $oRemote->Get($oDef->GetExtAttCode());
|
||||
$this->m_aLoadedAtt[$sCode] = true;
|
||||
$this->m_aCurrValues[$sCode] = $oTargetObj->Get($oDef->GetExtAttCode());
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->m_aCurrValues[$sCode] = $oDef->GetDefaultValue();
|
||||
}
|
||||
$this->m_aLoadedAtt[$sCode] = true;
|
||||
}
|
||||
}
|
||||
if ($oAttDef instanceof AttributeFriendlyName)
|
||||
{
|
||||
$this->m_aLoadedAtt[$sAttCode] = true;
|
||||
$this->m_aCurrValues[$sAttCode] = $oTargetObj->GetName();
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->m_aLoadedAtt[$sKeyAttCode.'_friendlyname'] = true;
|
||||
$this->m_aCurrValues[$sKeyAttCode.'_friendlyname'] = $oTargetObj->GetName();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$value = $this->m_aCurrValues[$sAttCode];
|
||||
}
|
||||
|
||||
$value = $this->m_aCurrValues[$sAttCode];
|
||||
if ($value instanceof DBObjectSet)
|
||||
{
|
||||
$value->Rewind();
|
||||
@@ -558,16 +556,8 @@ abstract class DBObject
|
||||
//return $this->Get($sAttCode.'_friendlyname');
|
||||
$sTargetClass = $oAtt->GetTargetClass(EXTKEY_ABSOLUTE);
|
||||
$iTargetKey = $this->Get($sAttCode);
|
||||
if ($iTargetKey < 0)
|
||||
{
|
||||
// the key points to an object that exists only in memory... no hyperlink points to it yet
|
||||
return '';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sLabel = $this->Get($sAttCode.'_friendlyname');
|
||||
return $this->MakeHyperLink($sTargetClass, $iTargetKey, $sLabel);
|
||||
}
|
||||
$sLabel = $this->Get($sAttCode.'_friendlyname');
|
||||
return $this->MakeHyperLink($sTargetClass, $iTargetKey, $sLabel);
|
||||
}
|
||||
|
||||
// That's a standard attribute (might be an ext field or a direct field, etc.)
|
||||
@@ -604,7 +594,7 @@ abstract class DBObject
|
||||
}
|
||||
else
|
||||
{
|
||||
$sEditValue = $oAtt->GetEditValue($this->Get($sAttCode), $this);
|
||||
$sEditValue = $oAtt->GetEditValue($this->Get($sAttCode));
|
||||
}
|
||||
return $sEditValue;
|
||||
}
|
||||
@@ -639,7 +629,7 @@ abstract class DBObject
|
||||
return $oAtt->GetAsCSV($this->GetOriginal($sAttCode), $sSeparator, $sTextQualifier, $this);
|
||||
}
|
||||
|
||||
public static function MakeHyperLink($sObjClass, $sObjKey, $sLabel = '', $sUrlMakerClass = null, $bWithNavigationContext = true)
|
||||
protected static function MakeHyperLink($sObjClass, $sObjKey, $sLabel = '', $sUrlMakerClass = null, $bWithNavigationContext = true)
|
||||
{
|
||||
if ($sObjKey <= 0) return '<em>'.Dict::S('UI:UndefinedObject').'</em>'; // Objects built in memory have negative IDs
|
||||
|
||||
@@ -794,29 +784,6 @@ abstract class DBObject
|
||||
return MetaModel::GetStateDescription(get_class($this), $sStateValue);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridable - Define attributes read-only from the end-user perspective
|
||||
*
|
||||
* @return array List of attcodes
|
||||
*/
|
||||
public static function GetReadOnlyAttributes()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overridable - Get predefined objects (could be hardcoded)
|
||||
* The predefined objects will be synchronized with the DB at each install/upgrade
|
||||
* As soon as a class has predefined objects, then nobody can create nor delete objects
|
||||
* @return array An array of id => array of attcode => php value(so-called "real value": integer, string, ormDocument, DBObjectSet, etc.)
|
||||
*/
|
||||
public static function GetPredefinedObjects()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the set of flags (OPT_ATT_HIDDEN, OPT_ATT_READONLY, OPT_ATT_MANDATORY...)
|
||||
* for the given attribute in the current state of the object
|
||||
@@ -828,16 +795,6 @@ abstract class DBObject
|
||||
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '')
|
||||
{
|
||||
$iFlags = 0; // By default (if no life cycle) no flag at all
|
||||
|
||||
$aReadOnlyAtts = $this->GetReadOnlyAttributes();
|
||||
if ($aReadOnlyAtts != null)
|
||||
{
|
||||
if (in_array($sAttCode, $aReadOnlyAtts))
|
||||
{
|
||||
return OPT_ATT_READONLY;
|
||||
}
|
||||
}
|
||||
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode(get_class($this));
|
||||
if (!empty($sStateAttCode))
|
||||
{
|
||||
@@ -1097,30 +1054,35 @@ abstract class DBObject
|
||||
$aDelta = array();
|
||||
foreach ($aProposal as $sAtt => $proposedValue)
|
||||
{
|
||||
if (!array_key_exists($sAtt, $this->m_aOrigValues))
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAtt);
|
||||
// Ignore external fields and friendly names that change only as a consequence of modifying another field
|
||||
if ((!$oAttDef->IsExternalField() && !($oAttDef instanceof AttributeFriendlyName)))
|
||||
{
|
||||
// The value was not set
|
||||
$aDelta[$sAtt] = $proposedValue;
|
||||
}
|
||||
elseif(is_object($proposedValue))
|
||||
{
|
||||
$oLinkAttDef = MetaModel::GetAttributeDef(get_class($this), $sAtt);
|
||||
// The value is an object, the comparison is not strict
|
||||
if (!$oLinkAttDef->Equals($proposedValue, $this->m_aOrigValues[$sAtt]))
|
||||
if (!array_key_exists($sAtt, $this->m_aOrigValues))
|
||||
{
|
||||
// The value was not set
|
||||
$aDelta[$sAtt] = $proposedValue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The value is a scalar, the comparison must be 100% strict
|
||||
if($this->m_aOrigValues[$sAtt] !== $proposedValue)
|
||||
{
|
||||
//echo "$sAtt:<pre>\n";
|
||||
//var_dump($this->m_aOrigValues[$sAtt]);
|
||||
//var_dump($proposedValue);
|
||||
//echo "</pre>\n";
|
||||
$aDelta[$sAtt] = $proposedValue;
|
||||
elseif(is_object($proposedValue))
|
||||
{
|
||||
$oLinkAttDef = MetaModel::GetAttributeDef(get_class($this), $sAtt);
|
||||
// The value is an object, the comparison is not strict
|
||||
if (!$oLinkAttDef->Equals($proposedValue, $this->m_aOrigValues[$sAtt]))
|
||||
{
|
||||
$aDelta[$sAtt] = $proposedValue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The value is a scalar, the comparison must be 100% strict
|
||||
if($this->m_aOrigValues[$sAtt] !== $proposedValue)
|
||||
{
|
||||
//echo "$sAtt:<pre>\n";
|
||||
//var_dump($this->m_aOrigValues[$sAtt]);
|
||||
//var_dump($proposedValue);
|
||||
//echo "</pre>\n";
|
||||
$aDelta[$sAtt] = $proposedValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1370,26 +1332,6 @@ abstract class DBObject
|
||||
throw new CoreException("Object not following integrity rules", array('issues' => $sIssues, 'class' => get_class($this), 'id' => $this->GetKey()));
|
||||
}
|
||||
|
||||
// Stop watches
|
||||
$sState = $this->GetState();
|
||||
if ($sState != '')
|
||||
{
|
||||
foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
|
||||
{
|
||||
if ($oAttDef instanceof AttributeStopWatch)
|
||||
{
|
||||
if (in_array($sState, $oAttDef->GetStates()))
|
||||
{
|
||||
// Start the stop watch and compute the deadlines
|
||||
$oSW = $this->Get($sAttCode);
|
||||
$oSW->Start($this, $oAttDef);
|
||||
$oSW->ComputeDeadlines($this, $oAttDef);
|
||||
$this->Set($sAttCode, $oSW);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// First query built upon on the root class, because the ID must be created first
|
||||
$this->m_iKey = $this->DBInsertSingleTable($sRootClass);
|
||||
|
||||
@@ -1473,25 +1415,6 @@ abstract class DBObject
|
||||
throw new CoreException("DBUpdate: could not update a newly created object, please call DBInsert instead");
|
||||
}
|
||||
|
||||
// Stop watches
|
||||
$sState = $this->GetState();
|
||||
if ($sState != '')
|
||||
{
|
||||
foreach(MetaModel::ListAttributeDefs(get_class($this)) as $sAttCode => $oAttDef)
|
||||
{
|
||||
if ($oAttDef instanceof AttributeStopWatch)
|
||||
{
|
||||
if (in_array($sState, $oAttDef->GetStates()))
|
||||
{
|
||||
// Compute or recompute the deadlines
|
||||
$oSW = $this->Get($sAttCode);
|
||||
$oSW->ComputeDeadlines($this, $oAttDef);
|
||||
$this->Set($sAttCode, $oSW);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->DoComputeValues();
|
||||
$this->OnUpdate();
|
||||
|
||||
@@ -1733,10 +1656,6 @@ abstract class DBObject
|
||||
return MetaModel::EnumTransitions(get_class($this), $sState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Designed as an action to be called when a stop watch threshold times out
|
||||
* or from within the framework
|
||||
*/
|
||||
public function ApplyStimulus($sStimulusCode)
|
||||
{
|
||||
$sStateAttCode = MetaModel::GetStateAttributeCode(get_class($this));
|
||||
@@ -1771,6 +1690,7 @@ abstract class DBObject
|
||||
// if one call fails, the whole is considered as failed
|
||||
if (!$bRet) $bSuccess = false;
|
||||
}
|
||||
|
||||
if ($bSuccess)
|
||||
{
|
||||
// Change state triggers...
|
||||
@@ -1787,44 +1707,11 @@ abstract class DBObject
|
||||
{
|
||||
$oTrigger->DoActivate($this->ToArgs('this'));
|
||||
}
|
||||
|
||||
// Stop watches
|
||||
foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
|
||||
{
|
||||
if ($oAttDef instanceof AttributeStopWatch)
|
||||
{
|
||||
$oSW = $this->Get($sAttCode);
|
||||
if (in_array($sNewState, $oAttDef->GetStates()))
|
||||
{
|
||||
$oSW->Start($this, $oAttDef);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oSW->Stop($this, $oAttDef);
|
||||
}
|
||||
$this->Set($sAttCode, $oSW);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $bSuccess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Designed as an action to be called when a stop watch threshold times out
|
||||
*/
|
||||
public function ResetStopWatch($sAttCode)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef(get_class($this), $sAttCode);
|
||||
if (!$oAttDef instanceof AttributeStopWatch)
|
||||
{
|
||||
throw new CoreException("Invalid stop watch id: '$sAttCode'");
|
||||
}
|
||||
$oSW = $this->Get($sAttCode);
|
||||
$oSW->Reset($this, $oAttDef);
|
||||
$this->Set($sAttCode, $oSW);
|
||||
}
|
||||
|
||||
// Make standard context arguments
|
||||
// Note: Needs to be reviewed because it is currently called once per attribute when an object is written (CheckToWrite / CheckValue)
|
||||
// Several options here:
|
||||
@@ -1842,7 +1729,7 @@ abstract class DBObject
|
||||
$aScalarArgs[$sArgName.'->hyperlink()'] = $this->GetHyperlink('iTopStandardURLMaker', false);
|
||||
$aScalarArgs[$sArgName.'->hyperlink(portal)'] = $this->GetHyperlink('PortalURLMaker', false);
|
||||
$aScalarArgs[$sArgName.'->name()'] = $this->GetName();
|
||||
|
||||
|
||||
$sClass = get_class($this);
|
||||
foreach(MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
|
||||
{
|
||||
@@ -1862,7 +1749,6 @@ abstract class DBObject
|
||||
$aScalarArgs[$sArgName.'->head('.$sAttCode.')'] = $oCaseLog->GetLatestEntry();
|
||||
}
|
||||
}
|
||||
|
||||
$this->m_aAsArgs = $aScalarArgs;
|
||||
$oKPI->ComputeStats('ToArgs', get_class($this));
|
||||
}
|
||||
|
||||
@@ -548,38 +548,24 @@ class DBObjectSearch
|
||||
{
|
||||
if ($bTranslateMainAlias)
|
||||
{
|
||||
$sOrigAlias = $this->GetFirstJoinedClassAlias();
|
||||
$sOrigAlias = $this->GetClassAlias();
|
||||
if (array_key_exists($sOrigAlias, $aClassAliases))
|
||||
{
|
||||
$sNewAlias = MetaModel::GenerateUniqueAlias($aClassAliases, $sOrigAlias, $this->GetFirstJoinedClass());
|
||||
if (isset($this->m_aSelectedClasses[$sOrigAlias]))
|
||||
{
|
||||
$this->m_aSelectedClasses[$sNewAlias] = $this->GetFirstJoinedClass();
|
||||
unset($this->m_aSelectedClasses[$sOrigAlias]);
|
||||
}
|
||||
|
||||
// TEMPORARY ALGORITHM (m_aClasses is not correctly updated, it is not possible to add a subtree onto a subnode)
|
||||
// Replace the element at the same position (unset + set is not enough because the hash array is ordered)
|
||||
$aPrevList = $this->m_aClasses;
|
||||
$this->m_aClasses = array();
|
||||
foreach ($aPrevList as $sSomeAlias => $sSomeClass)
|
||||
{
|
||||
if ($sSomeAlias == $sOrigAlias)
|
||||
{
|
||||
$this->m_aClasses[$sNewAlias] = $sSomeClass; // note: GetFirstJoinedClass now returns '' !!!
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->m_aClasses[$sSomeAlias] = $sSomeClass;
|
||||
}
|
||||
}
|
||||
$sNewAlias = MetaModel::GenerateUniqueAlias($aClassAliases, $sOrigAlias, $this->GetClass());
|
||||
//echo "<p>Generating a new alias for $sOrigAlias (already used). It is now: $sNewAlias</p>\n";
|
||||
$this->m_aSelectedClasses[$sNewAlias] = $this->GetClass();
|
||||
unset($this->m_aSelectedClasses[$sOrigAlias]);
|
||||
|
||||
$this->m_aClasses[$sNewAlias] = $this->GetClass();
|
||||
unset($this->m_aClasses[$sOrigAlias]);
|
||||
|
||||
// Translate the condition expression with the new alias
|
||||
$aAliasTranslation[$sOrigAlias]['*'] = $sNewAlias;
|
||||
}
|
||||
|
||||
//echo "<p>Adding the alias ".$this->GetClass()." as ".$this->GetClassAlias()."</p>\n";
|
||||
// add the alias into the filter aliases list
|
||||
$aClassAliases[$this->GetFirstJoinedClassAlias()] = $this->GetFirstJoinedClass();
|
||||
$aClassAliases[$this->GetClassAlias()] = $this->GetClass();
|
||||
}
|
||||
|
||||
foreach($this->m_aPointingTo as $sExtKeyAttCode=>$aPointingTo)
|
||||
@@ -612,6 +598,7 @@ class DBObjectSearch
|
||||
|
||||
protected function AddCondition_PointingTo_InNameSpace(DBObjectSearch $oFilter, $sExtKeyAttCode, &$aClassAliases, &$aAliasTranslation, $iOperatorCode)
|
||||
{
|
||||
//echo "<p style=\"color:green\">Calling: AddCondition_PointingTo_InNameSpace([<pre>".print_r($aClassAliases, true)."</pre></br>], [<pre>".print_r($aAliasTranslation, true)."</pre>]);</p>";
|
||||
if (!MetaModel::IsValidKeyAttCode($this->GetClass(), $sExtKeyAttCode))
|
||||
{
|
||||
throw new CoreWarning("The attribute code '$sExtKeyAttCode' is not an external key of the class '{$this->GetClass()}' - the condition will be ignored");
|
||||
@@ -623,7 +610,7 @@ class DBObjectSearch
|
||||
}
|
||||
if(($iOperatorCode != TREE_OPERATOR_EQUALS) && !($oAttExtKey instanceof AttributeHierarchicalKey))
|
||||
{
|
||||
throw new CoreException("The specified tree operator $iOperatorCode is not applicable to the key '{$this->GetClass()}::$sExtKeyAttCode', which is not a HierarchicalKey");
|
||||
throw new CoreException("The specified tree operator $isOperatorCode is not applicable to the key '{$this->GetClass()}::$sExtKeyAttCode', which is not a HierarchicalKey");
|
||||
}
|
||||
|
||||
$bSamePointingTo = false;
|
||||
@@ -633,19 +620,27 @@ class DBObjectSearch
|
||||
{
|
||||
if (array_key_exists($oFilter->GetClassAlias(), $this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode]))
|
||||
{
|
||||
//echo "<p style=\"color:red\">[".__LINE__."]this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode][".$oFilter->GetFirstJoinedClassAlias()."]:<pre>\n".print_r($this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode], true)."</pre>;</p>";
|
||||
$bSamePointingTo = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//echo "<p style=\"color:red\">[".__LINE__."]Calling: AddToNameSpace([".implode(',', $aClassAliases)."], [".implode(',', $aAliasTranslation)."]);</p>";
|
||||
if ($bSamePointingTo)
|
||||
{
|
||||
//echo "<p style=\"color:red\">[".__LINE__."]AddPointingTo: Merging filters for [$sExtKeyAttCode][$iOperatorCode][".$oFilter->GetClassAlias()."]</p>";
|
||||
// Same ext key, alias and same operator, merge the filters together
|
||||
// $sAlias = $oFilter->GetClassAlias();
|
||||
//echo "<p style=\"color:red\">[".__LINE__."]before: AddToNameSpace(aClassAliases[<pre>\n".print_r($aClassAliases, true)."</pre>], aAliasTranslation[<pre>\n".print_r($aAliasTranslation, true)."</pre>]);</p>";
|
||||
$oFilter->AddToNamespace($aClassAliases, $aAliasTranslation, true /* Don't translate the main alias */);
|
||||
//echo "<p style=\"color:blue\">[".__LINE__."]after: AddToNameSpace(aClassAliases[<pre>\n".print_r($aClassAliases, true)."</pre>], aAliasTranslation[<pre>\n".print_r($aAliasTranslation, true)."</pre>]);</p>";
|
||||
// $this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode][$sAlias]->MergeWith($oFilter, $aClassAliases, $aAliasTranslation);
|
||||
$this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode][$oFilter->GetClassAlias()] = $oFilter;
|
||||
}
|
||||
else
|
||||
{
|
||||
//echo "<p style=\"color:red\">[".__LINE__."]AddPointingTo: Adding a new PointingTo filter for [$sExtKeyAttCode][$iOperatorCode][".$oFilter->GetClassAlias()."]</p>";
|
||||
$oFilter->AddToNamespace($aClassAliases, $aAliasTranslation);
|
||||
$this->m_aPointingTo[$sExtKeyAttCode][$iOperatorCode][$oFilter->GetClassAlias()] = $oFilter;
|
||||
}
|
||||
@@ -921,7 +916,6 @@ class DBObjectSearch
|
||||
{
|
||||
$aParams = array_merge($aContextParams, $this->m_aParams);
|
||||
}
|
||||
$aParams = MetaModel::PrepareQueryArguments($aParams);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -932,7 +926,7 @@ class DBObjectSearch
|
||||
$sSelectedClasses = implode(', ', array_keys($this->m_aSelectedClasses));
|
||||
$sRes = 'SELECT '.$sSelectedClasses.' FROM';
|
||||
|
||||
$sRes .= ' '.$this->GetFirstJoinedClass().' AS '.$this->GetFirstJoinedClassAlias();
|
||||
$sRes .= ' '.$this->GetClass().' AS '.$this->GetClassAlias();
|
||||
$sRes .= $this->ToOQL_Joins();
|
||||
$sRes .= " WHERE ".$this->m_oSearchCondition->Render($aParams, $bRetrofitParams);
|
||||
|
||||
@@ -992,7 +986,7 @@ class DBObjectSearch
|
||||
break;
|
||||
|
||||
}
|
||||
$sRes .= ' JOIN '.$oFilter->GetFirstJoinedClass().' AS '.$oFilter->GetFirstJoinedClassAlias().' ON '.$this->GetFirstJoinedClassAlias().'.'.$sExtKey.$sOperator.$oFilter->GetFirstJoinedClassAlias().'.id';
|
||||
$sRes .= ' JOIN '.$oFilter->GetClass().' AS '.$oFilter->GetClassAlias().' ON '.$this->GetClassAlias().'.'.$sExtKey.$sOperator.$oFilter->GetClassAlias().'.id';
|
||||
$sRes .= $oFilter->ToOQL_Joins();
|
||||
}
|
||||
}
|
||||
@@ -1001,7 +995,7 @@ class DBObjectSearch
|
||||
{
|
||||
foreach($aReferences as $sForeignExtKeyAttCode=>$oForeignFilter)
|
||||
{
|
||||
$sRes .= ' JOIN '.$oForeignFilter->GetFirstJoinedClass().' AS '.$oForeignFilter->GetFirstJoinedClassAlias().' ON '.$oForeignFilter->GetFirstJoinedClassAlias().'.'.$sForeignExtKeyAttCode.' = '.$this->GetFirstJoinedClassAlias().'.id';
|
||||
$sRes .= ' JOIN '.$oForeignFilter->GetClass().' AS '.$oForeignFilter->GetClassAlias().' ON '.$oForeignFilter->GetClassAlias().'.'.$sForeignExtKeyAttCode.' = '.$this->GetClassAlias().'.id';
|
||||
$sRes .= $oForeignFilter->ToOQL_Joins();
|
||||
}
|
||||
}
|
||||
@@ -1137,7 +1131,7 @@ class DBObjectSearch
|
||||
|
||||
if (!MetaModel::IsValidClass($sClass))
|
||||
{
|
||||
throw new UnknownClassOqlException($sQuery, $oOqlQuery->GetClassDetails(), MetaModel::GetClasses());
|
||||
throw new OqlNormalizeException('Unknown class', $sQuery, $oOqlQuery->GetClassDetails(), MetaModel::GetClasses());
|
||||
}
|
||||
|
||||
$oResultFilter = new DBObjectSearch($sClass, $sClassAlias);
|
||||
@@ -1157,7 +1151,7 @@ class DBObjectSearch
|
||||
$sJoinClassAlias = $oJoinSpec->GetClassAlias();
|
||||
if (!MetaModel::IsValidClass($sJoinClass))
|
||||
{
|
||||
throw new UnknownClassOqlException($sQuery, $oJoinSpec->GetClassDetails(), MetaModel::GetClasses());
|
||||
throw new OqlNormalizeException('Unknown class', $sQuery, $oJoinSpec->GetClassDetails(), MetaModel::GetClasses());
|
||||
}
|
||||
if (array_key_exists($sJoinClassAlias, $aAliases))
|
||||
{
|
||||
@@ -1288,4 +1282,4 @@ class DBObjectSearch
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
?>
|
||||
|
||||
@@ -290,11 +290,6 @@ class DBObjectSet
|
||||
return $this->m_oFilter->GetClass();
|
||||
}
|
||||
|
||||
public function GetClassAlias()
|
||||
{
|
||||
return $this->m_oFilter->GetClassAlias();
|
||||
}
|
||||
|
||||
public function GetSelectedClasses()
|
||||
{
|
||||
return $this->m_oFilter->GetSelectedClasses();
|
||||
@@ -316,19 +311,6 @@ class DBObjectSet
|
||||
$this->m_iLimitStart = $iLimitStart;
|
||||
}
|
||||
|
||||
public function SetOrderBy($aOrderBy)
|
||||
{
|
||||
if ($this->m_aOrderBy != $aOrderBy)
|
||||
{
|
||||
$this->m_aOrderBy = $aOrderBy;
|
||||
if ($this->m_bLoaded)
|
||||
{
|
||||
$this->m_bLoaded = false;
|
||||
$this->Load();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function GetLimitCount()
|
||||
{
|
||||
return $this->m_iLimitCount;
|
||||
@@ -339,20 +321,6 @@ class DBObjectSet
|
||||
return $this->m_iLimitStart;
|
||||
}
|
||||
|
||||
public function GetRealSortOrder()
|
||||
{
|
||||
// Get the class default sort order if not specified with the API
|
||||
//
|
||||
if (empty($this->m_aOrderBy))
|
||||
{
|
||||
return MetaModel::GetOrderByDefault($this->m_oFilter->GetClass());
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->m_aOrderBy;
|
||||
}
|
||||
}
|
||||
|
||||
public function Load()
|
||||
{
|
||||
if ($this->m_bLoaded) return;
|
||||
@@ -361,11 +329,11 @@ class DBObjectSet
|
||||
|
||||
if ($this->m_iLimitCount > 0)
|
||||
{
|
||||
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->GetRealSortOrder(), $this->m_aArgs, $this->m_aAttToLoad, $this->m_aExtendedDataSpec, $this->m_iLimitCount, $this->m_iLimitStart);
|
||||
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->m_aOrderBy, $this->m_aArgs, $this->m_aAttToLoad, $this->m_aExtendedDataSpec, $this->m_iLimitCount, $this->m_iLimitStart);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->GetRealSortOrder(), $this->m_aArgs, $this->m_aAttToLoad, $this->m_aExtendedDataSpec);
|
||||
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->m_aOrderBy, $this->m_aArgs, $this->m_aAttToLoad, $this->m_aExtendedDataSpec);
|
||||
}
|
||||
$resQuery = CMDBSource::Query($sSQL);
|
||||
if (!$resQuery) return;
|
||||
@@ -402,7 +370,7 @@ class DBObjectSet
|
||||
{
|
||||
if (is_null($this->m_iCount))
|
||||
{
|
||||
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, array(), $this->m_aArgs, null, null, 0, 0, true);
|
||||
$sSQL = MetaModel::MakeSelectQuery($this->m_oFilter, $this->m_aOrderBy, $this->m_aArgs, null, null, 0, 0, true);
|
||||
$resQuery = CMDBSource::Query($sSQL);
|
||||
if (!$resQuery) return 0;
|
||||
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
/**
|
||||
* Send an email (abstraction for synchronous/asynchronous modes)
|
||||
* Send an mail (for notification, testing,... purposes)
|
||||
* #@# TODO - replace by a more sophisticated mean (and update the prototype)
|
||||
*
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
@@ -23,11 +24,6 @@
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
require_once(APPROOT.'/lib/swiftmailer/lib/swift_required.php');
|
||||
|
||||
Swift_Preferences::getInstance()->setCharset('UTF-8');
|
||||
|
||||
|
||||
define ('EMAIL_SEND_OK', 0);
|
||||
define ('EMAIL_SEND_PENDING', 1);
|
||||
define ('EMAIL_SEND_ERROR', 2);
|
||||
@@ -35,32 +31,36 @@ define ('EMAIL_SEND_ERROR', 2);
|
||||
|
||||
class EMail
|
||||
{
|
||||
protected static $m_oConfig = null;
|
||||
protected $m_sBody;
|
||||
protected $m_sSubject;
|
||||
protected $m_sTo;
|
||||
protected $m_aHeaders; // array of key=>value
|
||||
protected $m_aAttachments;
|
||||
|
||||
public function LoadConfig($sConfigFile = ITOP_DEFAULT_CONFIG_FILE)
|
||||
public function __construct($sTo = '', $sSubject = '', $sBody = '', $aHeaders = array())
|
||||
{
|
||||
if (is_null(self::$m_oConfig))
|
||||
{
|
||||
self::$m_oConfig = new Config($sConfigFile);
|
||||
}
|
||||
$this->m_sTo = $sTo;
|
||||
$this->m_sSubject = $sSubject;
|
||||
$this->m_sBody = $sBody;
|
||||
$this->m_aHeaders = $aHeaders;
|
||||
$this->m_aAttachments = array();
|
||||
}
|
||||
|
||||
// Errors management : not that simple because we need that function to be
|
||||
// executed in the background, while making sure that any issue would be reported clearly
|
||||
protected $m_aMailErrors; //array of strings explaining the issues
|
||||
|
||||
protected $m_oMessage;
|
||||
|
||||
public function __construct()
|
||||
public function mail_error_handler($errno, $errstr, $errfile, $errline)
|
||||
{
|
||||
$this->m_oMessage = Swift_Message::newInstance();
|
||||
|
||||
$oEncoder = new Swift_Mime_ContentEncoder_PlainContentEncoder('8bit');
|
||||
$this->m_oMessage->setEncoder($oEncoder);
|
||||
$sCleanMessage= str_replace("mail() [<a href='function.mail'>function.mail</a>]: ", "", $errstr);
|
||||
$this->m_aMailErrors[] = $sCleanMessage;
|
||||
}
|
||||
|
||||
protected function SendAsynchronous(&$aIssues, $oLog = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
AsyncSendEmail::AddToQueue($this, $oLog);
|
||||
AsyncSendEmail::AddToQueue($this->m_sTo, $this->m_sSubject, $this->m_sBody, $this->m_aHeaders, $oLog);
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
@@ -73,37 +73,40 @@ class EMail
|
||||
|
||||
protected function SendSynchronous(&$aIssues, $oLog = null)
|
||||
{
|
||||
$this->LoadConfig();
|
||||
|
||||
$sTransport = self::$m_oConfig->Get('email_transport');
|
||||
switch ($sTransport)
|
||||
$sHeaders = 'MIME-Version: 1.0' . "\r\n";
|
||||
// ! the case is important for MS-Outlook
|
||||
if (!array_key_exists('Content-Type', $this->m_aHeaders))
|
||||
{
|
||||
case 'SMTP':
|
||||
$sHost = self::$m_oConfig->Get('email_transport_smtp.host');
|
||||
$sPort = self::$m_oConfig->Get('email_transport_smtp.port');
|
||||
$sEncryption = self::$m_oConfig->Get('email_transport_smtp.encryption');
|
||||
$sUserName = self::$m_oConfig->Get('email_transport_smtp.username');
|
||||
$sPassword = self::$m_oConfig->Get('email_transport_smtp.password');
|
||||
|
||||
$oTransport = Swift_SmtpTransport::newInstance($sHost, $sPort, $sEncryption);
|
||||
if (strlen($sUserName) > 0)
|
||||
{
|
||||
$oTransport->setUsername($sUserName);
|
||||
$oTransport->setPassword($sPassword);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'PHPMail':
|
||||
default:
|
||||
$oTransport = Swift_MailTransport::newInstance();
|
||||
$sHeaders .= 'Content-Type: text/html; charset=UTF-8' . "\r\n";
|
||||
}
|
||||
if (!array_key_exists('Content-Transfer-Encoding', $this->m_aHeaders))
|
||||
{
|
||||
$sHeaders .= 'Content-Transfer-Encoding: 8bit' . "\r\n";
|
||||
}
|
||||
foreach ($this->m_aHeaders as $sKey => $sValue)
|
||||
{
|
||||
$sHeaders .= "$sKey: $sValue\r\n";
|
||||
}
|
||||
|
||||
$oMailer = Swift_Mailer::newInstance($oTransport);
|
||||
|
||||
$iSent = $oMailer->send($this->m_oMessage);
|
||||
if ($iSent === false)
|
||||
// Under Windows (not yet proven for Linux/PHP) mail may issue a warning
|
||||
// that I could not mask (tried error_reporting(), etc.)
|
||||
$this->m_aMailErrors = array();
|
||||
set_error_handler(array($this, 'mail_error_handler'));
|
||||
$bRes = mail
|
||||
(
|
||||
str_replace(array("\n", "\r"), ' ', $this->m_sTo), // Prevent header injection
|
||||
$this->EncodeHeaderField($this->m_sSubject), // Prevent header injection & MIME Encode charsets
|
||||
$this->m_sBody,
|
||||
$sHeaders
|
||||
);
|
||||
restore_error_handler();
|
||||
if (!$bRes && empty($this->m_aMailErrors))
|
||||
{
|
||||
$aIssues = 'une erreur s\'est produite... mais quoi !!!';
|
||||
$this->m_aMailErrors[] = 'Unknown reason';
|
||||
}
|
||||
if (count($this->m_aMailErrors) > 0)
|
||||
{
|
||||
$aIssues = $this->m_aMailErrors;
|
||||
return EMAIL_SEND_ERROR;
|
||||
}
|
||||
else
|
||||
@@ -115,6 +118,7 @@ class EMail
|
||||
|
||||
public function Send(&$aIssues, $bForceSynchronous = false, $oLog = null)
|
||||
{
|
||||
$this->BuildMessage(); // assemble the attachments into the header/body structure
|
||||
if ($bForceSynchronous)
|
||||
{
|
||||
return $this->SendSynchronous($aIssues, $oLog);
|
||||
@@ -137,39 +141,13 @@ class EMail
|
||||
{
|
||||
if (strlen($sValue) > 0)
|
||||
{
|
||||
$oHeaders = $this->m_oMessage->getHeaders();
|
||||
switch(strtolower($sKey))
|
||||
{
|
||||
case 'from':
|
||||
case 'cc':
|
||||
case 'bcc':
|
||||
$aMatches = array();
|
||||
// Header may be in the form: John Doe <jd@company.com>
|
||||
if (preg_match('/^([^<]+) <([^>]+)>$/', $sValue, $aMatches))
|
||||
{
|
||||
$aHeader = array($aMatches[2] => $aMatches[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
$aHeader = array($sValue);
|
||||
}
|
||||
$oHeaders->addMailboxHeader($sKey, $aHeader);
|
||||
break;
|
||||
|
||||
default:
|
||||
$oHeaders->addTextHeader($sKey, $sValue);
|
||||
}
|
||||
$this->m_aHeaders[$sKey] = $sValue;
|
||||
}
|
||||
}
|
||||
|
||||
public function SetMessageId($sId)
|
||||
{
|
||||
// Note: Swift will add the angle brackets for you
|
||||
// so let's remove the angle brackets if present, for historical reasons
|
||||
$sId = str_replace(array('<', '>'), '', $sId);
|
||||
|
||||
$oMsgId = $this->m_oMessage->getHeaders()->get('Message-ID');
|
||||
$oMsgId->SetId($sId);
|
||||
$this->AddToHeader('Message-ID', $sId);
|
||||
}
|
||||
|
||||
public function SetReferences($sReferences)
|
||||
@@ -177,60 +155,19 @@ class EMail
|
||||
$this->AddToHeader('References', $sReferences);
|
||||
}
|
||||
|
||||
public function SetBody($sBody, $sMimeType = 'text/html')
|
||||
public function SetBody($sBody)
|
||||
{
|
||||
$this->m_oMessage->setBody($sBody, $sMimeType);
|
||||
}
|
||||
|
||||
public function AddPart($sText, $sMimeType = 'text/html')
|
||||
{
|
||||
$this->m_oMessage->addPart($sText, $sMimeType);
|
||||
}
|
||||
|
||||
public function AddAttachment($data, $sFileName, $sMimeType)
|
||||
{
|
||||
$this->m_oMessage->attach(Swift_Attachment::newInstance($data, $sFileName, $sMimeType));
|
||||
$this->m_sBody = $sBody;
|
||||
}
|
||||
|
||||
public function SetSubject($aSubject)
|
||||
{
|
||||
$this->m_oMessage->setSubject($aSubject);
|
||||
}
|
||||
|
||||
public function GetSubject()
|
||||
{
|
||||
return $this->m_oMessage->getSubject();
|
||||
$this->m_sSubject = $aSubject;
|
||||
}
|
||||
|
||||
public function SetRecipientTO($sAddress)
|
||||
{
|
||||
$this->m_oMessage->setTo($sAddress);
|
||||
}
|
||||
|
||||
public function GetRecipientTO($bAsString = false)
|
||||
{
|
||||
$aRes = $this->m_oMessage->getTo();
|
||||
if ($bAsString)
|
||||
{
|
||||
$aStrings = array();
|
||||
foreach ($aRes as $sEmail => $sName)
|
||||
{
|
||||
if (is_null($sName))
|
||||
{
|
||||
$aStrings[] = $sEmail;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sName = str_replace(array('<', '>'), '', $sName);
|
||||
$aStrings[] = "$sName <$sEmail>";
|
||||
}
|
||||
}
|
||||
return implode(', ', $aStrings);
|
||||
}
|
||||
else
|
||||
{
|
||||
return $aRes;
|
||||
}
|
||||
$this->m_sTo = $sAddress;
|
||||
}
|
||||
|
||||
public function SetRecipientCC($sAddress)
|
||||
@@ -243,16 +180,14 @@ class EMail
|
||||
$this->AddToHeader('Bcc', $sAddress);
|
||||
}
|
||||
|
||||
public function SetRecipientFrom($sAddress, $sLabel = '')
|
||||
public function SetRecipientFrom($sAddress)
|
||||
{
|
||||
if ($sLabel != '')
|
||||
{
|
||||
$this->m_oMessage->setFrom(array($sAddress => $sLabel));
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->m_oMessage->setFrom($sAddress);
|
||||
}
|
||||
$this->AddToHeader('From', $sAddress);
|
||||
|
||||
// This is required on Windows because otherwise I would get the error
|
||||
// "sendmail_from" not set in php.ini" even if it is correctly working
|
||||
// (apparently, once it worked the SMTP server won't claim anymore for it)
|
||||
ini_set("sendmail_from", $sAddress);
|
||||
}
|
||||
|
||||
public function SetRecipientReplyTo($sAddress)
|
||||
@@ -260,6 +195,48 @@ class EMail
|
||||
$this->AddToHeader('Reply-To', $sAddress);
|
||||
}
|
||||
|
||||
public function AddAttachment($data, $sFileName, $sMimeType)
|
||||
{
|
||||
$this->m_aAttachments[] = array('data' => $data, 'filename' => $sFileName, 'mimeType' => $sMimeType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes care of the attachments (if any) to build the header/body of the message before storing or sending it
|
||||
*/
|
||||
protected function BuildMessage()
|
||||
{
|
||||
if (count($this->m_aAttachments) == 0) return; // Nothing to do if there are no attachments
|
||||
|
||||
$sDelimiter = '== iTopEmailPart---'.md5(date('r', time()))." ==";
|
||||
$sContentType = isset($this->m_aHeaders['Content-Type']) ? $this->m_aHeaders['Content-Type'] : 'text/html; charset="UTF-8"';
|
||||
$sContentHeader = "Content-Type: $sContentType\r\n";
|
||||
$this->m_aHeaders['Content-Type'] = "multipart/mixed; boundary=\"{$sDelimiter}\"";
|
||||
|
||||
$aAttachments = array();
|
||||
foreach($this->m_aAttachments as $aAttach)
|
||||
{
|
||||
$sAttachmentHeader = "Content-Type: {$aAttach['mimeType']};\r\n Name=\"{$aAttach['filename']}\"\r\n";
|
||||
$sAttachmentHeader .= "Content-Transfer-Encoding: base64\r\nContent-Disposition: attachment;\r\n filename=\"{$aAttach['filename']}\"\r\n";
|
||||
$sAttachmentHeader .= "\r\n";
|
||||
$sAttachment = chunk_split(base64_encode($aAttach['data']));
|
||||
$aAttachments[] = $sAttachmentHeader.$sAttachment."\r\n";
|
||||
}
|
||||
$this->m_sBody = "This is a multi-part message in MIME format.\r\n--".$sDelimiter."\r\n".$sContentHeader."\r\n".$this->m_sBody."\r\n--".$sDelimiter."\r\n";
|
||||
$this->m_sBody .= implode("--".$sDelimiter."\r\n", $aAttachments);
|
||||
$this->m_sBody .= "--".$sDelimiter."--";
|
||||
}
|
||||
|
||||
/**
|
||||
* MIME encode the content of a header field according to RFC2047
|
||||
* @param string $sFieldContent the content of the header to encode
|
||||
* @return string The encoded string
|
||||
*/
|
||||
protected function EncodeHeaderField($sFieldContent)
|
||||
{
|
||||
$sTemp = str_replace(array("\n", "\r"), ' ', $sFieldContent);
|
||||
$sTemp = iconv_mime_encode('Tagada', $sTemp, array('scheme' => 'Q', 'input-charset' => 'UTF-8', 'output-charset' => 'UTF-8'));
|
||||
return preg_replace('/^Tagada: /', '', $sTemp);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -91,19 +91,6 @@ abstract class Expression
|
||||
}
|
||||
|
||||
abstract public function RenameParam($sOldName, $sNewName);
|
||||
|
||||
/**
|
||||
* Make the most relevant label, given the value of the expression
|
||||
*
|
||||
* @param DBObjectSearch oFilter The context in which this expression has been used
|
||||
* @param string sValue The value returned by the query, for this expression
|
||||
* @param string sDefault The default value if no relevant label could be computed
|
||||
* @return The label
|
||||
*/
|
||||
public function MakeValueLabel($oFilter, $sValue, $sDefault)
|
||||
{
|
||||
return $sDefault;
|
||||
}
|
||||
}
|
||||
|
||||
class SQLExpression extends Expression
|
||||
@@ -366,26 +353,12 @@ class ScalarExpression extends UnaryExpression
|
||||
{
|
||||
public function __construct($value)
|
||||
{
|
||||
if (!is_scalar($value) && !is_null($value))
|
||||
if (!is_scalar($value))
|
||||
{
|
||||
throw new CoreException('Attempt to create a scalar expression from a non scalar', array('var_type'=>gettype($value)));
|
||||
}
|
||||
parent::__construct($value);
|
||||
}
|
||||
|
||||
// recursive rendering
|
||||
public function Render(&$aArgs = null, $bRetrofitParams = false)
|
||||
{
|
||||
if (is_null($this->m_value))
|
||||
{
|
||||
$sRet = 'NULL';
|
||||
}
|
||||
else
|
||||
{
|
||||
$sRet = CMDBSource::Quote($this->m_value);
|
||||
}
|
||||
return $sRet;
|
||||
}
|
||||
}
|
||||
|
||||
class TrueExpression extends ScalarExpression
|
||||
@@ -458,12 +431,6 @@ class FieldExpression extends UnaryExpression
|
||||
// Add a reference to the field
|
||||
$aUnresolved[$this->m_sName] = $this;
|
||||
}
|
||||
elseif ($sAlias == '')
|
||||
{
|
||||
// An empty alias means "any alias"
|
||||
// In such a case, the results are indexed differently
|
||||
$aUnresolved[$this->m_sParent][$this->m_sName] = $this;
|
||||
}
|
||||
}
|
||||
|
||||
public function Translate($aTranslationData, $bMatchAll = true, $bMarkFieldsAsResolved = true)
|
||||
@@ -498,52 +465,6 @@ class FieldExpression extends UnaryExpression
|
||||
}
|
||||
return $oRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the most relevant label, given the value of the expression
|
||||
*
|
||||
* @param DBObjectSearch oFilter The context in which this expression has been used
|
||||
* @param string sValue The value returned by the query, for this expression
|
||||
* @param string sDefault The default value if no relevant label could be computed
|
||||
* @return The label
|
||||
*/
|
||||
public function MakeValueLabel($oFilter, $sValue, $sDefault)
|
||||
{
|
||||
$sAttCode = $this->GetName();
|
||||
$sParentAlias = $this->GetParent();
|
||||
|
||||
$aSelectedClasses = $oFilter->GetSelectedClasses();
|
||||
$sClass = $aSelectedClasses[$sParentAlias];
|
||||
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
// Set a default value for the general case
|
||||
$sRes = $oAttDef->GetAsHtml($sValue);
|
||||
|
||||
// Exceptions...
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
$sObjClass = $oAttDef->GetTargetClass();
|
||||
$iObjKey = (int)$sValue;
|
||||
if ($iObjKey > 0)
|
||||
{
|
||||
$oObject = MetaModel::GetObject($sObjClass, $iObjKey);
|
||||
$sRes = $oObject->GetHyperlink();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Undefined
|
||||
$sRes = DBObject::MakeHyperLink($sObjClass, 0);
|
||||
}
|
||||
}
|
||||
elseif ($oAttDef->IsExternalField())
|
||||
{
|
||||
if (is_null($sValue))
|
||||
{
|
||||
$sRes = Dict::S('UI:UndefinedObject');
|
||||
}
|
||||
}
|
||||
return $sRes;
|
||||
}
|
||||
}
|
||||
|
||||
// Has been resolved into an SQL expression
|
||||
@@ -829,46 +750,7 @@ class FunctionExpression extends Expression
|
||||
{
|
||||
$this->m_aArgs[$key] = $oExpr->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make the most relevant label, given the value of the expression
|
||||
*
|
||||
* @param DBObjectSearch oFilter The context in which this expression has been used
|
||||
* @param string sValue The value returned by the query, for this expression
|
||||
* @param string sDefault The default value if no relevant label could be computed
|
||||
* @return The label
|
||||
*/
|
||||
public function MakeValueLabel($oFilter, $sValue, $sDefault)
|
||||
{
|
||||
$sRes = $sDefault;
|
||||
if (strtolower($this->m_sVerb) == 'date_format')
|
||||
{
|
||||
$oFormatExpr = $this->m_aArgs[1];
|
||||
if ($oFormatExpr->Render() == "'%w'")
|
||||
{
|
||||
static $aWeekDayToString = null;
|
||||
if (is_null($aWeekDayToString))
|
||||
{
|
||||
// Init the correspondance table
|
||||
$aWeekDayToString = array(
|
||||
0 => Dict::S('DayOfWeek-Sunday'),
|
||||
1 => Dict::S('DayOfWeek-Monday'),
|
||||
2 => Dict::S('DayOfWeek-Tuesday'),
|
||||
3 => Dict::S('DayOfWeek-Wednesday'),
|
||||
4 => Dict::S('DayOfWeek-Thursday'),
|
||||
5 => Dict::S('DayOfWeek-Friday'),
|
||||
6 => Dict::S('DayOfWeek-Saturday')
|
||||
);
|
||||
}
|
||||
if (isset($aWeekDayToString[(int)$sValue]))
|
||||
{
|
||||
$sRes = $aWeekDayToString[(int)$sValue];
|
||||
}
|
||||
}
|
||||
}
|
||||
return $sRes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class IntervalExpression extends Expression
|
||||
@@ -1069,14 +951,12 @@ class QueryBuilderExpressions
|
||||
{
|
||||
protected $m_oConditionExpr;
|
||||
protected $m_aSelectExpr;
|
||||
protected $m_aGroupByExpr;
|
||||
protected $m_aJoinFields;
|
||||
|
||||
public function __construct($oCondition, $aGroupByExpr = null)
|
||||
public function __construct($oCondition)
|
||||
{
|
||||
$this->m_oConditionExpr = $oCondition;
|
||||
$this->m_aSelectExpr = array();
|
||||
$this->m_aGroupByExpr = $aGroupByExpr;
|
||||
$this->m_aJoinFields = array();
|
||||
}
|
||||
|
||||
@@ -1085,11 +965,6 @@ class QueryBuilderExpressions
|
||||
return $this->m_aSelectExpr;
|
||||
}
|
||||
|
||||
public function GetGroupBy()
|
||||
{
|
||||
return $this->m_aGroupByExpr;
|
||||
}
|
||||
|
||||
public function GetCondition()
|
||||
{
|
||||
return $this->m_oConditionExpr;
|
||||
@@ -1123,13 +998,6 @@ class QueryBuilderExpressions
|
||||
{
|
||||
$oExpr->GetUnresolvedFields($sAlias, $aUnresolved);
|
||||
}
|
||||
if ($this->m_aGroupByExpr)
|
||||
{
|
||||
foreach($this->m_aGroupByExpr as $sColAlias => $oExpr)
|
||||
{
|
||||
$oExpr->GetUnresolvedFields($sAlias, $aUnresolved);
|
||||
}
|
||||
}
|
||||
foreach($this->m_aJoinFields as $oExpression)
|
||||
{
|
||||
$oExpression->GetUnresolvedFields($sAlias, $aUnresolved);
|
||||
@@ -1143,13 +1011,6 @@ class QueryBuilderExpressions
|
||||
{
|
||||
$this->m_aSelectExpr[$sColAlias] = $oExpr->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
|
||||
}
|
||||
if ($this->m_aGroupByExpr)
|
||||
{
|
||||
foreach($this->m_aGroupByExpr as $sColAlias => $oExpr)
|
||||
{
|
||||
$this->m_aGroupByExpr[$sColAlias] = $oExpr->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
|
||||
}
|
||||
}
|
||||
foreach($this->m_aJoinFields as $index => $oExpression)
|
||||
{
|
||||
$this->m_aJoinFields[$index] = $oExpression->Translate($aTranslationData, $bMatchAll, $bMarkFieldsAsResolved);
|
||||
@@ -1163,13 +1024,6 @@ class QueryBuilderExpressions
|
||||
{
|
||||
$this->m_aSelectExpr[$sColAlias] = $oExpr->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
if ($this->m_aGroupByExpr)
|
||||
{
|
||||
foreach($this->m_aGroupByExpr as $sColAlias => $oExpr)
|
||||
{
|
||||
$this->m_aGroupByExpr[$sColAlias] = $oExpr->RenameParam($sOldName, $sNewName);
|
||||
}
|
||||
}
|
||||
foreach($this->m_aJoinFields as $index => $oExpression)
|
||||
{
|
||||
$this->m_aJoinFields[$index] = $oExpression->RenameParam($sOldName, $sNewName);
|
||||
|
||||
@@ -50,6 +50,22 @@ abstract class FilterDefinition
|
||||
$this->ConsistencyCheck();
|
||||
}
|
||||
|
||||
// Left here for backward compatibility, deprecated in 2.0
|
||||
public function OverloadParams($aParams)
|
||||
{
|
||||
foreach ($aParams as $sParam => $value)
|
||||
{
|
||||
if (!array_key_exists($sParam, $this->m_aParams))
|
||||
{
|
||||
throw new CoreException("Unknown attribute definition parameter '$sParam', please select a value in {".implode(", ", $this->m_aParams)."}");
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->m_aParams[$sParam] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// to be overloaded
|
||||
static protected function ListExpectedParams()
|
||||
{
|
||||
@@ -155,13 +171,12 @@ class FilterFromAttribute extends FilterDefinition
|
||||
return array_merge(parent::ListExpectedParams(), array("refattribute"));
|
||||
}
|
||||
|
||||
public function __construct($oRefAttribute, $sSuffix = '')
|
||||
public function __construct($oRefAttribute, $aParam = array())
|
||||
{
|
||||
// In this very specific case, the code is the one of the attribute
|
||||
// (this to get a very very simple syntax upon declaration)
|
||||
$aParam = array();
|
||||
$aParam["refattribute"] = $oRefAttribute;
|
||||
parent::__construct($oRefAttribute->GetCode().$sSuffix, $aParam);
|
||||
parent::__construct($oRefAttribute->GetCode(), $aParam);
|
||||
}
|
||||
|
||||
public function GetType() {return "Basic";}
|
||||
|
||||
@@ -18,7 +18,6 @@ require_once(APPROOT.'core/modulehandler.class.inc.php');
|
||||
require_once(APPROOT.'core/querybuildercontext.class.inc.php');
|
||||
require_once(APPROOT.'core/querymodifier.class.inc.php');
|
||||
require_once(APPROOT.'core/metamodelmodifier.inc.php');
|
||||
require_once(APPROOT.'core/computing.inc.php');
|
||||
|
||||
/**
|
||||
* Metamodel
|
||||
@@ -297,7 +296,7 @@ abstract class MetaModel
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
$sStringCode = 'Class:'.$sClass;
|
||||
return Dict::S($sStringCode, str_replace('_', ' ', $sClass));
|
||||
return Dict::S($sStringCode, $sClass);
|
||||
}
|
||||
final static public function GetName_Obsolete($sClass)
|
||||
{
|
||||
@@ -377,10 +376,9 @@ abstract class MetaModel
|
||||
$sParentClass = self::GetParentPersistentClass($sClass);
|
||||
if (strlen($sParentClass) > 0)
|
||||
{
|
||||
return self::GetClassIcon($sParentClass, $bImgTag, $sMoreStyles);
|
||||
return self::GetClassIcon($sParentClass);
|
||||
}
|
||||
}
|
||||
$sIcon = str_replace('/modules/', '/env-'.utils::GetCurrentEnvironment().'/', $sIcon); // Support of pre-2.0 modules
|
||||
if ($bImgTag && ($sIcon != ''))
|
||||
{
|
||||
$sIcon = "<img src=\"$sIcon\" style=\"vertical-align:middle;$sMoreStyles\"/>";
|
||||
@@ -427,17 +425,16 @@ abstract class MetaModel
|
||||
return array('%1$s', array($nameRawSpec));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the friendly name expression for a given class
|
||||
*/
|
||||
final static public function GetNameExpression($sClass)
|
||||
final static public function GetNameExpression($sClass, $sClassAlias)
|
||||
{
|
||||
$aNameSpec = self::GetNameSpec($sClass);
|
||||
$sFormat = $aNameSpec[0];
|
||||
$aAttributes = $aNameSpec[1];
|
||||
|
||||
$aPieces = preg_split('/%([0-9])\\$s/', $sFormat, -1, PREG_SPLIT_DELIM_CAPTURE);
|
||||
//echo "<pre>\n";
|
||||
//print_r($aPieces);
|
||||
//echo "</pre>\n";
|
||||
$aExpressions = array();
|
||||
foreach($aPieces as $i => $sPiece)
|
||||
{
|
||||
@@ -449,18 +446,8 @@ abstract class MetaModel
|
||||
|
||||
if (isset($aAttributes[$iReplacement]))
|
||||
{
|
||||
$sAttCode = $aAttributes[$iReplacement];
|
||||
$oAttDef = self::GetAttributeDef($sClass, $sAttCode);
|
||||
if ($oAttDef->IsExternalField() || ($oAttDef instanceof AttributeFriendlyName))
|
||||
{
|
||||
$sKeyAttCode = $oAttDef->GetKeyAttCode();
|
||||
$sClassOfAttribute = self::GetAttributeOrigin($sClass, $sKeyAttCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sClassOfAttribute = self::GetAttributeOrigin($sClass, $sAttCode);
|
||||
}
|
||||
$aExpressions[] = new FieldExpression($sAttCode, $sClassOfAttribute);
|
||||
$sAtt = $aAttributes[$iReplacement];
|
||||
$aExpressions[] = new FieldExpression($sAtt, $sClassAlias);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -473,67 +460,14 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
}
|
||||
//echo "<pre>\n";
|
||||
//print_r($aExpressions);
|
||||
//echo "</pre>\n";
|
||||
|
||||
$oNameExpr = new CharConcatExpression($aExpressions);
|
||||
return $oNameExpr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the friendly name for the class and its subclasses (if finalclass = 'subclass' ...)
|
||||
* Simplifies the final expression by grouping classes having the same name expression
|
||||
* Used when querying a parent class
|
||||
*/
|
||||
final static protected function GetExtendedNameExpression($sClass)
|
||||
{
|
||||
// 1st step - get all of the required expressions (instantiable classes)
|
||||
// and group them using their OQL representation
|
||||
//
|
||||
$aFNExpressions = array(); // signature => array('expression' => oExp, 'classes' => array of classes)
|
||||
foreach (self::EnumChildClasses($sClass, ENUM_CHILD_CLASSES_ALL) as $sSubClass)
|
||||
{
|
||||
if (($sSubClass != $sClass) && self::IsAbstract($sSubClass)) continue;
|
||||
|
||||
$oSubClassName = self::GetNameExpression($sSubClass);
|
||||
$sSignature = $oSubClassName->Render();
|
||||
if (!array_key_exists($sSignature, $aFNExpressions))
|
||||
{
|
||||
$aFNExpressions[$sSignature] = array(
|
||||
'expression' => $oSubClassName,
|
||||
'classes' => array(),
|
||||
);
|
||||
}
|
||||
$aFNExpressions[$sSignature]['classes'][] = $sSubClass;
|
||||
}
|
||||
|
||||
// 2nd step - build the final name expression depending on the finalclass
|
||||
//
|
||||
if (count($aFNExpressions) == 1)
|
||||
{
|
||||
$aExpData = reset($aFNExpressions);
|
||||
$oNameExpression = $aExpData['expression'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$oNameExpression = null;
|
||||
foreach ($aFNExpressions as $sSignature => $aExpData)
|
||||
{
|
||||
$oClassListExpr = ListExpression::FromScalars($aExpData['classes']);
|
||||
$oClassExpr = new FieldExpression('finalclass', $sClass);
|
||||
$oClassInList = new BinaryExpression($oClassExpr, 'IN', $oClassListExpr);
|
||||
|
||||
if (is_null($oNameExpression))
|
||||
{
|
||||
$oNameExpression = $aExpData['expression'];
|
||||
}
|
||||
else
|
||||
{
|
||||
$oNameExpression = new FunctionExpression('IF', array($oClassInList, $aExpData['expression'], $oNameExpression));
|
||||
}
|
||||
}
|
||||
}
|
||||
return $oNameExpression;
|
||||
}
|
||||
|
||||
final static public function GetStateAttributeCode($sClass)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
@@ -560,26 +494,6 @@ abstract class MetaModel
|
||||
self::_check_subclass($sClass);
|
||||
return array_key_exists("display_template", self::$m_aClassParams[$sClass]) ? self::$m_aClassParams[$sClass]["display_template"]: '';
|
||||
}
|
||||
|
||||
final static public function GetOrderByDefault($sClass, $bOnlyDeclared = false)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
$aOrderBy = array_key_exists("order_by_default", self::$m_aClassParams[$sClass]) ? self::$m_aClassParams[$sClass]["order_by_default"]: array();
|
||||
if ($bOnlyDeclared)
|
||||
{
|
||||
// Used to reverse engineer the declaration of the data model
|
||||
return $aOrderBy;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (count($aOrderBy) == 0)
|
||||
{
|
||||
$aOrderBy['friendlyname'] = true;
|
||||
}
|
||||
return $aOrderBy;
|
||||
}
|
||||
}
|
||||
|
||||
final static public function GetAttributeOrigin($sClass, $sAttCode)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
@@ -648,7 +562,7 @@ abstract class MetaModel
|
||||
return self::$m_sTablePrefix."view_".$sClass;
|
||||
}
|
||||
|
||||
final static public function DBEnumTables()
|
||||
final static protected function DBEnumTables()
|
||||
{
|
||||
// This API does not rely on our capability to query the DB and retrieve
|
||||
// the list of existing tables
|
||||
@@ -825,6 +739,10 @@ abstract class MetaModel
|
||||
final static public function GetAttributeDef($sClass, $sAttCode)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
if (!array_key_exists($sAttCode, self::$m_aAttribDefs[$sClass]))
|
||||
{
|
||||
echo "<p>$sAttCode is NOT a valid attribute of class $sClass.</p>";
|
||||
}
|
||||
return self::$m_aAttribDefs[$sClass][$sAttCode];
|
||||
}
|
||||
|
||||
@@ -908,11 +826,7 @@ abstract class MetaModel
|
||||
|
||||
final static public function GetClassFilterDef($sClass, $sFilterCode)
|
||||
{
|
||||
self::_check_subclass($sClass);
|
||||
if (!array_key_exists($sFilterCode, self::$m_aFilterDefs[$sClass]))
|
||||
{
|
||||
throw new CoreException("Unknown filter code '$sFilterCode' for class '$sClass'");
|
||||
}
|
||||
self::_check_subclass($sClass);
|
||||
return self::$m_aFilterDefs[$sClass][$sFilterCode];
|
||||
}
|
||||
|
||||
@@ -1261,7 +1175,7 @@ abstract class MetaModel
|
||||
|
||||
// Build the list of available extensions
|
||||
//
|
||||
$aInterfaces = array('iApplicationUIExtension', 'iApplicationObjectExtension', 'iQueryModifier', 'iOnClassInitialization', 'iPopupMenuExtension');
|
||||
$aInterfaces = array('iApplicationUIExtension', 'iApplicationObjectExtension', 'iQueryModifier', 'iOnClassInitialization');
|
||||
foreach($aInterfaces as $sInterface)
|
||||
{
|
||||
self::$m_aExtensionClasses[$sInterface] = array();
|
||||
@@ -1407,7 +1321,7 @@ abstract class MetaModel
|
||||
$sRemoteAttCode = $oAttDef->GetExtAttCode()."_friendlyname";
|
||||
$sFriendlyNameAttCode = $sAttCode.'_friendlyname';
|
||||
// propagate "is_null_allowed" ?
|
||||
$oFriendlyName = new AttributeExternalField($sFriendlyNameAttCode, array("allowed_values"=>null, "extkey_attcode"=>$sKeyAttCode, "target_attcode"=>$sRemoteAttCode, "depends_on"=>array()));
|
||||
$oFriendlyName = new AttributeExternalField($sFriendlyNameAttCode, array("allowed_values"=>null, "extkey_attcode"=>$sKeyAttCode, "target_attcode"=>$sRemoteAttCode, "is_null_allowed"=>true, "depends_on"=>array()));
|
||||
$oFriendlyName->SetHostClass($sClass);
|
||||
self::$m_aAttribDefs[$sClass][$sFriendlyNameAttCode] = $oFriendlyName;
|
||||
self::$m_aAttribOrigins[$sClass][$sFriendlyNameAttCode] = $sRemoteClass;
|
||||
@@ -1636,6 +1550,18 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
|
||||
// Left here for backward compatibility, deprecated in 2.0
|
||||
public static function Init_OverloadAttributeParams($sAttCode, $aParams)
|
||||
{
|
||||
$sTargetClass = self::GetCallersPHPClass("Init");
|
||||
|
||||
if (!self::IsValidAttCode($sTargetClass, $sAttCode))
|
||||
{
|
||||
throw new CoreException("Could not overload '$sAttCode', expecting a code from {".implode(", ", self::GetAttributesList($sTargetClass))."}");
|
||||
}
|
||||
self::$m_aAttribDefs[$sTargetClass][$sAttCode]->OverloadParams($aParams);
|
||||
}
|
||||
|
||||
protected static function Init_IsKnownClass($sClass)
|
||||
{
|
||||
// Differs from self::IsValidClass()
|
||||
@@ -1976,7 +1902,7 @@ abstract class MetaModel
|
||||
|
||||
protected static $m_aQueryStructCache = array();
|
||||
|
||||
public static function PrepareQueryArguments($aArgs)
|
||||
protected static function PrepareQueryArguments($aArgs)
|
||||
{
|
||||
// Translate any object into scalars
|
||||
//
|
||||
@@ -1999,86 +1925,7 @@ abstract class MetaModel
|
||||
return $aScalarArgs;
|
||||
}
|
||||
|
||||
public static function MakeGroupByQuery(DBObjectSearch $oFilter, $aArgs, $aGroupByExpr)
|
||||
{
|
||||
$aAttToLoad = array();
|
||||
$oSelect = self::MakeSelectStructure($oFilter, array(), $aArgs, $aAttToLoad, null, 0, 0, false, $aGroupByExpr);
|
||||
|
||||
$aScalarArgs = array_merge(self::PrepareQueryArguments($aArgs), $oFilter->GetInternalParams());
|
||||
try
|
||||
{
|
||||
$sRes = $oSelect->RenderGroupBy($aScalarArgs);
|
||||
}
|
||||
catch (MissingQueryArgument $e)
|
||||
{
|
||||
// Add some information...
|
||||
$e->addInfo('OQL', $oFilter->ToOQL());
|
||||
throw $e;
|
||||
}
|
||||
return $sRes;
|
||||
}
|
||||
|
||||
|
||||
public static function MakeSelectQuery(DBObjectSearch $oFilter, $aOrderBy = array(), $aArgs = array(), $aAttToLoad = null, $aExtendedDataSpec = null, $iLimitCount = 0, $iLimitStart = 0, $bGetCount = false)
|
||||
{
|
||||
// Check the order by specification, and prefix with the class alias
|
||||
// and make sure that the ordering columns are going to be selected
|
||||
//
|
||||
$aOrderSpec = array();
|
||||
foreach ($aOrderBy as $sFieldAlias => $bAscending)
|
||||
{
|
||||
if ($sFieldAlias != 'id')
|
||||
{
|
||||
MyHelpers::CheckValueInArray('field name in ORDER BY spec', $sFieldAlias, self::GetAttributesList($oFilter->GetFirstJoinedClass()));
|
||||
}
|
||||
if (!is_bool($bAscending))
|
||||
{
|
||||
throw new CoreException("Wrong direction in ORDER BY spec, found '$bAscending' and expecting a boolean value");
|
||||
}
|
||||
$sFirstClassAlias = $oFilter->GetClassAlias();
|
||||
|
||||
if (self::IsValidAttCode($oFilter->GetClass(), $sFieldAlias))
|
||||
{
|
||||
$oAttDef = self::GetAttributeDef($oFilter->GetClass(), $sFieldAlias);
|
||||
foreach($oAttDef->GetOrderBySQLExpressions($sFirstClassAlias) as $sSQLExpression)
|
||||
{
|
||||
$aOrderSpec[$sSQLExpression] = $bAscending;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$aOrderSpec['`'.$sFirstClassAlias.$sFieldAlias.'`'] = $bAscending;
|
||||
}
|
||||
|
||||
// Make sure that the columns used for sorting are present in the loaded columns
|
||||
if (!is_null($aAttToLoad) && !isset($aAttToLoad[$sFirstClassAlias][$sFieldAlias]))
|
||||
{
|
||||
$aAttToLoad[$sFirstClassAlias][$sFieldAlias] = MetaModel::GetAttributeDef($oFilter->GetFirstJoinedClass(), $sFieldAlias);
|
||||
}
|
||||
}
|
||||
|
||||
$oSelect = self::MakeSelectStructure($oFilter, $aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount);
|
||||
|
||||
$aScalarArgs = array_merge(self::PrepareQueryArguments($aArgs), $oFilter->GetInternalParams());
|
||||
try
|
||||
{
|
||||
$sRes = $oSelect->RenderSelect($aOrderSpec, $aScalarArgs, $iLimitCount, $iLimitStart, $bGetCount);
|
||||
if ($oFilter->GetClassAlias() == 'itop')
|
||||
{
|
||||
echo $sRes."<br/>\n";
|
||||
}
|
||||
}
|
||||
catch (MissingQueryArgument $e)
|
||||
{
|
||||
// Add some information...
|
||||
$e->addInfo('OQL', $sOqlQuery);
|
||||
throw $e;
|
||||
}
|
||||
return $sRes;
|
||||
}
|
||||
|
||||
|
||||
protected static function MakeSelectStructure(DBObjectSearch $oFilter, $aOrderBy, $aArgs, $aAttToLoad, $aExtendedDataSpec, $iLimitCount, $iLimitStart, $bGetCount, $aGroupByExpr = null)
|
||||
{
|
||||
// Hide objects that are not visible to the current user
|
||||
//
|
||||
@@ -2129,13 +1976,6 @@ abstract class MetaModel
|
||||
$sRawId = $sOqlQuery.'|'.implode(',', array_keys($aAttributes));
|
||||
}
|
||||
}
|
||||
if (!is_null($aGroupByExpr))
|
||||
{
|
||||
foreach($aGroupByExpr as $sAlias => $oExpr)
|
||||
{
|
||||
$sRawId = 'g:'.$sAlias.'!'.$oExpr->Render();
|
||||
}
|
||||
}
|
||||
$sOqlId = md5($sRawId);
|
||||
}
|
||||
else
|
||||
@@ -2168,7 +2008,8 @@ abstract class MetaModel
|
||||
{
|
||||
// Note: For versions of APC older than 3.0.17, fetch() accepts only one parameter
|
||||
//
|
||||
$sOqlAPCCacheId = 'itop-'.MetaModel::GetEnvironmentId().'-query-cache-'.$sOqlId;
|
||||
$sAppIdentity = self::GetConfig()->Get('session_name');
|
||||
$sOqlAPCCacheId = $sAppIdentity.'-query-cache-'.$sOqlId;
|
||||
$oKPI = new ExecutionKPI();
|
||||
$result = apc_fetch($sOqlAPCCacheId);
|
||||
$oKPI->ComputeStats('Query APC (fetch)', $sOqlQuery);
|
||||
@@ -2181,25 +2022,53 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
|
||||
// Check the order by specification, and prefix with the class alias
|
||||
// and make sure that the ordering columns are going to be selected
|
||||
//
|
||||
$aOrderSpec = array();
|
||||
foreach ($aOrderBy as $sFieldAlias => $bAscending)
|
||||
{
|
||||
if ($sFieldAlias != 'id')
|
||||
{
|
||||
MyHelpers::CheckValueInArray('field name in ORDER BY spec', $sFieldAlias, self::GetAttributesList($oFilter->GetFirstJoinedClass()));
|
||||
}
|
||||
if (!is_bool($bAscending))
|
||||
{
|
||||
throw new CoreException("Wrong direction in ORDER BY spec, found '$bAscending' and expecting a boolean value");
|
||||
}
|
||||
$sFirstClassAlias = $oFilter->GetFirstJoinedClassAlias();
|
||||
$aOrderSpec[$sFirstClassAlias.$sFieldAlias] = $bAscending;
|
||||
|
||||
// Make sure that the columns used for sorting are present in the loaded columns
|
||||
if (!is_null($aAttToLoad) && !isset($aAttToLoad[$sFirstClassAlias][$sFieldAlias]))
|
||||
{
|
||||
$aAttToLoad[$sFirstClassAlias][$sFieldAlias] = MetaModel::GetAttributeDef($oFilter->GetFirstJoinedClass(), $sFieldAlias);
|
||||
}
|
||||
}
|
||||
// By default, force the name attribute to be the ordering key
|
||||
//
|
||||
if (empty($aOrderSpec))
|
||||
{
|
||||
foreach ($oFilter->GetSelectedClasses() as $sSelectedAlias => $sSelectedClass)
|
||||
{
|
||||
// By default, simply order on the "friendlyname" attribute, ascending
|
||||
$aOrderSpec[$sSelectedAlias."friendlyname"] = true;
|
||||
|
||||
// Make sure that the columns used for sorting are present in the loaded columns
|
||||
if (!is_null($aAttToLoad) && !isset($aAttToLoad[$sSelectedAlias]["friendlyname"]))
|
||||
{
|
||||
$aAttToLoad[$sSelectedAlias]["friendlyname"] = MetaModel::GetAttributeDef($sSelectedClass, "friendlyname");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isset($oSelect))
|
||||
{
|
||||
$oBuild = new QueryBuilderContext($oFilter, $aModifierProperties, $aGroupByExpr);
|
||||
$oBuild = new QueryBuilderContext($oFilter, $aModifierProperties);
|
||||
|
||||
$oKPI = new ExecutionKPI();
|
||||
$oSelect = self::MakeQuery($oBuild, $oFilter, $aAttToLoad, array(), true /* main query */);
|
||||
$oSelect->SetCondition($oBuild->m_oQBExpressions->GetCondition());
|
||||
$oSelect->SetSourceOQL($sOqlQuery);
|
||||
if ($aGroupByExpr)
|
||||
{
|
||||
$aCols = $oBuild->m_oQBExpressions->GetGroupBy();
|
||||
$oSelect->SetGroupBy($aCols);
|
||||
$oSelect->SetSelect($aCols);
|
||||
}
|
||||
else
|
||||
{
|
||||
$oSelect->SetSelect($oBuild->m_oQBExpressions->GetSelect());
|
||||
}
|
||||
|
||||
$oKPI->ComputeStats('MakeQuery (select)', $sOqlQuery);
|
||||
|
||||
if (self::$m_bQueryCacheEnabled)
|
||||
@@ -2224,12 +2093,28 @@ abstract class MetaModel
|
||||
foreach($aExtendedDataSpec['fields'] as $sColumn)
|
||||
{
|
||||
$sColRef = $oFilter->GetClassAlias().'_extdata_'.$sColumn;
|
||||
$aExtendedFields[$sColRef] = new FieldExpressionResolved($sColumn, $sTableAlias);
|
||||
$aExtendedFields[$sColRef] = new FieldExpressionResolved($sColumn, $sTableAlias);;
|
||||
}
|
||||
$oSelectExt = new SQLQuery($aExtendedDataSpec['table'], $sTableAlias, $aExtendedFields);
|
||||
$oSelect->AddInnerJoin($oSelectExt, 'id', $aExtendedDataSpec['join_key'] /*, $sTableAlias*/);
|
||||
}
|
||||
|
||||
// Go
|
||||
//
|
||||
$aScalarArgs = array_merge(self::PrepareQueryArguments($aArgs), $oFilter->GetInternalParams());
|
||||
|
||||
try
|
||||
{
|
||||
$sRes = $oSelect->RenderSelect($aOrderSpec, $aScalarArgs, $iLimitCount, $iLimitStart, $bGetCount);
|
||||
//echo "<p>MakeQuery: $sRes</p>";
|
||||
}
|
||||
catch (MissingQueryArgument $e)
|
||||
{
|
||||
// Add some information...
|
||||
$e->addInfo('OQL', $sOqlQuery);
|
||||
throw $e;
|
||||
}
|
||||
|
||||
if (self::$m_bTraceQueries)
|
||||
{
|
||||
$sQueryId = md5($sRes);
|
||||
@@ -2253,7 +2138,7 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
|
||||
return $oSelect;
|
||||
return $sRes;
|
||||
}
|
||||
|
||||
public static function ShowQueryTrace()
|
||||
@@ -2318,8 +2203,6 @@ abstract class MetaModel
|
||||
$aModifierProperties = self::MakeModifierProperties($oFilter);
|
||||
$oBuild = new QueryBuilderContext($oFilter, $aModifierProperties);
|
||||
$oSelect = self::MakeQuery($oBuild, $oFilter, null, array(), true /* main query */);
|
||||
$oSelect->SetCondition($oBuild->m_oQBExpressions->GetCondition());
|
||||
$oSelect->SetSelect($oBuild->m_oQBExpressions->GetSelect());
|
||||
$aScalarArgs = array_merge(self::PrepareQueryArguments($aArgs), $oFilter->GetInternalParams());
|
||||
return $oSelect->RenderDelete($aScalarArgs);
|
||||
}
|
||||
@@ -2330,13 +2213,11 @@ abstract class MetaModel
|
||||
$aModifierProperties = self::MakeModifierProperties($oFilter);
|
||||
$oBuild = new QueryBuilderContext($oFilter, $aModifierProperties);
|
||||
$oSelect = self::MakeQuery($oBuild, $oFilter, null, $aValues, true /* main query */);
|
||||
$oSelect->SetCondition($oBuild->m_oQBExpressions->GetCondition());
|
||||
$oSelect->SetSelect($oBuild->m_oQBExpressions->GetSelect());
|
||||
$aScalarArgs = array_merge(self::PrepareQueryArguments($aArgs), $oFilter->GetInternalParams());
|
||||
return $oSelect->RenderUpdate($aScalarArgs);
|
||||
}
|
||||
|
||||
private static function MakeQuery(&$oBuild, DBObjectSearch $oFilter, $aAttToLoad = null, $aValues = array(), $bIsMainQueryUNUSED = false)
|
||||
private static function MakeQuery(&$oBuild, DBObjectSearch $oFilter, $aAttToLoad = null, $aValues = array(), $bIsMainQuery = false)
|
||||
{
|
||||
// Note: query class might be different than the class of the filter
|
||||
// -> this occurs when we are linking our class to an external class (referenced by, or pointing to)
|
||||
@@ -2366,7 +2247,6 @@ abstract class MetaModel
|
||||
foreach ($aAttList as $sAttCode => $oAttDef)
|
||||
{
|
||||
if (!$oAttDef->IsScalar()) continue;
|
||||
// keep because it can be used for sorting - if (!$oAttDef->LoadInObject()) continue;
|
||||
|
||||
foreach ($oAttDef->GetSQLExpressions() as $sColId => $sSQLExpr)
|
||||
{
|
||||
@@ -2430,69 +2310,31 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
|
||||
$aFNJoinAlias = array(); // array of (subclass => alias)
|
||||
if (array_key_exists('friendlyname', $aExpectedAtts))
|
||||
{
|
||||
// To optimize: detect a restriction on child classes in the condition expression
|
||||
// e.g. SELECT FunctionalCI WHERE finalclass IN ('Server', 'VirtualMachine')
|
||||
$oNameExpression = self::GetExtendedNameExpression($sClass);
|
||||
$aTranslateNow = array();
|
||||
$aTranslateNow[$sClassAlias]['friendlyname'] = self::GetNameExpression($sClass, $sClassAlias);
|
||||
//echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oBuild->m_oQBExpressions, true)."</pre></p>\n";
|
||||
$oBuild->m_oQBExpressions->Translate($aTranslateNow, false);
|
||||
//echo "<p>oQBExpr ".__LINE__.": <pre>\n".print_r($oBuild->m_oQBExpressions, true)."</pre></p>\n";
|
||||
|
||||
$aNameFields = array();
|
||||
$oNameExpression->GetUnresolvedFields('', $aNameFields);
|
||||
$aTranslateNameFields = array();
|
||||
foreach($aNameFields as $sSubClass => $aFields)
|
||||
$aNameSpec = self::GetNameSpec($sClass);
|
||||
foreach($aNameSpec[1] as $i => $sAttCode)
|
||||
{
|
||||
foreach($aFields as $sAttCode => $oField)
|
||||
$oAttDef = self::GetAttributeDef($sClass, $sAttCode);
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
$oAttDef = self::GetAttributeDef($sSubClass, $sAttCode);
|
||||
if ($oAttDef->IsExternalKey())
|
||||
{
|
||||
$sClassOfAttribute = self::$m_aAttribOrigins[$sSubClass][$sAttCode];
|
||||
$aExtKeys[$sClassOfAttribute][$sAttCode] = array();
|
||||
}
|
||||
elseif ($oAttDef->IsExternalField() || ($oAttDef instanceof AttributeFriendlyName))
|
||||
{
|
||||
$sKeyAttCode = $oAttDef->GetKeyAttCode();
|
||||
$sClassOfAttribute = self::$m_aAttribOrigins[$sSubClass][$sKeyAttCode];
|
||||
$aExtKeys[$sClassOfAttribute][$sKeyAttCode][$sAttCode] = $oAttDef;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sClassOfAttribute = self::GetAttributeOrigin($sSubClass, $sAttCode);
|
||||
}
|
||||
|
||||
if (self::IsParentClass($sClassOfAttribute, $sClass))
|
||||
{
|
||||
// The attribute is part of the standard query
|
||||
//
|
||||
$sAliasForAttribute = $sClassAlias;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The attribute will be available from an additional outer join
|
||||
// For each subclass (table) one single join is enough
|
||||
//
|
||||
if (!array_key_exists($sClassOfAttribute, $aFNJoinAlias))
|
||||
{
|
||||
$sAliasForAttribute = $oBuild->GenerateClassAlias($sClassAlias.'_fn_'.$sClassOfAttribute, $sClassOfAttribute);
|
||||
$aFNJoinAlias[$sClassOfAttribute] = $sAliasForAttribute;
|
||||
}
|
||||
else
|
||||
{
|
||||
$sAliasForAttribute = $aFNJoinAlias[$sClassOfAttribute];
|
||||
}
|
||||
}
|
||||
|
||||
$aTranslateNameFields[$sSubClass][$sAttCode] = new FieldExpression($sAttCode, $sAliasForAttribute);
|
||||
$sKeyTableClass = self::$m_aAttribOrigins[$sClass][$sAttCode];
|
||||
$aExtKeys[$sKeyTableClass][$sAttCode] = array();
|
||||
}
|
||||
elseif ($oAttDef->IsExternalField() || ($oAttDef instanceof AttributeFriendlyName))
|
||||
{
|
||||
$sKeyAttCode = $oAttDef->GetKeyAttCode();
|
||||
$sKeyTableClass = self::$m_aAttribOrigins[$sClass][$sKeyAttCode];
|
||||
$aExtKeys[$sKeyTableClass][$sKeyAttCode][$sAttCode] = $oAttDef;
|
||||
}
|
||||
}
|
||||
$oNameExpression = $oNameExpression->Translate($aTranslateNameFields, false);
|
||||
|
||||
$aTranslateNow = array();
|
||||
$aTranslateNow[$sClassAlias]['friendlyname'] = $oNameExpression;
|
||||
$oBuild->m_oQBExpressions->Translate($aTranslateNow, false);
|
||||
}
|
||||
|
||||
// Add the ext fields used in the select (eventually adds an external key)
|
||||
foreach(self::ListAttributeDefs($sClass) as $sAttCode=>$oAttDef)
|
||||
{
|
||||
@@ -2598,13 +2440,12 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
|
||||
// Additional JOINS for Friendly names
|
||||
// Translate the conditions... and go
|
||||
//
|
||||
foreach ($aFNJoinAlias as $sSubClass => $sSubClassAlias)
|
||||
if ($bIsMainQuery)
|
||||
{
|
||||
$oSubClassFilter = new DBObjectSearch($sSubClass, $sSubClassAlias);
|
||||
$oSelectFN = self::MakeQuerySingleTable($oBuild, $oSubClassFilter, $sSubClass, $aExtKeys, array());
|
||||
$oSelectBase->AddLeftJoin($oSelectFN, $sKeyField, self::DBGetKey($sSubClass));
|
||||
$oSelectBase->SetCondition($oBuild->m_oQBExpressions->GetCondition());
|
||||
$oSelectBase->SetSelect($oBuild->m_oQBExpressions->GetSelect());
|
||||
}
|
||||
|
||||
// That's all... cross fingers and we'll get some working query
|
||||
@@ -2710,7 +2551,7 @@ abstract class MetaModel
|
||||
// add it to the output
|
||||
foreach ($oAttDef->GetSQLExpressions() as $sColId => $sSQLExpr)
|
||||
{
|
||||
if (array_key_exists($sAttCode.$sColId, $aExpectedAtts))
|
||||
if (array_key_exists($sAttCode, $aExpectedAtts))
|
||||
{
|
||||
$oFieldSQLExp = new FieldExpressionResolved($sSQLExpr, $sTableAlias);
|
||||
foreach (MetaModel::EnumPlugins('iQueryModifier') as $sPluginClass => $oQueryModifier)
|
||||
@@ -3797,20 +3638,11 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
// Find out unused columns
|
||||
//
|
||||
foreach($aTableInfo['Fields'] as $sField => $aFieldData)
|
||||
{
|
||||
if (!isset($aFieldData['used']) || !$aFieldData['used'])
|
||||
{
|
||||
$aErrors[$sClass]['*'][] = "Column '$sField' in table '$sTable' is not used";
|
||||
if (!CMDBSource::IsNullAllowed($sTable, $sField))
|
||||
{
|
||||
// Allow null values so that new record can be inserted
|
||||
// without specifying the value of this unknown column
|
||||
$sFieldDefinition = "`$sField` ".CMDBSource::GetFieldType($sTable, $sField).' NULL';
|
||||
$aSugFix[$sClass][$sAttCode][] = "ALTER TABLE `$sTable` CHANGE `$sField` $sFieldDefinition";
|
||||
$aAlterTableItems[$sTable][$sField] = "CHANGE `$sField` $sFieldDefinition";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3844,20 +3676,28 @@ abstract class MetaModel
|
||||
{
|
||||
// Check that the view is complete
|
||||
//
|
||||
// Note: checking the list of attributes is not enough because the columns can be stable while the SELECT is not stable
|
||||
// Example: new way to compute the friendly name
|
||||
// The correct comparison algorithm is to compare the queries,
|
||||
// by using "SHOW CREATE VIEW" (MySQL 5.0.1 required) or to look into INFORMATION_SCHEMA/views
|
||||
// both requiring some privileges
|
||||
// Decision: to simplify, let's consider the views as being wrong anytime
|
||||
if (true)
|
||||
$bIsComplete = true;
|
||||
foreach(self::ListAttributeDefs($sClass) as $sAttCode=>$oAttDef)
|
||||
{
|
||||
foreach($oAttDef->GetSQLExpressions() as $sSuffix => $sTrash)
|
||||
{
|
||||
$sCol = $sAttCode.$sSuffix;
|
||||
if (!CMDBSource::IsField($sView, $sCol))
|
||||
{
|
||||
$bIsComplete = false;
|
||||
$aErrors[$sClass][$sAttCode][] = "field '$sCol' could not be found in view '$sView'";
|
||||
$aSugFix[$sClass][$sAttCode][] = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!$bIsComplete)
|
||||
{
|
||||
// Rework the view
|
||||
//
|
||||
$oFilter = new DBObjectSearch($sClass, '');
|
||||
$oFilter->AllowAllData();
|
||||
$sSQL = self::MakeSelectQuery($oFilter);
|
||||
$aErrors[$sClass]['*'][] = "Redeclare view '$sView' (systematic - to support an eventual change in the friendly name computation)";
|
||||
$aErrors[$sClass]['*'][] = "View '$sView' is currently not complete";
|
||||
$aSugFix[$sClass]['*'][] = "ALTER VIEW `$sView` AS $sSQL";
|
||||
}
|
||||
}
|
||||
@@ -4274,27 +4114,14 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
|
||||
public static function Startup($config, $bModelOnly = false, $bAllowCache = true, $bTraceSourceFiles = false)
|
||||
public static function Startup($sConfigFile, $bModelOnly = false, $bAllowCache = true, $bTraceSourceFiles = false)
|
||||
{
|
||||
if (!defined('MODULESROOT'))
|
||||
{
|
||||
define('MODULESROOT', APPROOT.'env-'.utils::GetCurrentEnvironment().'/');
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
self::$m_bTraceSourceFiles = $bTraceSourceFiles;
|
||||
|
||||
self::LoadConfig($sConfigFile, $bAllowCache);
|
||||
|
||||
if ($bModelOnly) return;
|
||||
|
||||
CMDBSource::SelectDB(self::$m_sDBName);
|
||||
|
||||
foreach(get_declared_classes() as $sPHPClass)
|
||||
@@ -4313,9 +4140,9 @@ abstract class MetaModel
|
||||
}
|
||||
}
|
||||
|
||||
public static function LoadConfig($oConfiguration, $bAllowCache = false)
|
||||
public static function LoadConfig($sConfigFile, $bAllowCache = false)
|
||||
{
|
||||
self::$m_oConfig = $oConfiguration;
|
||||
self::$m_oConfig = new Config($sConfigFile);
|
||||
|
||||
// Set log ASAP
|
||||
if (self::$m_oConfig->GetLogGlobal())
|
||||
@@ -4373,14 +4200,14 @@ abstract class MetaModel
|
||||
|
||||
// Note: load the dictionary as soon as possible, because it might be
|
||||
// needed when some error occur
|
||||
$sAppIdentity = 'itop-'.MetaModel::GetEnvironmentId();
|
||||
$sAppIdentity = self::GetConfig()->Get('session_name');
|
||||
$bDictInitializedFromData = false;
|
||||
if (!self::$m_bUseAPCCache || !Dict::InCache($sAppIdentity))
|
||||
{
|
||||
$bDictInitializedFromData = true;
|
||||
foreach (self::$m_oConfig->GetDictionaries() as $sModule => $sToInclude)
|
||||
{
|
||||
self::IncludeModule('dictionaries', $sToInclude);
|
||||
self::IncludeModule($sConfigFile, 'dictionaries', $sToInclude);
|
||||
}
|
||||
}
|
||||
// Set the language... after the dictionaries have been loaded!
|
||||
@@ -4392,19 +4219,19 @@ abstract class MetaModel
|
||||
|
||||
foreach (self::$m_oConfig->GetAppModules() as $sModule => $sToInclude)
|
||||
{
|
||||
self::IncludeModule('application', $sToInclude);
|
||||
self::IncludeModule($sConfigFile, 'application', $sToInclude);
|
||||
}
|
||||
foreach (self::$m_oConfig->GetDataModels() as $sModule => $sToInclude)
|
||||
{
|
||||
self::IncludeModule('business', $sToInclude);
|
||||
self::IncludeModule($sConfigFile, 'business', $sToInclude);
|
||||
}
|
||||
foreach (self::$m_oConfig->GetWebServiceCategories() as $sModule => $sToInclude)
|
||||
{
|
||||
self::IncludeModule('webservice', $sToInclude);
|
||||
self::IncludeModule($sConfigFile, 'webservice', $sToInclude);
|
||||
}
|
||||
foreach (self::$m_oConfig->GetAddons() as $sModule => $sToInclude)
|
||||
{
|
||||
self::IncludeModule('addons', $sToInclude);
|
||||
self::IncludeModule($sConfigFile, 'addons', $sToInclude);
|
||||
}
|
||||
|
||||
$sServer = self::$m_oConfig->GetDBHost();
|
||||
@@ -4420,7 +4247,8 @@ abstract class MetaModel
|
||||
$oKPI = new ExecutionKPI();
|
||||
// Note: For versions of APC older than 3.0.17, fetch() accepts only one parameter
|
||||
//
|
||||
$sOqlAPCCacheId = 'itop-'.MetaModel::GetEnvironmentId().'-metamodel';
|
||||
$sAppIdentity = self::GetConfig()->Get('session_name');
|
||||
$sOqlAPCCacheId = $sAppIdentity.'-metamodel';
|
||||
$result = apc_fetch($sOqlAPCCacheId);
|
||||
|
||||
if (is_array($result))
|
||||
@@ -4508,14 +4336,9 @@ abstract class MetaModel
|
||||
return self::$m_oConfig;
|
||||
}
|
||||
|
||||
public static function GetEnvironmentId()
|
||||
{
|
||||
return md5(APPROOT).'-'.utils::GetCurrentEnvironment();
|
||||
}
|
||||
|
||||
protected static $m_aExtensionClasses = array();
|
||||
|
||||
protected static function IncludeModule($sModuleType, $sToInclude)
|
||||
protected static function IncludeModule($sConfigFile, $sModuleType, $sToInclude)
|
||||
{
|
||||
$sFirstChar = substr($sToInclude, 0, 1);
|
||||
$sSecondChar = substr($sToInclude, 1, 1);
|
||||
@@ -4540,7 +4363,6 @@ abstract class MetaModel
|
||||
}
|
||||
if (!file_exists($sFile))
|
||||
{
|
||||
$sConfigFile = self::$m_oConfig->GetLoadedFile();
|
||||
throw new CoreException('Wrong filename in configuration file', array('file' => $sConfigFile, 'module' => $sModuleType, 'filename' => $sFile));
|
||||
}
|
||||
require_once($sFile);
|
||||
@@ -4890,7 +4712,6 @@ abstract class MetaModel
|
||||
*/
|
||||
static public function ApplyParams($aInput, $aParams)
|
||||
{
|
||||
// Declare magic parameters
|
||||
$aParams['APP_URL'] = utils::GetAbsoluteUrlAppRoot();
|
||||
$aParams['MODULES_URL'] = utils::GetAbsoluteUrlModulesRoot();
|
||||
|
||||
@@ -4938,44 +4759,43 @@ abstract class MetaModel
|
||||
return $oInstance;
|
||||
}
|
||||
|
||||
public static function GetCacheEntries($sEnvironment = null)
|
||||
public static function GetCacheEntries(Config $oConfig = null)
|
||||
{
|
||||
if (!function_exists('apc_cache_info')) return array();
|
||||
if (is_null($sEnvironment))
|
||||
if (is_null($oConfig))
|
||||
{
|
||||
$sEnvironment = MetaModel::GetEnvironmentId();
|
||||
$oConfig = self::GetConfig();
|
||||
}
|
||||
$sAppIdentity = $oConfig->Get('session_name');
|
||||
|
||||
$aCacheUserData = apc_cache_info('user');
|
||||
$sPrefix = $sAppIdentity.'-';
|
||||
|
||||
$aEntries = array();
|
||||
$aCacheUserData = @apc_cache_info('user');
|
||||
if (is_array($aCacheUserData))
|
||||
{
|
||||
$sPrefix = 'itop-'.$sEnvironment.'-';
|
||||
|
||||
foreach($aCacheUserData['cache_list'] as $i => $aEntry)
|
||||
foreach($aCacheUserData['cache_list'] as $i => $aEntry)
|
||||
{
|
||||
$sEntryKey = $aEntry['info'];
|
||||
if (strpos($sEntryKey, $sPrefix) === 0)
|
||||
{
|
||||
$sEntryKey = $aEntry['info'];
|
||||
if (strpos($sEntryKey, $sPrefix) === 0)
|
||||
{
|
||||
$sCleanKey = substr($sEntryKey, strlen($sPrefix));
|
||||
$aEntries[$sCleanKey] = $aEntry;
|
||||
}
|
||||
$sCleanKey = substr($sEntryKey, strlen($sPrefix));
|
||||
$aEntries[$sCleanKey] = $aEntry;
|
||||
}
|
||||
}
|
||||
return $aEntries;
|
||||
}
|
||||
|
||||
public static function ResetCache($sEnvironment = null)
|
||||
public static function ResetCache(Config $oConfig = null)
|
||||
{
|
||||
if (!function_exists('apc_delete')) return;
|
||||
if (is_null($sEnvironment))
|
||||
if (is_null($oConfig))
|
||||
{
|
||||
$sEnvironment = MetaModel::GetEnvironmentId();
|
||||
$oConfig = self::GetConfig();
|
||||
}
|
||||
$sAppIdentity = $oConfig->Get('session_name');
|
||||
|
||||
$sAppIdentity = 'itop-'.$sEnvironment;
|
||||
Dict::ResetCache($sAppIdentity);
|
||||
|
||||
foreach(self::GetCacheEntries($sEnvironment) as $sKey => $aAPCInfo)
|
||||
foreach(self::GetCacheEntries($oConfig) as $sKey => $aAPCInfo)
|
||||
{
|
||||
$sAPCKey = $aAPCInfo['info'];
|
||||
apc_delete($sAPCKey);
|
||||
|
||||
@@ -50,13 +50,7 @@ class OQLException extends CoreException
|
||||
parent::__construct($sMessage, 0);
|
||||
}
|
||||
|
||||
public function GetUserFriendlyDescription()
|
||||
{
|
||||
// Todo - translate all errors!
|
||||
return $this->getMessage();
|
||||
}
|
||||
|
||||
public function getHtmlDesc($sHighlightHtmlBegin = '<span style="font-weight: bolder">', $sHighlightHtmlEnd = '</span>')
|
||||
public function getHtmlDesc($sHighlightHtmlBegin = '<b>', $sHighlightHtmlEnd = '</b>')
|
||||
{
|
||||
$sRet = htmlentities($this->m_MyIssue.", found '".$this->m_sUnexpected."' in: ", ENT_QUOTES, 'UTF-8');
|
||||
$sRet .= htmlentities(substr($this->m_sInput, 0, $this->m_iCol), ENT_QUOTES, 'UTF-8');
|
||||
@@ -77,27 +71,7 @@ class OQLException extends CoreException
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
public function GetIssue()
|
||||
{
|
||||
return $this->m_MyIssue;
|
||||
}
|
||||
|
||||
public function GetSuggestions()
|
||||
{
|
||||
return $this->m_aExpecting;
|
||||
}
|
||||
|
||||
public function GetWrongWord()
|
||||
{
|
||||
return $this->m_sUnexpected;
|
||||
}
|
||||
|
||||
public function GetColumn()
|
||||
{
|
||||
return $this->m_iCol;
|
||||
}
|
||||
|
||||
static public function FindClosestString($sInput, $aDictionary)
|
||||
static protected function FindClosestString($sInput, $aDictionary)
|
||||
{
|
||||
// no shortest distance found, yet
|
||||
$fShortest = -1;
|
||||
@@ -114,7 +88,7 @@ class OQLException extends CoreException
|
||||
return $sSuggestion;
|
||||
}
|
||||
|
||||
if (($fDist <= 3) && ($fShortest < 0 || $fDist <= $fShortest))
|
||||
if ($fShortest < 0 || ($fDist < 4 && $fDist <= $fShortest))
|
||||
{
|
||||
// set the closest match, and shortest distance
|
||||
$sRet = $sSuggestion;
|
||||
|
||||
@@ -31,28 +31,6 @@ class OqlNormalizeException extends OQLException
|
||||
parent::__construct($sIssue, $sInput, 0, $oName->GetPos(), $oName->GetValue(), $aExpecting);
|
||||
}
|
||||
}
|
||||
class UnknownClassOqlException extends OqlNormalizeException
|
||||
{
|
||||
public function __construct($sInput, OqlName $oName, $aExpecting = null)
|
||||
{
|
||||
parent::__construct('Unknown class', $sInput, $oName, $aExpecting);
|
||||
}
|
||||
|
||||
public function GetUserFriendlyDescription()
|
||||
{
|
||||
$sWrongClass = $this->GetWrongWord();
|
||||
$sSuggest = self::FindClosestString($sWrongClass, $this->GetSuggestions());
|
||||
|
||||
if ($sSuggest != '')
|
||||
{
|
||||
return Dict::Format('UI:OQL:UnknownClassAndFix', $sWrongClass, $sSuggest);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Dict::Format('UI:OQL:UnknownClassNoFix', $sWrongClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class OqlInterpreterException extends OQLException
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?php
|
||||
// Copyright (C) 2011-2012 Combodo SARL
|
||||
// Copyright (C) 2011 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
@@ -26,7 +26,6 @@ define('CASELOG_SEPARATOR', "\n".'========== %1$s : %2$s (%3$d) ============'."\
|
||||
class ormCaseLog {
|
||||
protected $m_sLog;
|
||||
protected $m_aIndex;
|
||||
protected $m_bModified;
|
||||
|
||||
/**
|
||||
* Initializes the log with the first (initial) entry
|
||||
@@ -37,7 +36,6 @@ class ormCaseLog {
|
||||
{
|
||||
$this->m_sLog = $sLog;
|
||||
$this->m_aIndex = $aIndex;
|
||||
$this->m_bModified = false;
|
||||
}
|
||||
|
||||
public function GetText()
|
||||
@@ -55,25 +53,13 @@ class ormCaseLog {
|
||||
return $this->m_sLog;
|
||||
}
|
||||
|
||||
public function ClearModifiedFlag()
|
||||
{
|
||||
$this->m_bModified = false;
|
||||
}
|
||||
|
||||
public function GetAsHTML(WebPage $oP = null, $bEditMode = false, $aTransfoHandler = null)
|
||||
{
|
||||
$sHtml = '<table style="width:100%;table-layout:fixed"><tr><td>'; // Use table-layout:fixed to force the with to be independent from the actual content
|
||||
$iPos = 0;
|
||||
$aIndex = $this->m_aIndex;
|
||||
if (($bEditMode) && (count($aIndex) > 0) && $this->m_bModified)
|
||||
for($index=count($this->m_aIndex)-1 ; $index >= 0 ; $index--)
|
||||
{
|
||||
// Don't display the first element, that is still considered as editable
|
||||
$iPos = $aIndex[0]['separator_length'] + $aIndex[0]['text_length'];
|
||||
array_shift($aIndex);
|
||||
}
|
||||
for($index=count($aIndex)-1 ; $index >= 0 ; $index--)
|
||||
{
|
||||
if ($index < count($aIndex) - CASELOG_VISIBLE_ITEMS)
|
||||
if ($index < count($this->m_aIndex) - CASELOG_VISIBLE_ITEMS)
|
||||
{
|
||||
$sOpen = '';
|
||||
$sDisplay = 'style="display:none;"';
|
||||
@@ -83,31 +69,31 @@ class ormCaseLog {
|
||||
$sOpen = ' open';
|
||||
$sDisplay = '';
|
||||
}
|
||||
$iPos += $aIndex[$index]['separator_length'];
|
||||
$sTextEntry = substr($this->m_sLog, $iPos, $aIndex[$index]['text_length']);
|
||||
$iPos += $this->m_aIndex[$index]['separator_length'];
|
||||
$sTextEntry = substr($this->m_sLog, $iPos, $this->m_aIndex[$index]['text_length']);
|
||||
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", htmlentities($sTextEntry, ENT_QUOTES, 'UTF-8'));
|
||||
if (!is_null($aTransfoHandler))
|
||||
{
|
||||
$sTextEntry = call_user_func($aTransfoHandler, $sTextEntry);
|
||||
}
|
||||
$iPos += $aIndex[$index]['text_length'];
|
||||
$iPos += $this->m_aIndex[$index]['text_length'];
|
||||
|
||||
$sEntry = '<div class="caselog_header'.$sOpen.'">';
|
||||
// Workaround: PHP < 5.3 cannot unserialize correctly DateTime objects,
|
||||
// therefore we have changed the format. To preserve the compatibility with existing
|
||||
// installations of iTop, both format are allowed:
|
||||
// the 'date' item is either a DateTime object, or a unix timestamp
|
||||
if (is_int($aIndex[$index]['date']))
|
||||
if (is_int($this->m_aIndex[$index]['date']))
|
||||
{
|
||||
// Unix timestamp
|
||||
$sDate = date(Dict::S('UI:CaseLog:DateFormat'),$aIndex[$index]['date']);
|
||||
$sDate = date(Dict::S('UI:CaseLog:DateFormat'), $this->m_aIndex[$index]['date']);
|
||||
}
|
||||
elseif (is_object($aIndex[$index]['date']))
|
||||
elseif (is_object($this->m_aIndex[$index]['date']))
|
||||
{
|
||||
if (version_compare(phpversion(), '5.3.0', '>='))
|
||||
{
|
||||
// DateTime
|
||||
$sDate = $aIndex[$index]['date']->format(Dict::S('UI:CaseLog:DateFormat'));
|
||||
$sDate = $this->m_aIndex[$index]['date']->format(Dict::S('UI:CaseLog:DateFormat'));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -115,7 +101,7 @@ class ormCaseLog {
|
||||
$sDate = '';
|
||||
}
|
||||
}
|
||||
$sEntry .= sprintf(Dict::S('UI:CaseLog:Header_Date_UserName'), $sDate, $aIndex[$index]['user_name']);
|
||||
$sEntry .= sprintf(Dict::S('UI:CaseLog:Header_Date_UserName'), $sDate, $this->m_aIndex[$index]['user_name']);
|
||||
$sEntry .= '</div>';
|
||||
$sEntry .= '<div class="caselog_entry"'.$sDisplay.'>';
|
||||
$sEntry .= $sTextEntry;
|
||||
@@ -164,13 +150,11 @@ class ormCaseLog {
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new entry to the log or merge the given text into the currently modified entry
|
||||
* and updates the internal index
|
||||
* Add a new entry to the log and updates the internal index
|
||||
* @param $sText string The text of the new entry
|
||||
*/
|
||||
public function AddLogEntry($sText, $sOnBehalfOf = '')
|
||||
{
|
||||
$bMergeEntries = false;
|
||||
$sDate = date(Dict::S('UI:CaseLog:DateFormat'));
|
||||
if ($sOnBehalfOf == '')
|
||||
{
|
||||
@@ -181,61 +165,17 @@ class ormCaseLog {
|
||||
{
|
||||
$iUserId = null;
|
||||
}
|
||||
if ($this->m_bModified)
|
||||
{
|
||||
$aLatestEntry = end($this->m_aIndex);
|
||||
if ($aLatestEntry['user_name'] != $sOnBehalfOf)
|
||||
{
|
||||
$bMergeEntries = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
$bMergeEntries = true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($bMergeEntries)
|
||||
{
|
||||
$aLatestEntry = end($this->m_aIndex);
|
||||
$this->m_sLog = substr($this->m_sLog, $aLatestEntry['separator_length']);
|
||||
$sSeparator = sprintf(CASELOG_SEPARATOR, $sDate, $sOnBehalfOf, $iUserId);
|
||||
$iSepLength = strlen($sSeparator);
|
||||
$iTextlength = strlen($sText."\n");
|
||||
$this->m_sLog = $sSeparator.$sText.$this->m_sLog; // Latest entry printed first
|
||||
$this->m_aIndex[] = array(
|
||||
'user_name' => $sOnBehalfOf,
|
||||
'user_id' => $iUserId,
|
||||
'date' => time(),
|
||||
'text_length' => $aLatestEntry['text_length'] + $iTextlength,
|
||||
'separator_length' => $iSepLength,
|
||||
);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
$sSeparator = sprintf(CASELOG_SEPARATOR, $sDate, $sOnBehalfOf, $iUserId);
|
||||
$iSepLength = strlen($sSeparator);
|
||||
$iTextlength = strlen($sText);
|
||||
$this->m_sLog = $sSeparator.$sText.$this->m_sLog; // Latest entry printed first
|
||||
$this->m_aIndex[] = array(
|
||||
'user_name' => $sOnBehalfOf,
|
||||
'user_id' => $iUserId,
|
||||
'date' => time(),
|
||||
'text_length' => $iTextlength,
|
||||
'separator_length' => $iSepLength,
|
||||
);
|
||||
}
|
||||
$this->m_bModified = true;
|
||||
}
|
||||
|
||||
public function GetModifiedEntry()
|
||||
{
|
||||
$sModifiedEntry = '';
|
||||
if ($this->m_bModified)
|
||||
{
|
||||
$sModifiedEntry = $this->GetLatestEntry();
|
||||
}
|
||||
return $sModifiedEntry;
|
||||
$sSeparator = sprintf(CASELOG_SEPARATOR, $sDate, $sOnBehalfOf, $iUserId);
|
||||
$iSepLength = strlen($sSeparator);
|
||||
$iTextlength = strlen($sText);
|
||||
$this->m_sLog = $sSeparator.$sText.$this->m_sLog; // Latest entry printed first
|
||||
$this->m_aIndex[] = array(
|
||||
'user_name' => $sOnBehalfOf,
|
||||
'user_id' => $iUserId,
|
||||
'date' => time(),
|
||||
'text_length' => $iTextlength,
|
||||
'separator_length' => $iSepLength,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -260,4 +200,4 @@ class ormCaseLog {
|
||||
return $iLast;
|
||||
}
|
||||
}
|
||||
?>
|
||||
?>
|
||||
|
||||
@@ -1,465 +0,0 @@
|
||||
<?php
|
||||
// Copyright (C) 2010-2012 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
require_once('backgroundprocess.inc.php');
|
||||
|
||||
/**
|
||||
* ormStopWatch
|
||||
* encapsulate the behavior of a stop watch that will be stored as an attribute of class AttributeStopWatch
|
||||
*
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* ormStopWatch
|
||||
* encapsulate the behavior of a stop watch that will be stored as an attribute of class AttributeStopWatch
|
||||
*
|
||||
* @package itopORM
|
||||
*/
|
||||
class ormStopWatch
|
||||
{
|
||||
protected $iTimeSpent; // seconds
|
||||
protected $iStarted; // unix time (seconds)
|
||||
protected $iLastStart; // unix time (seconds)
|
||||
protected $iStopped; // unix time (seconds)
|
||||
protected $aThresholds;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct($iTimeSpent = 0, $iStarted = null, $iLastStart = null, $iStopped = null)
|
||||
{
|
||||
$this->iTimeSpent = (int) $iTimeSpent;
|
||||
$this->iStarted = $iStarted;
|
||||
$this->iLastStart = $iLastStart;
|
||||
$this->iStopped = $iStopped;
|
||||
|
||||
$this->aThresholds = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Necessary for the triggers
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
return (string) $this->iTimeSpent;
|
||||
}
|
||||
|
||||
public function DefineThreshold($iPercent, $tDeadline = null, $bPassed = false, $bTriggered = false, $iOverrun = null)
|
||||
{
|
||||
$this->aThresholds[$iPercent] = array(
|
||||
'deadline' => $tDeadline, // unix time (seconds)
|
||||
'passed' => $bPassed,
|
||||
'triggered' => $bTriggered,
|
||||
'overrun' => $iOverrun
|
||||
);
|
||||
}
|
||||
|
||||
public function MarkThresholdAsTriggered($iPercent)
|
||||
{
|
||||
$this->aThresholds[$iPercent]['triggered'] = true;
|
||||
}
|
||||
|
||||
public function GetTimeSpent()
|
||||
{
|
||||
return $this->iTimeSpent;
|
||||
}
|
||||
|
||||
public function GetStartDate()
|
||||
{
|
||||
return $this->iStarted;
|
||||
}
|
||||
|
||||
public function GetLastStartDate()
|
||||
{
|
||||
return $this->iLastStart;
|
||||
}
|
||||
|
||||
public function GetStopDate()
|
||||
{
|
||||
return $this->iStopped;
|
||||
}
|
||||
|
||||
public function GetThresholdDate($iPercent)
|
||||
{
|
||||
if (array_key_exists($iPercent, $this->aThresholds))
|
||||
{
|
||||
return $this->aThresholds[$iPercent]['deadline'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public function GetOverrun($iPercent)
|
||||
{
|
||||
if (array_key_exists($iPercent, $this->aThresholds))
|
||||
{
|
||||
return $this->aThresholds[$iPercent]['overrun'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public function IsThresholdPassed($iPercent)
|
||||
{
|
||||
if (array_key_exists($iPercent, $this->aThresholds))
|
||||
{
|
||||
return $this->aThresholds[$iPercent]['passed'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public function IsThresholdTriggered($iPercent)
|
||||
{
|
||||
if (array_key_exists($iPercent, $this->aThresholds))
|
||||
{
|
||||
return $this->aThresholds[$iPercent]['triggered'];
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function GetAsHTML($oAttDef, $oHostObject = null)
|
||||
{
|
||||
$aProperties = array();
|
||||
|
||||
$aProperties['States'] = implode(', ', $oAttDef->GetStates());
|
||||
|
||||
if (is_null($this->iLastStart))
|
||||
{
|
||||
if (is_null($this->iStarted))
|
||||
{
|
||||
$aProperties['Elapsed'] = 'never started';
|
||||
}
|
||||
else
|
||||
{
|
||||
$aProperties['Elapsed'] = $this->iTimeSpent.' s';
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$iElapsedTemp = ''; //$this->ComputeDuration($oHostObject, $oAttDef, $this->iLastStart, time());
|
||||
$aProperties['Elapsed'] = $this->iTimeSpent.' + '.$iElapsedTemp.' s + <img src="../images/indicator.gif">';
|
||||
}
|
||||
|
||||
$aProperties['Started'] = $oAttDef->SecondsToDate($this->iStarted);
|
||||
$aProperties['LastStart'] = $oAttDef->SecondsToDate($this->iLastStart);
|
||||
$aProperties['Stopped'] = $oAttDef->SecondsToDate($this->iStopped);
|
||||
|
||||
foreach ($this->aThresholds as $iPercent => $aThresholdData)
|
||||
{
|
||||
$sThresholdDesc = $oAttDef->SecondsToDate($aThresholdData['deadline']);
|
||||
if ($aThresholdData['triggered'])
|
||||
{
|
||||
$sThresholdDesc .= " <b>TRIGGERED</b>";
|
||||
}
|
||||
if ($aThresholdData['overrun'])
|
||||
{
|
||||
$sThresholdDesc .= " Overrun:".(int) $aThresholdData['overrun']." sec.";
|
||||
}
|
||||
$aProperties[$iPercent.'%'] = $sThresholdDesc;
|
||||
}
|
||||
$sRes = "<TABLE class=\"listResults\">";
|
||||
$sRes .= "<TBODY>";
|
||||
foreach ($aProperties as $sProperty => $sValue)
|
||||
{
|
||||
$sRes .= "<TR>";
|
||||
$sCell = str_replace("\n", "<br>\n", $sValue);
|
||||
$sRes .= "<TD class=\"label\">$sProperty</TD><TD>$sCell</TD>";
|
||||
$sRes .= "</TR>";
|
||||
}
|
||||
$sRes .= "</TBODY>";
|
||||
$sRes .= "</TABLE>";
|
||||
return $sRes;
|
||||
}
|
||||
|
||||
protected function ComputeGoal($oObject, $oAttDef)
|
||||
{
|
||||
$sMetricComputer = $oAttDef->Get('goal_computing');
|
||||
$oComputer = new $sMetricComputer();
|
||||
$aCallSpec = array($oComputer, 'ComputeMetric');
|
||||
if (!is_callable($aCallSpec))
|
||||
{
|
||||
throw new CoreException("Unknown class/verb '$sMetricComputer/ComputeMetric'");
|
||||
}
|
||||
$iRet = call_user_func($aCallSpec, $oObject);
|
||||
return $iRet;
|
||||
}
|
||||
|
||||
protected function ComputeDeadline($oObject, $oAttDef, $iStartTime, $iDurationSec)
|
||||
{
|
||||
$sWorkingTimeComputer = $oAttDef->Get('working_time_computing');
|
||||
$aCallSpec = array($sWorkingTimeComputer, '__construct');
|
||||
if (!is_callable($aCallSpec))
|
||||
{
|
||||
//throw new CoreException("Pas de constructeur pour $sWorkingTimeComputer!");
|
||||
}
|
||||
$oComputer = new $sWorkingTimeComputer();
|
||||
$aCallSpec = array($oComputer, 'GetDeadline');
|
||||
if (!is_callable($aCallSpec))
|
||||
{
|
||||
throw new CoreException("Unknown class/verb '$sWorkingTimeComputer/GetDeadline'");
|
||||
}
|
||||
// GetDeadline($oObject, $iDuration, DateTime $oStartDate)
|
||||
$oStartDate = new DateTime('@'.$iStartTime); // setTimestamp not available in PHP 5.2
|
||||
$oDeadline = call_user_func($aCallSpec, $oObject, $iDurationSec, $oStartDate);
|
||||
$iRet = $oDeadline->format('U');
|
||||
return $iRet;
|
||||
}
|
||||
|
||||
protected function ComputeDuration($oObject, $oAttDef, $iStartTime, $iEndTime)
|
||||
{
|
||||
$sWorkingTimeComputer = $oAttDef->Get('working_time_computing');
|
||||
$oComputer = new $sWorkingTimeComputer();
|
||||
$aCallSpec = array($oComputer, 'GetOpenDuration');
|
||||
if (!is_callable($aCallSpec))
|
||||
{
|
||||
throw new CoreException("Unknown class/verb '$sWorkingTimeComputer/GetOpenDuration'");
|
||||
}
|
||||
// GetOpenDuration($oObject, DateTime $oStartDate, DateTime $oEndDate)
|
||||
$oStartDate = new DateTime('@'.$iStartTime); // setTimestamp not available in PHP 5.2
|
||||
$oEndDate = new DateTime('@'.$iEndTime);
|
||||
$iRet = call_user_func($aCallSpec, $oObject, $oStartDate, $oEndDate);
|
||||
return $iRet;
|
||||
}
|
||||
|
||||
public function Reset($oObject, $oAttDef)
|
||||
{
|
||||
$this->iTimeSpent = 0;
|
||||
$this->iStarted = null;
|
||||
$this->iLastStart = null;
|
||||
$this->iStopped = null;
|
||||
|
||||
foreach ($this->aThresholds as $iPercent => &$aThresholdData)
|
||||
{
|
||||
$aThresholdData['passed'] = false;
|
||||
$aThresholdData['triggered'] = false;
|
||||
$aThresholdData['deadline'] = null;
|
||||
$aThresholdData['overrun'] = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Start or continue
|
||||
* It is the responsibility of the caller to compute the deadlines
|
||||
* (to avoid computing twice for the same result)
|
||||
*/
|
||||
public function Start($oObject, $oAttDef)
|
||||
{
|
||||
if (!is_null($this->iLastStart))
|
||||
{
|
||||
// Already started
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_null($this->iStarted))
|
||||
{
|
||||
$this->iStarted = time();
|
||||
}
|
||||
$this->iLastStart = time();
|
||||
$this->iStopped = null;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute or recompute the goal and threshold deadlines
|
||||
*/
|
||||
public function ComputeDeadlines($oObject, $oAttDef)
|
||||
{
|
||||
if (is_null($this->iLastStart))
|
||||
{
|
||||
// Currently stopped - do nothing
|
||||
return false;
|
||||
}
|
||||
|
||||
$iDurationGoal = $this->ComputeGoal($oObject, $oAttDef);
|
||||
foreach ($this->aThresholds as $iPercent => &$aThresholdData)
|
||||
{
|
||||
if (is_null($iDurationGoal))
|
||||
{
|
||||
// No limit: leave null thresholds
|
||||
$aThresholdData['deadline'] = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
$iThresholdDuration = round($iPercent * $iDurationGoal / 100);
|
||||
$aThresholdData['deadline'] = $this->ComputeDeadline($oObject, $oAttDef, $this->iLastStart, $iThresholdDuration - $this->iTimeSpent);
|
||||
// OR $aThresholdData['deadline'] = $this->ComputeDeadline($oObject, $oAttDef, $this->iStarted, $iThresholdDuration);
|
||||
|
||||
}
|
||||
if (is_null($aThresholdData['deadline']) || ($aThresholdData['deadline'] > time()))
|
||||
{
|
||||
// The threshold is in the future, reset
|
||||
$aThresholdData['passed'] = false;
|
||||
$aThresholdData['triggered'] = false;
|
||||
$aThresholdData['overrun'] = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
// The new threshold is in the past
|
||||
$aThresholdData['passed'] = true;
|
||||
// Note: the overrun can be wrong, but the correct algorithm to compute
|
||||
// the overrun of a deadline in the past requires that the ormStopWatch keeps track of all its history!!!
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop counting if not already done
|
||||
*/
|
||||
public function Stop($oObject, $oAttDef)
|
||||
{
|
||||
if (is_null($this->iLastStart))
|
||||
{
|
||||
// Already stopped
|
||||
return false;
|
||||
}
|
||||
|
||||
$iElapsed = $this->ComputeDuration($oObject, $oAttDef, $this->iLastStart, time());
|
||||
$this->iTimeSpent = $this->iTimeSpent + $iElapsed;
|
||||
|
||||
foreach ($this->aThresholds as $iPercent => &$aThresholdData)
|
||||
{
|
||||
if (!is_null($aThresholdData['deadline']) && (time() > $aThresholdData['deadline']))
|
||||
{
|
||||
if ($aThresholdData['overrun'] > 0)
|
||||
{
|
||||
// Accumulate from last start
|
||||
$aThresholdData['overrun'] += $iElapsed;
|
||||
}
|
||||
else
|
||||
{
|
||||
// First stop after the deadline has been passed
|
||||
$iOverrun = $this->ComputeDuration($oObject, $oAttDef, $aThresholdData['deadline'], time());
|
||||
$aThresholdData['overrun'] = $iOverrun;
|
||||
}
|
||||
$aThresholdData['passed'] = true;
|
||||
}
|
||||
$aThresholdData['deadline'] = null;
|
||||
}
|
||||
|
||||
$this->iLastStart = null;
|
||||
$this->iStopped = time();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* CheckStopWatchThresholds
|
||||
* Implements the automatic actions
|
||||
*
|
||||
* @package itopORM
|
||||
*/
|
||||
class CheckStopWatchThresholds implements iBackgroundProcess
|
||||
{
|
||||
public function GetPeriodicity()
|
||||
{
|
||||
return 10; // seconds
|
||||
}
|
||||
|
||||
public function Process($iTimeLimit)
|
||||
{
|
||||
foreach (MetaModel::GetClasses() as $sClass)
|
||||
{
|
||||
foreach (MetaModel::ListAttributeDefs($sClass) as $sAttCode => $oAttDef)
|
||||
{
|
||||
if ($oAttDef instanceof AttributeStopWatch)
|
||||
{
|
||||
foreach ($oAttDef->ListThresholds() as $iThreshold => $aThresholdData)
|
||||
{
|
||||
$iPercent = $aThresholdData['percent']; // could be different than the index !
|
||||
|
||||
$sExpression = "SELECT $sClass WHERE {$sAttCode}_laststart AND {$sAttCode}_{$iThreshold}_triggered = 0 AND {$sAttCode}_{$iThreshold}_deadline < NOW()";
|
||||
//echo $sExpression."<br/>\n";
|
||||
$oFilter = DBObjectSearch::FromOQL($sExpression);
|
||||
$aList = array();
|
||||
$oSet = new DBObjectSet($oFilter);
|
||||
while ((time() < $iTimeLimit) && ($oObj = $oSet->Fetch()))
|
||||
{
|
||||
$sClass = get_class($oObj);
|
||||
|
||||
$aList[] = $sClass.'::'.$oObj->GetKey().' '.$sAttCode.' '.$iThreshold;
|
||||
//echo $sClass.'::'.$oObj->GetKey().' '.$sAttCode.' '.$iThreshold."\n";
|
||||
|
||||
// Execute planned actions
|
||||
//
|
||||
foreach ($aThresholdData['actions'] as $aActionData)
|
||||
{
|
||||
$sVerb = $aActionData['verb'];
|
||||
$aParams = $aActionData['params'];
|
||||
$sParams = implode(', ', $aParams);
|
||||
//echo "Calling: $sVerb($sParams)<br/>\n";
|
||||
$aCallSpec = array($oObj, $sVerb);
|
||||
call_user_func_array($aCallSpec, $aParams);
|
||||
}
|
||||
|
||||
// Mark the threshold as "triggered"
|
||||
//
|
||||
$oSW = $oObj->Get($sAttCode);
|
||||
$oSW->MarkThresholdAsTriggered($iThreshold);
|
||||
$oObj->Set($sAttCode, $oSW);
|
||||
|
||||
if($oObj->IsModified())
|
||||
{
|
||||
// Todo - factorize so that only one single change will be instantiated
|
||||
$oMyChange = new CMDBChange();
|
||||
$oMyChange->Set("date", time());
|
||||
$oMyChange->Set("userinfo", "Automatic - threshold triggered");
|
||||
$iChangeId = $oMyChange->DBInsertNoReload();
|
||||
|
||||
$oObj->DBUpdateTracked($oMyChange, true /*skip security*/);
|
||||
}
|
||||
|
||||
// Activate any existing trigger
|
||||
//
|
||||
$sClassList = implode("', '", MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL));
|
||||
$oSet = new DBObjectSet(
|
||||
DBObjectSearch::FromOQL("SELECT TriggerOnThresholdReached AS t WHERE t.target_class IN ('$sClassList') AND stop_watch_code=:stop_watch_code AND threshold_index = :threshold_index"),
|
||||
array(), // order by
|
||||
array('stop_watch_code' => $sAttCode, 'threshold_index' => $iThreshold)
|
||||
);
|
||||
while ($oTrigger = $oSet->Fetch())
|
||||
{
|
||||
$oTrigger->DoActivate($oObj->ToArgs('this'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$iProcessed = count($aList);
|
||||
return "Triggered $iProcessed threshold(s)";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
?>
|
||||
@@ -32,10 +32,10 @@ class QueryBuilderContext
|
||||
|
||||
public $m_oQBExpressions;
|
||||
|
||||
public function __construct($oFilter, $aModifierProperties, $aGroupByExpr = null)
|
||||
public function __construct($oFilter, $aModifierProperties)
|
||||
{
|
||||
$this->m_oRootFilter = $oFilter;
|
||||
$this->m_oQBExpressions = new QueryBuilderExpressions($oFilter->GetCriteria(), $aGroupByExpr);
|
||||
$this->m_oQBExpressions = new QueryBuilderExpressions($oFilter->GetCriteria());
|
||||
|
||||
$this->m_aClassAliases = $oFilter->GetJoinedClasses();
|
||||
$this->m_aTableAliases = array();
|
||||
|
||||
@@ -41,7 +41,6 @@ class SQLQuery
|
||||
private $m_sTable = '';
|
||||
private $m_sTableAlias = '';
|
||||
private $m_aFields = array();
|
||||
private $m_aGroupBy = array();
|
||||
private $m_oConditionExpr = null;
|
||||
private $m_bToDelete = true; // The current table must be listed for deletion ?
|
||||
private $m_aValues = array(); // Values to set in case of an update query
|
||||
@@ -63,7 +62,6 @@ class SQLQuery
|
||||
$this->m_sTable = $sTable;
|
||||
$this->m_sTableAlias = $sTableAlias;
|
||||
$this->m_aFields = $aFields;
|
||||
$this->m_aGroupBy = null;
|
||||
$this->m_oConditionExpr = null;
|
||||
$this->m_bToDelete = $bToDelete;
|
||||
$this->m_aValues = $aValues;
|
||||
@@ -127,12 +125,11 @@ class SQLQuery
|
||||
}
|
||||
$aFrom = array();
|
||||
$aFields = array();
|
||||
$aGroupBy = array();
|
||||
$oCondition = null;
|
||||
$aDelTables = array();
|
||||
$aSetValues = array();
|
||||
$aSelectedIdFields = array();
|
||||
$this->privRender($aFrom, $aFields, $aGroupBy, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
|
||||
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
|
||||
echo "From ...<br/>\n";
|
||||
echo "<pre style=\"font-size: smaller;\">\n";
|
||||
print_r($aFrom);
|
||||
@@ -144,11 +141,6 @@ class SQLQuery
|
||||
$this->m_aFields = $aExpressions;
|
||||
}
|
||||
|
||||
public function SetGroupBy($aExpressions)
|
||||
{
|
||||
$this->m_aGroupBy = $aExpressions;
|
||||
}
|
||||
|
||||
public function SetCondition($oConditionExpr)
|
||||
{
|
||||
$this->m_oConditionExpr = $oConditionExpr;
|
||||
@@ -243,12 +235,11 @@ class SQLQuery
|
||||
// The goal will be to complete the list as we build the Joins
|
||||
$aFrom = array();
|
||||
$aFields = array();
|
||||
$aGroupBy = array();
|
||||
$oCondition = null;
|
||||
$aDelTables = array();
|
||||
$aSetValues = array();
|
||||
$aSelectedIdFields = array();
|
||||
$this->privRender($aFrom, $aFields, $aGroupBy, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
|
||||
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
|
||||
|
||||
// Target: DELETE myAlias1, myAlias2 FROM t1 as myAlias1, t2 as myAlias2, t3 as topreserve WHERE ...
|
||||
|
||||
@@ -279,12 +270,11 @@ class SQLQuery
|
||||
// The goal will be to complete the list as we build the Joins
|
||||
$aFrom = array();
|
||||
$aFields = array();
|
||||
$aGroupBy = array();
|
||||
$oCondition = null;
|
||||
$aDelTables = array();
|
||||
$aSetValues = array();
|
||||
$aSelectedIdFields = array();
|
||||
$this->privRender($aFrom, $aFields, $aGroupBy, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
|
||||
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
|
||||
$sFrom = self::ClauseFrom($aFrom);
|
||||
$sValues = self::ClauseValues($aSetValues);
|
||||
$sWhere = self::ClauseWhere($oCondition, $aArgs);
|
||||
@@ -297,12 +287,11 @@ class SQLQuery
|
||||
// The goal will be to complete the lists as we build the Joins
|
||||
$aFrom = array();
|
||||
$aFields = array();
|
||||
$aGroupBy = array();
|
||||
$oCondition = null;
|
||||
$aDelTables = array();
|
||||
$aSetValues = array();
|
||||
$aSelectedIdFields = array();
|
||||
$this->privRender($aFrom, $aFields, $aGroupBy, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
|
||||
$this->privRender($aFrom, $aFields, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
|
||||
|
||||
$sFrom = self::ClauseFrom($aFrom);
|
||||
$sWhere = self::ClauseWhere($oCondition, $aArgs);
|
||||
@@ -339,27 +328,6 @@ class SQLQuery
|
||||
return $sSQL;
|
||||
}
|
||||
|
||||
// Interface, build the SQL query
|
||||
public function RenderGroupBy($aArgs = array())
|
||||
{
|
||||
// The goal will be to complete the lists as we build the Joins
|
||||
$aFrom = array();
|
||||
$aFields = array();
|
||||
$aGroupBy = array();
|
||||
$oCondition = null;
|
||||
$aDelTables = array();
|
||||
$aSetValues = array();
|
||||
$aSelectedIdFields = array();
|
||||
$this->privRender($aFrom, $aFields, $aGroupBy, $oCondition, $aDelTables, $aSetValues, $aSelectedIdFields);
|
||||
|
||||
$sSelect = self::ClauseSelect($aFields);
|
||||
$sFrom = self::ClauseFrom($aFrom);
|
||||
$sWhere = self::ClauseWhere($oCondition, $aArgs);
|
||||
$sGroupBy = self::ClauseGroupBy($aGroupBy);
|
||||
$sSQL = "SELECT $sSelect, COUNT(*) AS _itop_count_ FROM $sFrom WHERE $sWhere GROUP BY $sGroupBy";
|
||||
return $sSQL;
|
||||
}
|
||||
|
||||
private static function ClauseSelect($aFields)
|
||||
{
|
||||
$aSelect = array();
|
||||
@@ -371,12 +339,6 @@ class SQLQuery
|
||||
return $sSelect;
|
||||
}
|
||||
|
||||
private static function ClauseGroupBy($aGroupBy)
|
||||
{
|
||||
$sRes = implode(', ', $aGroupBy);
|
||||
return $sRes;
|
||||
}
|
||||
|
||||
private static function ClauseDelete($aDelTableAliases)
|
||||
{
|
||||
$aDelTables = array();
|
||||
@@ -445,22 +407,21 @@ class SQLQuery
|
||||
$aOrderBySpec = array();
|
||||
foreach($aOrderBy as $sFieldAlias => $bAscending)
|
||||
{
|
||||
// Note: sFieldAlias must have backticks around column aliases
|
||||
$aOrderBySpec[] = $sFieldAlias.($bAscending ? " ASC" : " DESC");
|
||||
$aOrderBySpec[] = '`'.$sFieldAlias.'`'.($bAscending ? " ASC" : " DESC");
|
||||
}
|
||||
$sOrderBy = implode(", ", $aOrderBySpec);
|
||||
return $sOrderBy;
|
||||
}
|
||||
|
||||
// Purpose: prepare the query data, once for all
|
||||
private function privRender(&$aFrom, &$aFields, &$aGroupBy, &$oCondition, &$aDelTables, &$aSetValues, &$aSelectedIdFields)
|
||||
private function privRender(&$aFrom, &$aFields, &$oCondition, &$aDelTables, &$aSetValues, &$aSelectedIdFields)
|
||||
{
|
||||
$sTableAlias = $this->privRenderSingleTable($aFrom, $aFields, $aGroupBy, $aDelTables, $aSetValues, $aSelectedIdFields, '', array('jointype' => 'first'));
|
||||
$sTableAlias = $this->privRenderSingleTable($aFrom, $aFields, $aDelTables, $aSetValues, $aSelectedIdFields, '', array('jointype' => 'first'));
|
||||
$oCondition = $this->m_oConditionExpr;
|
||||
return $sTableAlias;
|
||||
}
|
||||
|
||||
private function privRenderSingleTable(&$aFrom, &$aFields, &$aGroupBy, &$aDelTables, &$aSetValues, &$aSelectedIdFields, $sCallerAlias = '', $aJoinData)
|
||||
private function privRenderSingleTable(&$aFrom, &$aFields, &$aDelTables, &$aSetValues, &$aSelectedIdFields, $sCallerAlias = '', $aJoinData)
|
||||
{
|
||||
$aActualTableFields = CMDBSource::GetTableFieldsList($this->m_sTable);
|
||||
|
||||
@@ -544,13 +505,6 @@ class SQLQuery
|
||||
{
|
||||
$aFields["`$sAlias`"] = $oExpression->Render();
|
||||
}
|
||||
if ($this->m_aGroupBy)
|
||||
{
|
||||
foreach($this->m_aGroupBy as $sAlias => $oExpression)
|
||||
{
|
||||
$aGroupBy["`$sAlias`"] = $oExpression->Render();
|
||||
}
|
||||
}
|
||||
if ($this->m_bToDelete)
|
||||
{
|
||||
$aDelTables[] = "`{$this->m_sTableAlias}`";
|
||||
@@ -573,7 +527,7 @@ class SQLQuery
|
||||
{
|
||||
$oRightSelect = $aJoinData["select"];
|
||||
|
||||
$sJoinTableAlias = $oRightSelect->privRenderSingleTable($aTempFrom, $aFields, $aGroupBy, $aDelTables, $aSetValues, $aSelectedIdFields, $this->m_sTableAlias, $aJoinData);
|
||||
$sJoinTableAlias = $oRightSelect->privRenderSingleTable($aTempFrom, $aFields, $aDelTables, $aSetValues, $aSelectedIdFields, $this->m_sTableAlias, $aJoinData);
|
||||
}
|
||||
$aFrom[$this->m_sTableAlias]['subfrom'] = $aTempFrom;
|
||||
|
||||
|
||||
@@ -278,35 +278,4 @@ class lnkTriggerAction extends cmdbAbstractObject
|
||||
MetaModel::Init_SetZListItems('advanced_search', array('action_id', 'trigger_id', 'order')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
|
||||
class TriggerOnThresholdReached extends TriggerOnObject
|
||||
{
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb,bizmodel",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "description",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('description'),
|
||||
"db_table" => "priv_trigger_threshold",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
"display_template" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeString("stop_watch_code", array("allowed_values"=>null, "sql"=>"stop_watch_code", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("threshold_index", array("allowed_values"=>null, "sql"=>"threshold_index", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'target_class', 'stop_watch_code', 'threshold_index', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('target_class', 'threshold_index', 'threshold_index')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
|
||||
// MetaModel::Init_SetZListItems('advanced_search', array('name')); // Criteria of the advanced search form
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -41,8 +41,6 @@ define('UR_ACTION_BULK_READ', 4); // Export multiple objects
|
||||
define('UR_ACTION_BULK_MODIFY', 5); // Create/modify multiple objects
|
||||
define('UR_ACTION_BULK_DELETE', 6); // Delete multiple objects
|
||||
|
||||
define('UR_ACTION_CREATE', 7); // Instantiate an object
|
||||
|
||||
define('UR_ACTION_APPLICATION_DEFINED', 10000); // Application specific actions (CSV import, View schema...)
|
||||
|
||||
/**
|
||||
@@ -673,21 +671,9 @@ class UserRights
|
||||
|
||||
if (MetaModel::DBIsReadOnly())
|
||||
{
|
||||
if ($iActionCode == UR_ACTION_CREATE) return false;
|
||||
if ($iActionCode == UR_ACTION_MODIFY) return false;
|
||||
if ($iActionCode == UR_ACTION_DELETE) return false;
|
||||
if ($iActionCode == UR_ACTION_BULK_MODIFY) return false;
|
||||
if ($iActionCode == UR_ACTION_DELETE) return false;
|
||||
if ($iActionCode == UR_ACTION_BULK_DELETE) return false;
|
||||
}
|
||||
|
||||
$aPredefinedObjects = call_user_func(array($sClass, 'GetPredefinedObjects'));
|
||||
if ($aPredefinedObjects != null)
|
||||
{
|
||||
// As opposed to the read-only DB, modifying an object is allowed
|
||||
// (the constant columns will be marked as read-only)
|
||||
//
|
||||
if ($iActionCode == UR_ACTION_CREATE) return false;
|
||||
if ($iActionCode == UR_ACTION_DELETE) return false;
|
||||
if ($iActionCode == UR_ACTION_BULK_DELETE) return false;
|
||||
}
|
||||
|
||||
@@ -699,12 +685,6 @@ class UserRights
|
||||
{
|
||||
$oUser = self::$m_oUser;
|
||||
}
|
||||
if ($iActionCode == UR_ACTION_CREATE)
|
||||
{
|
||||
// The addons currently DO NOT handle the case "CREATE"
|
||||
// Therefore it is considered to be equivalent to "MODIFY"
|
||||
$iActionCode = UR_ACTION_MODIFY;
|
||||
}
|
||||
return self::$m_oAddOn->IsActionAllowed($oUser, $sClass, $iActionCode, $oInstanceSet);
|
||||
}
|
||||
elseif(($iActionCode == UR_ACTION_READ) && MetaModel::HasCategory($sClass, 'view_in_gui'))
|
||||
|
||||
115
css/fg.menu.css
115
css/fg.menu.css
@@ -1,115 +0,0 @@
|
||||
/* Styles for jQuery menu widget
|
||||
Author: Maggie Wachs, maggie@filamentgroup.com
|
||||
Date: September 2008
|
||||
*/
|
||||
|
||||
|
||||
/* REQUIRED STYLES - the menus will only render correctly with these rules */
|
||||
|
||||
.positionHelper { z-index: 2999; }
|
||||
.fg-menu-container { position: absolute; top:0; left:-999px; padding: .4em; overflow: hidden; }
|
||||
.fg-menu-container.fg-menu-flyout { overflow: visible; }
|
||||
|
||||
.fg-menu, .fg-menu ul { list-style-type:none; padding: 0; margin:0; }
|
||||
|
||||
.fg-menu { position:relative; }
|
||||
.fg-menu-flyout .fg-menu { position:static; }
|
||||
|
||||
.fg-menu ul { position:absolute; top:0; }
|
||||
.fg-menu ul ul { top:-1px; }
|
||||
|
||||
.fg-menu-container.fg-menu-ipod .fg-menu-content,
|
||||
.fg-menu-container.fg-menu-ipod .fg-menu-content ul { background: none !important; }
|
||||
|
||||
.fg-menu.fg-menu-scroll,
|
||||
.fg-menu ul.fg-menu-scroll { overflow: scroll; overflow-x: hidden; }
|
||||
|
||||
.fg-menu li { clear:both; float:left; width:100%; margin: 0; padding:0; border: 0; }
|
||||
.fg-menu li li { font-size:1em; } /* inner li font size must be reset so that they don't blow up */
|
||||
|
||||
.fg-menu-flyout ul ul { padding: .4em; }
|
||||
.fg-menu-flyout li { position:relative; }
|
||||
|
||||
.fg-menu-scroll { overflow: scroll; overflow-x: hidden; }
|
||||
|
||||
.fg-menu-breadcrumb { margin: 0; padding: 0; }
|
||||
|
||||
.fg-menu-footer { margin-top: .4em; padding: .4em; }
|
||||
.fg-menu-header { margin-bottom: .4em; padding: .4em; }
|
||||
|
||||
.fg-menu-breadcrumb li { float: left; list-style: none; margin: 0; padding: 0 .2em; font-size: .9em; opacity: .7; }
|
||||
.fg-menu-breadcrumb li.fg-menu-prev-list,
|
||||
.fg-menu-breadcrumb li.fg-menu-current-crumb { clear: left; float: none; opacity: 1; }
|
||||
.fg-menu-breadcrumb li.fg-menu-current-crumb { padding-top: .2em; }
|
||||
|
||||
.fg-menu-breadcrumb a,
|
||||
.fg-menu-breadcrumb span { float: left; }
|
||||
|
||||
.fg-menu-footer a:link,
|
||||
.fg-menu-footer a:visited { float:left; width:100%; text-decoration: none; }
|
||||
.fg-menu-footer a:hover,
|
||||
.fg-menu-footer a:active { }
|
||||
|
||||
.fg-menu-footer a span { float:left; cursor: pointer; }
|
||||
|
||||
.fg-menu-breadcrumb .fg-menu-prev-list a:link,
|
||||
.fg-menu-breadcrumb .fg-menu-prev-list a:visited,
|
||||
.fg-menu-breadcrumb .fg-menu-prev-list a:hover,
|
||||
.fg-menu-breadcrumb .fg-menu-prev-list a:active { background-image: none; text-decoration:none; }
|
||||
|
||||
.fg-menu-breadcrumb .fg-menu-prev-list a { float: left; padding-right: .4em; }
|
||||
.fg-menu-breadcrumb .fg-menu-prev-list a .ui-icon { float: left; }
|
||||
|
||||
.fg-menu-breadcrumb .fg-menu-current-crumb a:link,
|
||||
.fg-menu-breadcrumb .fg-menu-current-crumb a:visited,
|
||||
.fg-menu-breadcrumb .fg-menu-current-crumb a:hover,
|
||||
.fg-menu-breadcrumb .fg-menu-current-crumb a:active { display:block; background-image:none; font-size:1.3em; text-decoration:none; }
|
||||
|
||||
|
||||
|
||||
/* REQUIRED LINK STYLES: links are "display:block" by default; if the menu options are split into
|
||||
selectable node links and 'next' links, the script floats the node links left and floats the 'next' links to the right */
|
||||
|
||||
.fg-menu a:link,
|
||||
.fg-menu a:visited,
|
||||
.fg-menu a:hover,
|
||||
.fg-menu a:active { float:left; width:92%; padding:.3em 3%; text-decoration:none; outline: 0 !important; }
|
||||
|
||||
.fg-menu a { border: 1px dashed transparent; }
|
||||
|
||||
.fg-menu a.ui-state-default:link,
|
||||
.fg-menu a.ui-state-default:visited,
|
||||
.fg-menu a.ui-state-default:hover,
|
||||
.fg-menu a.ui-state-default:active,
|
||||
.fg-menu a.ui-state-hover:link,
|
||||
.fg-menu a.ui-state-hover:visited,
|
||||
.fg-menu a.ui-state-hover:hover,
|
||||
.fg-menu a.ui-state-hover:active,
|
||||
.fg-menu a.ui-state-active:link,
|
||||
.fg-menu a.ui-state-active:visited,
|
||||
.fg-menu a.ui-state-active:hover,
|
||||
.fg-menu a.ui-state-active:active { border-style: solid; font-weight: normal; }
|
||||
|
||||
.fg-menu a span { display:block; cursor:pointer; }
|
||||
|
||||
|
||||
/* SUGGESTED STYLES - for use with jQuery UI Themeroller CSS */
|
||||
|
||||
.fg-menu-indicator span { float:left; }
|
||||
.fg-menu-indicator span.ui-icon { float:right; }
|
||||
|
||||
.fg-menu-content.ui-widget-content,
|
||||
.fg-menu-content ul.ui-widget-content { border:0; }
|
||||
|
||||
|
||||
/* ICONS AND DIVIDERS */
|
||||
|
||||
.fg-menu.fg-menu-has-icons a:link,
|
||||
.fg-menu.fg-menu-has-icons a:visited,
|
||||
.fg-menu.fg-menu-has-icons a:hover,
|
||||
.fg-menu.fg-menu-has-icons a:active { padding-left:20px; }
|
||||
|
||||
.fg-menu .horizontal-divider hr, .fg-menu .horizontal-divider span { padding:0; margin:5px .6em; }
|
||||
.fg-menu .horizontal-divider hr { border:0; height:1px; }
|
||||
.fg-menu .horizontal-divider span { font-size:.9em; text-transform: uppercase; padding-left:.2em; }
|
||||
|
||||
@@ -40,14 +40,6 @@ h3 {
|
||||
color: #EB8F00;
|
||||
text-decoration: none;
|
||||
}
|
||||
table.datatable {
|
||||
width: 100%;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
}
|
||||
td.menucontainer {
|
||||
text-align: right;
|
||||
}
|
||||
table.listResults {
|
||||
padding: 0px;
|
||||
border-top: 3px solid #f6f6f1;
|
||||
@@ -66,7 +58,7 @@ table.listContainer {
|
||||
border: 0;
|
||||
padding: 0;
|
||||
margin:0;
|
||||
width: 100%;
|
||||
width: 97%;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
@@ -184,13 +176,6 @@ legend {
|
||||
-webkit-border-radius: 6px;
|
||||
border-radius: 6px;
|
||||
}
|
||||
legend.transparent {
|
||||
background: transparent;
|
||||
color: #333333;
|
||||
font-size: 1em;
|
||||
font-weight: normal;
|
||||
padding: 0;
|
||||
}
|
||||
.ui-widget-content td legend a, .ui-widget-content td legend a:hover, .ui-widget-content td legend a:visited {
|
||||
color: #fff;
|
||||
}
|
||||
@@ -400,10 +385,6 @@ a.CollapsibleLabel.open, td a.CollapsibleLabel.open {
|
||||
background-color:#f6f6f1;
|
||||
padding:5px;
|
||||
}
|
||||
/* move up a header immediately following a display block (i.e. "actions" menu) */
|
||||
.display_block + .page_header {
|
||||
margin-top: -8px;
|
||||
}
|
||||
|
||||
.notreeview li { background: url(../images/tv-item.gif) 0 0 no-repeat; }
|
||||
.notreeview .collapsable { background-image: url(../images/tv-collapsable.gif); }
|
||||
@@ -422,12 +403,8 @@ div.itop_popup {
|
||||
padding: 0;
|
||||
float:right;
|
||||
}
|
||||
div.itop_popup > ul > li {
|
||||
list-style: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
div.actions_menu > ul {
|
||||
div.itop_popup > ul {
|
||||
height:19px;
|
||||
line-height: 17px;
|
||||
vertical-align: middle;
|
||||
@@ -436,10 +413,9 @@ div.actions_menu > ul {
|
||||
padding-left: 5px;
|
||||
background: url(../images/actions_left.png) no-repeat top left;
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div.actions_menu > ul > li {
|
||||
div.itop_popup > ul > li {
|
||||
float: left;
|
||||
list-style: none;
|
||||
font-size: 11px;
|
||||
@@ -451,14 +427,12 @@ div.actions_menu > ul > li {
|
||||
font-weight: bold;
|
||||
color: #fff;
|
||||
vertical-align: middle;
|
||||
margin: 0;
|
||||
}
|
||||
#logOffBtn > ul > li {
|
||||
list-style: none;
|
||||
vertical-align: middle;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
#logOffBtn > ul {
|
||||
list-style: none;
|
||||
@@ -489,14 +463,6 @@ div.actions_menu > ul > li {
|
||||
white-space: nowrap;
|
||||
background: #fff;
|
||||
}
|
||||
.itop_popup ul {
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
.menucontainer div.toolkit_menu {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.itop_popup li a:hover, #logOffBtn li a:hover {
|
||||
background: #1A4473;
|
||||
}
|
||||
@@ -531,9 +497,6 @@ div.actions_menu > ul > li {
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
}
|
||||
.itop_popup > ul {
|
||||
margin: 0;
|
||||
}
|
||||
hr.menu-separator {
|
||||
border: none 0;
|
||||
border-top: 1px solid #ccc;;
|
||||
@@ -810,10 +773,9 @@ p.page-header {
|
||||
}
|
||||
td.dashboard {
|
||||
vertical-align:top;
|
||||
text-align: center;
|
||||
border: 1px solid #ccc;
|
||||
-moz-border-radius: 10px;
|
||||
-webkit-border-radius: 10px;
|
||||
border-radius: 10px;
|
||||
padding: 10px;
|
||||
width: 50%;
|
||||
}
|
||||
@@ -824,6 +786,7 @@ td.dashboard {
|
||||
/*** New Lacanau layout ***/
|
||||
|
||||
.ui-layout-pane { /* all 'panes' */
|
||||
background: #FFF;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
@@ -852,7 +815,6 @@ div#right {
|
||||
}
|
||||
div#menu {
|
||||
width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
.header-menu {
|
||||
padding-left: 24px;
|
||||
@@ -1099,11 +1061,8 @@ table.pagination {
|
||||
table.pagination tr td {
|
||||
padding: 3px;
|
||||
}
|
||||
.pagination_container {
|
||||
padding-left: 3px;
|
||||
}
|
||||
.pager {
|
||||
display:inline-block;
|
||||
float:left;
|
||||
}
|
||||
.pager p {
|
||||
margin-top: 0;
|
||||
@@ -1111,8 +1070,6 @@ table.pagination tr td {
|
||||
}
|
||||
.pager td span {
|
||||
min-width: 20px;
|
||||
padding-left: 2px;
|
||||
padding-right: 2px;
|
||||
display:inline-block;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
@@ -1132,7 +1089,7 @@ div.actions_button {
|
||||
float:right;
|
||||
background: url("../images/actions_left.png") no-repeat scroll left top transparent;
|
||||
padding-left: 5px;
|
||||
margin-top: 0;
|
||||
margin-top: 13px;
|
||||
margin-right: 10px;
|
||||
height:17px;
|
||||
vertical-align: middle;
|
||||
@@ -1154,218 +1111,4 @@ div.actions_button a, .actions_button a:hover, .actions_button a:visited {
|
||||
}
|
||||
select#org_id {
|
||||
max-width: 90%;
|
||||
}
|
||||
/*********** Dashboards ***********/
|
||||
.itop-dashboard {
|
||||
background-color: #fff;
|
||||
}
|
||||
.dragHover {
|
||||
background: url(./ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png);
|
||||
}
|
||||
.edit_mode .dashlet {
|
||||
background: url(./ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png);
|
||||
padding: 5px;
|
||||
margin:0;
|
||||
position:relative;
|
||||
}
|
||||
.edit_mode .dashlet-selected {
|
||||
background: #EB8F00 !important;
|
||||
padding: 5px;
|
||||
margin:0;
|
||||
}
|
||||
td.layout_cell {
|
||||
height: 50px; /* min-height does not work */
|
||||
vertical-align: top;
|
||||
}
|
||||
.dashlet-content {
|
||||
background: #fff;
|
||||
margin:0;
|
||||
}
|
||||
table.prop_table {
|
||||
border-bottom: 2px solid #F9F9F1;
|
||||
padding: 1px;
|
||||
width: 100%;
|
||||
}
|
||||
.close-box {
|
||||
margin: 5px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
z-index: 10;
|
||||
background: transparent url(../images/delete.png) no-repeat center;
|
||||
}
|
||||
td.prop_value {
|
||||
text-align: left;
|
||||
}
|
||||
tr.itop-property-field-modified td {
|
||||
background: #fbb;
|
||||
}
|
||||
tr.itop-property-field-modified td.hover {
|
||||
background: #f99;
|
||||
}
|
||||
td.prop_value textarea, td.prop_value input[type=text]{
|
||||
width: 98%;
|
||||
}
|
||||
td.prop_icon {
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
.dashlet {
|
||||
text-align:left;
|
||||
}
|
||||
.dashlet-inline {
|
||||
display: inline-block;
|
||||
}
|
||||
.dashlet-badge a.actions {
|
||||
background: none repeat scroll 0 0 transparent;
|
||||
color: #666666;
|
||||
font-size: 16px;
|
||||
text-decoration: none;
|
||||
}
|
||||
.dashlet-content .display_block {
|
||||
text-align:left;
|
||||
}
|
||||
.prop_apply .ui-icon-alert {
|
||||
display: none;
|
||||
}
|
||||
.prop_apply .ui-state-error .ui-icon-alert {
|
||||
display: block;
|
||||
}
|
||||
.ui-state-error .ui-icon-circle-check {
|
||||
display: none;
|
||||
}
|
||||
.summary-details {
|
||||
float: right;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.summary-details th {
|
||||
background: none repeat scroll 0 0 #CCCCCC;
|
||||
color: #EEEEEE;
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
.main_header {
|
||||
background-color: #F1F1F6;
|
||||
min-height: 60px;
|
||||
width: 100%;
|
||||
}
|
||||
.main_header h1 {
|
||||
color: #1C94C4;
|
||||
line-height: 16px;
|
||||
margin-bottom: 0;
|
||||
margin-top: 0;
|
||||
padding-bottom: 10px;
|
||||
padding-top: 10px;
|
||||
}
|
||||
.main_header img {
|
||||
margin-top: 10px;
|
||||
margin-right: 10px;
|
||||
float:left;
|
||||
}
|
||||
a.summary, a.summary:hover {
|
||||
background: none repeat scroll 0 0 transparent;
|
||||
color: #666666;
|
||||
text-decoration: none;
|
||||
padding-left: 0;
|
||||
}
|
||||
.summary-details td {
|
||||
background: none repeat scroll 0 0 transparent;
|
||||
padding: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#DashboardMenu > ul > li {
|
||||
list-style: none;
|
||||
vertical-align: middle;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#DashboardMenu > ul {
|
||||
list-style: none;
|
||||
vertical-align: middle;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 25px;
|
||||
}
|
||||
#DashboardMenu li a {
|
||||
display: block;
|
||||
padding: 5px 12px;
|
||||
text-decoration: none;
|
||||
color: #000;
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
white-space: nowrap;
|
||||
background: #fff;
|
||||
}
|
||||
#DashboardMenu li span {
|
||||
display: block;
|
||||
padding: 5px 12px;
|
||||
text-decoration: none;
|
||||
color: #000;
|
||||
white-space: nowrap;
|
||||
background: #fff;
|
||||
}
|
||||
#DashboardMenu li {
|
||||
list-style: none;
|
||||
}
|
||||
#DashboardMenu li a:hover {
|
||||
background: #1A4473;
|
||||
}
|
||||
|
||||
#DashboardMenu ul > li > ul
|
||||
{
|
||||
border: 1px solid black;
|
||||
background: #fff;
|
||||
}
|
||||
|
||||
#DashboardMenu li > ul
|
||||
{ margin: 0;
|
||||
padding: 0;
|
||||
position: absolute;
|
||||
display: none;
|
||||
border-top: 1px solid white;
|
||||
z-index: 999;
|
||||
}
|
||||
#DashboardMenu li ul li a:hover{
|
||||
background: #D81515;
|
||||
color: #fff;
|
||||
font-weight: bold;
|
||||
list-style: none;
|
||||
}
|
||||
.sortable_field_list {
|
||||
display: inline-block;
|
||||
width: 250px;
|
||||
height: 150px;
|
||||
border: 1px #333 solid;
|
||||
overflow: auto;
|
||||
padding-left: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.sortable_field_list li {
|
||||
list-style: none;
|
||||
font-size: 11px;
|
||||
}
|
||||
.sort_order {
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 12px;
|
||||
}
|
||||
.sort_none {
|
||||
background: url(../images/bg.gif) no-repeat center;
|
||||
}
|
||||
.sort_asc {
|
||||
background: url(../images/desc.gif) no-repeat center;
|
||||
}
|
||||
.sort_desc {
|
||||
background: url(../images/asc.gif) no-repeat center;
|
||||
}
|
||||
.sort_hidden {
|
||||
display: none;
|
||||
}
|
||||
.sortable_field_list > li.selected {
|
||||
background: #F6A828;
|
||||
}
|
||||
565
css/ui-lightness/jquery-ui-1.8.17.custom.css
vendored
565
css/ui-lightness/jquery-ui-1.8.17.custom.css
vendored
@@ -1,565 +0,0 @@
|
||||
/*
|
||||
* jQuery UI CSS Framework 1.8.17
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Theming/API
|
||||
*/
|
||||
|
||||
/* Layout helpers
|
||||
----------------------------------*/
|
||||
.ui-helper-hidden { display: none; }
|
||||
.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); }
|
||||
.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
|
||||
.ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; }
|
||||
.ui-helper-clearfix:after { clear: both; }
|
||||
.ui-helper-clearfix { zoom: 1; }
|
||||
.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
|
||||
|
||||
|
||||
/* Interaction Cues
|
||||
----------------------------------*/
|
||||
.ui-state-disabled { cursor: default !important; }
|
||||
|
||||
|
||||
/* Icons
|
||||
----------------------------------*/
|
||||
|
||||
/* states and images */
|
||||
.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; }
|
||||
|
||||
|
||||
/* Misc visuals
|
||||
----------------------------------*/
|
||||
|
||||
/* Overlays */
|
||||
.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
|
||||
|
||||
|
||||
/*
|
||||
* jQuery UI CSS Framework 1.8.17
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Theming/API
|
||||
*
|
||||
* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS,%20Tahoma,%20Verdana,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=02_glass.png&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=03_highlight_soft.png&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px
|
||||
*/
|
||||
|
||||
|
||||
/* Component containers
|
||||
----------------------------------*/
|
||||
.ui-widget { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1.1em; }
|
||||
.ui-widget .ui-widget { font-size: 1em; }
|
||||
.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1em; }
|
||||
.ui-widget-content { border: 1px solid #dddddd; background: #eeeeee url(images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x; color: #333333; }
|
||||
.ui-widget-content a { color: #333333; }
|
||||
.ui-widget-header { border: 1px solid #e78f08; background: #f6a828 url(images/ui-bg_gloss-wave_35_f6a828_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; }
|
||||
.ui-widget-header a { color: #ffffff; }
|
||||
|
||||
/* Interaction states
|
||||
----------------------------------*/
|
||||
.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #cccccc; background: #f6f6f6 url(images/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1c94c4; }
|
||||
.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #1c94c4; text-decoration: none; }
|
||||
.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #fbcb09; background: #fdf5ce url(images/ui-bg_glass_100_fdf5ce_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #c77405; }
|
||||
.ui-state-hover a, .ui-state-hover a:hover { color: #c77405; text-decoration: none; }
|
||||
.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #fbd850; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #eb8f00; }
|
||||
.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #eb8f00; text-decoration: none; }
|
||||
.ui-widget :active { outline: none; }
|
||||
|
||||
/* Interaction Cues
|
||||
----------------------------------*/
|
||||
.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fed22f; background: #ffe45c url(images/ui-bg_highlight-soft_75_ffe45c_1x100.png) 50% top repeat-x; color: #363636; }
|
||||
.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; }
|
||||
.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #b81900 url(images/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat; color: #ffffff; }
|
||||
.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #ffffff; }
|
||||
.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #ffffff; }
|
||||
.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
|
||||
.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
|
||||
.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
|
||||
|
||||
/* Icons
|
||||
----------------------------------*/
|
||||
|
||||
/* states and images */
|
||||
.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); }
|
||||
.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); }
|
||||
.ui-widget-header .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); }
|
||||
.ui-state-default .ui-icon { background-image: url(images/ui-icons_ef8c08_256x240.png); }
|
||||
.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); }
|
||||
.ui-state-active .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); }
|
||||
.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_228ef1_256x240.png); }
|
||||
.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_ffd27a_256x240.png); }
|
||||
|
||||
/* positioning */
|
||||
.ui-icon-carat-1-n { background-position: 0 0; }
|
||||
.ui-icon-carat-1-ne { background-position: -16px 0; }
|
||||
.ui-icon-carat-1-e { background-position: -32px 0; }
|
||||
.ui-icon-carat-1-se { background-position: -48px 0; }
|
||||
.ui-icon-carat-1-s { background-position: -64px 0; }
|
||||
.ui-icon-carat-1-sw { background-position: -80px 0; }
|
||||
.ui-icon-carat-1-w { background-position: -96px 0; }
|
||||
.ui-icon-carat-1-nw { background-position: -112px 0; }
|
||||
.ui-icon-carat-2-n-s { background-position: -128px 0; }
|
||||
.ui-icon-carat-2-e-w { background-position: -144px 0; }
|
||||
.ui-icon-triangle-1-n { background-position: 0 -16px; }
|
||||
.ui-icon-triangle-1-ne { background-position: -16px -16px; }
|
||||
.ui-icon-triangle-1-e { background-position: -32px -16px; }
|
||||
.ui-icon-triangle-1-se { background-position: -48px -16px; }
|
||||
.ui-icon-triangle-1-s { background-position: -64px -16px; }
|
||||
.ui-icon-triangle-1-sw { background-position: -80px -16px; }
|
||||
.ui-icon-triangle-1-w { background-position: -96px -16px; }
|
||||
.ui-icon-triangle-1-nw { background-position: -112px -16px; }
|
||||
.ui-icon-triangle-2-n-s { background-position: -128px -16px; }
|
||||
.ui-icon-triangle-2-e-w { background-position: -144px -16px; }
|
||||
.ui-icon-arrow-1-n { background-position: 0 -32px; }
|
||||
.ui-icon-arrow-1-ne { background-position: -16px -32px; }
|
||||
.ui-icon-arrow-1-e { background-position: -32px -32px; }
|
||||
.ui-icon-arrow-1-se { background-position: -48px -32px; }
|
||||
.ui-icon-arrow-1-s { background-position: -64px -32px; }
|
||||
.ui-icon-arrow-1-sw { background-position: -80px -32px; }
|
||||
.ui-icon-arrow-1-w { background-position: -96px -32px; }
|
||||
.ui-icon-arrow-1-nw { background-position: -112px -32px; }
|
||||
.ui-icon-arrow-2-n-s { background-position: -128px -32px; }
|
||||
.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; }
|
||||
.ui-icon-arrow-2-e-w { background-position: -160px -32px; }
|
||||
.ui-icon-arrow-2-se-nw { background-position: -176px -32px; }
|
||||
.ui-icon-arrowstop-1-n { background-position: -192px -32px; }
|
||||
.ui-icon-arrowstop-1-e { background-position: -208px -32px; }
|
||||
.ui-icon-arrowstop-1-s { background-position: -224px -32px; }
|
||||
.ui-icon-arrowstop-1-w { background-position: -240px -32px; }
|
||||
.ui-icon-arrowthick-1-n { background-position: 0 -48px; }
|
||||
.ui-icon-arrowthick-1-ne { background-position: -16px -48px; }
|
||||
.ui-icon-arrowthick-1-e { background-position: -32px -48px; }
|
||||
.ui-icon-arrowthick-1-se { background-position: -48px -48px; }
|
||||
.ui-icon-arrowthick-1-s { background-position: -64px -48px; }
|
||||
.ui-icon-arrowthick-1-sw { background-position: -80px -48px; }
|
||||
.ui-icon-arrowthick-1-w { background-position: -96px -48px; }
|
||||
.ui-icon-arrowthick-1-nw { background-position: -112px -48px; }
|
||||
.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; }
|
||||
.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; }
|
||||
.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; }
|
||||
.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; }
|
||||
.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; }
|
||||
.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; }
|
||||
.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; }
|
||||
.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; }
|
||||
.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; }
|
||||
.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; }
|
||||
.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; }
|
||||
.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; }
|
||||
.ui-icon-arrowreturn-1-w { background-position: -64px -64px; }
|
||||
.ui-icon-arrowreturn-1-n { background-position: -80px -64px; }
|
||||
.ui-icon-arrowreturn-1-e { background-position: -96px -64px; }
|
||||
.ui-icon-arrowreturn-1-s { background-position: -112px -64px; }
|
||||
.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; }
|
||||
.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; }
|
||||
.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; }
|
||||
.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; }
|
||||
.ui-icon-arrow-4 { background-position: 0 -80px; }
|
||||
.ui-icon-arrow-4-diag { background-position: -16px -80px; }
|
||||
.ui-icon-extlink { background-position: -32px -80px; }
|
||||
.ui-icon-newwin { background-position: -48px -80px; }
|
||||
.ui-icon-refresh { background-position: -64px -80px; }
|
||||
.ui-icon-shuffle { background-position: -80px -80px; }
|
||||
.ui-icon-transfer-e-w { background-position: -96px -80px; }
|
||||
.ui-icon-transferthick-e-w { background-position: -112px -80px; }
|
||||
.ui-icon-folder-collapsed { background-position: 0 -96px; }
|
||||
.ui-icon-folder-open { background-position: -16px -96px; }
|
||||
.ui-icon-document { background-position: -32px -96px; }
|
||||
.ui-icon-document-b { background-position: -48px -96px; }
|
||||
.ui-icon-note { background-position: -64px -96px; }
|
||||
.ui-icon-mail-closed { background-position: -80px -96px; }
|
||||
.ui-icon-mail-open { background-position: -96px -96px; }
|
||||
.ui-icon-suitcase { background-position: -112px -96px; }
|
||||
.ui-icon-comment { background-position: -128px -96px; }
|
||||
.ui-icon-person { background-position: -144px -96px; }
|
||||
.ui-icon-print { background-position: -160px -96px; }
|
||||
.ui-icon-trash { background-position: -176px -96px; }
|
||||
.ui-icon-locked { background-position: -192px -96px; }
|
||||
.ui-icon-unlocked { background-position: -208px -96px; }
|
||||
.ui-icon-bookmark { background-position: -224px -96px; }
|
||||
.ui-icon-tag { background-position: -240px -96px; }
|
||||
.ui-icon-home { background-position: 0 -112px; }
|
||||
.ui-icon-flag { background-position: -16px -112px; }
|
||||
.ui-icon-calendar { background-position: -32px -112px; }
|
||||
.ui-icon-cart { background-position: -48px -112px; }
|
||||
.ui-icon-pencil { background-position: -64px -112px; }
|
||||
.ui-icon-clock { background-position: -80px -112px; }
|
||||
.ui-icon-disk { background-position: -96px -112px; }
|
||||
.ui-icon-calculator { background-position: -112px -112px; }
|
||||
.ui-icon-zoomin { background-position: -128px -112px; }
|
||||
.ui-icon-zoomout { background-position: -144px -112px; }
|
||||
.ui-icon-search { background-position: -160px -112px; }
|
||||
.ui-icon-wrench { background-position: -176px -112px; }
|
||||
.ui-icon-gear { background-position: -192px -112px; }
|
||||
.ui-icon-heart { background-position: -208px -112px; }
|
||||
.ui-icon-star { background-position: -224px -112px; }
|
||||
.ui-icon-link { background-position: -240px -112px; }
|
||||
.ui-icon-cancel { background-position: 0 -128px; }
|
||||
.ui-icon-plus { background-position: -16px -128px; }
|
||||
.ui-icon-plusthick { background-position: -32px -128px; }
|
||||
.ui-icon-minus { background-position: -48px -128px; }
|
||||
.ui-icon-minusthick { background-position: -64px -128px; }
|
||||
.ui-icon-close { background-position: -80px -128px; }
|
||||
.ui-icon-closethick { background-position: -96px -128px; }
|
||||
.ui-icon-key { background-position: -112px -128px; }
|
||||
.ui-icon-lightbulb { background-position: -128px -128px; }
|
||||
.ui-icon-scissors { background-position: -144px -128px; }
|
||||
.ui-icon-clipboard { background-position: -160px -128px; }
|
||||
.ui-icon-copy { background-position: -176px -128px; }
|
||||
.ui-icon-contact { background-position: -192px -128px; }
|
||||
.ui-icon-image { background-position: -208px -128px; }
|
||||
.ui-icon-video { background-position: -224px -128px; }
|
||||
.ui-icon-script { background-position: -240px -128px; }
|
||||
.ui-icon-alert { background-position: 0 -144px; }
|
||||
.ui-icon-info { background-position: -16px -144px; }
|
||||
.ui-icon-notice { background-position: -32px -144px; }
|
||||
.ui-icon-help { background-position: -48px -144px; }
|
||||
.ui-icon-check { background-position: -64px -144px; }
|
||||
.ui-icon-bullet { background-position: -80px -144px; }
|
||||
.ui-icon-radio-off { background-position: -96px -144px; }
|
||||
.ui-icon-radio-on { background-position: -112px -144px; }
|
||||
.ui-icon-pin-w { background-position: -128px -144px; }
|
||||
.ui-icon-pin-s { background-position: -144px -144px; }
|
||||
.ui-icon-play { background-position: 0 -160px; }
|
||||
.ui-icon-pause { background-position: -16px -160px; }
|
||||
.ui-icon-seek-next { background-position: -32px -160px; }
|
||||
.ui-icon-seek-prev { background-position: -48px -160px; }
|
||||
.ui-icon-seek-end { background-position: -64px -160px; }
|
||||
.ui-icon-seek-start { background-position: -80px -160px; }
|
||||
/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */
|
||||
.ui-icon-seek-first { background-position: -80px -160px; }
|
||||
.ui-icon-stop { background-position: -96px -160px; }
|
||||
.ui-icon-eject { background-position: -112px -160px; }
|
||||
.ui-icon-volume-off { background-position: -128px -160px; }
|
||||
.ui-icon-volume-on { background-position: -144px -160px; }
|
||||
.ui-icon-power { background-position: 0 -176px; }
|
||||
.ui-icon-signal-diag { background-position: -16px -176px; }
|
||||
.ui-icon-signal { background-position: -32px -176px; }
|
||||
.ui-icon-battery-0 { background-position: -48px -176px; }
|
||||
.ui-icon-battery-1 { background-position: -64px -176px; }
|
||||
.ui-icon-battery-2 { background-position: -80px -176px; }
|
||||
.ui-icon-battery-3 { background-position: -96px -176px; }
|
||||
.ui-icon-circle-plus { background-position: 0 -192px; }
|
||||
.ui-icon-circle-minus { background-position: -16px -192px; }
|
||||
.ui-icon-circle-close { background-position: -32px -192px; }
|
||||
.ui-icon-circle-triangle-e { background-position: -48px -192px; }
|
||||
.ui-icon-circle-triangle-s { background-position: -64px -192px; }
|
||||
.ui-icon-circle-triangle-w { background-position: -80px -192px; }
|
||||
.ui-icon-circle-triangle-n { background-position: -96px -192px; }
|
||||
.ui-icon-circle-arrow-e { background-position: -112px -192px; }
|
||||
.ui-icon-circle-arrow-s { background-position: -128px -192px; }
|
||||
.ui-icon-circle-arrow-w { background-position: -144px -192px; }
|
||||
.ui-icon-circle-arrow-n { background-position: -160px -192px; }
|
||||
.ui-icon-circle-zoomin { background-position: -176px -192px; }
|
||||
.ui-icon-circle-zoomout { background-position: -192px -192px; }
|
||||
.ui-icon-circle-check { background-position: -208px -192px; }
|
||||
.ui-icon-circlesmall-plus { background-position: 0 -208px; }
|
||||
.ui-icon-circlesmall-minus { background-position: -16px -208px; }
|
||||
.ui-icon-circlesmall-close { background-position: -32px -208px; }
|
||||
.ui-icon-squaresmall-plus { background-position: -48px -208px; }
|
||||
.ui-icon-squaresmall-minus { background-position: -64px -208px; }
|
||||
.ui-icon-squaresmall-close { background-position: -80px -208px; }
|
||||
.ui-icon-grip-dotted-vertical { background-position: 0 -224px; }
|
||||
.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; }
|
||||
.ui-icon-grip-solid-vertical { background-position: -32px -224px; }
|
||||
.ui-icon-grip-solid-horizontal { background-position: -48px -224px; }
|
||||
.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; }
|
||||
.ui-icon-grip-diagonal-se { background-position: -80px -224px; }
|
||||
|
||||
|
||||
/* Misc visuals
|
||||
----------------------------------*/
|
||||
|
||||
/* Corner radius */
|
||||
.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; }
|
||||
.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; }
|
||||
.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; }
|
||||
.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; }
|
||||
|
||||
/* Overlays */
|
||||
.ui-widget-overlay { background: #666666 url(images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat; opacity: .50;filter:Alpha(Opacity=50); }
|
||||
.ui-widget-shadow { margin: -5px 0 0 -5px; padding: 5px; background: #000000 url(images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 5px; -khtml-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }/*
|
||||
* jQuery UI Resizable 1.8.17
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Resizable#theming
|
||||
*/
|
||||
.ui-resizable { position: relative;}
|
||||
.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block; }
|
||||
.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
|
||||
.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
|
||||
.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
|
||||
.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
|
||||
.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
|
||||
.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
|
||||
.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
|
||||
.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
|
||||
.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/*
|
||||
* jQuery UI Selectable 1.8.17
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Selectable#theming
|
||||
*/
|
||||
.ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
|
||||
/*
|
||||
* jQuery UI Accordion 1.8.17
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Accordion#theming
|
||||
*/
|
||||
/* IE/Win - Fix animation bug - #4615 */
|
||||
.ui-accordion { width: 100%; }
|
||||
.ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
|
||||
.ui-accordion .ui-accordion-li-fix { display: inline; }
|
||||
.ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
|
||||
.ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; }
|
||||
.ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; }
|
||||
.ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
|
||||
.ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; }
|
||||
.ui-accordion .ui-accordion-content-active { display: block; }
|
||||
/*
|
||||
* jQuery UI Autocomplete 1.8.17
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Autocomplete#theming
|
||||
*/
|
||||
.ui-autocomplete { position: absolute; cursor: default; }
|
||||
|
||||
/* workarounds */
|
||||
* html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
|
||||
|
||||
/*
|
||||
* jQuery UI Menu 1.8.17
|
||||
*
|
||||
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Menu#theming
|
||||
*/
|
||||
.ui-menu {
|
||||
list-style:none;
|
||||
padding: 2px;
|
||||
margin: 0;
|
||||
display:block;
|
||||
float: left;
|
||||
}
|
||||
.ui-menu .ui-menu {
|
||||
margin-top: -3px;
|
||||
}
|
||||
.ui-menu .ui-menu-item {
|
||||
margin:0;
|
||||
padding: 0;
|
||||
zoom: 1;
|
||||
float: left;
|
||||
clear: left;
|
||||
width: 100%;
|
||||
}
|
||||
.ui-menu .ui-menu-item a {
|
||||
text-decoration:none;
|
||||
display:block;
|
||||
padding:.2em .4em;
|
||||
line-height:1.5;
|
||||
zoom:1;
|
||||
}
|
||||
.ui-menu .ui-menu-item a.ui-state-hover,
|
||||
.ui-menu .ui-menu-item a.ui-state-active {
|
||||
font-weight: normal;
|
||||
margin: -1px;
|
||||
}
|
||||
/*
|
||||
* jQuery UI Button 1.8.17
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Button#theming
|
||||
*/
|
||||
.ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
|
||||
.ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
|
||||
button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
|
||||
.ui-button-icons-only { width: 3.4em; }
|
||||
button.ui-button-icons-only { width: 3.7em; }
|
||||
|
||||
/*button text element */
|
||||
.ui-button .ui-button-text { display: block; line-height: 1.4; }
|
||||
.ui-button-text-only .ui-button-text { padding: .4em 1em; }
|
||||
.ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
|
||||
.ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
|
||||
.ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
|
||||
.ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
|
||||
/* no icon support for input elements, provide padding by default */
|
||||
input.ui-button { padding: .4em 1em; }
|
||||
|
||||
/*button icon element(s) */
|
||||
.ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
|
||||
.ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
|
||||
.ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
|
||||
.ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
|
||||
.ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
|
||||
|
||||
/*button sets*/
|
||||
.ui-buttonset { margin-right: 7px; }
|
||||
.ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
|
||||
|
||||
/* workarounds */
|
||||
button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
|
||||
/*
|
||||
* jQuery UI Dialog 1.8.17
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Dialog#theming
|
||||
*/
|
||||
.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
|
||||
.ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; }
|
||||
.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; }
|
||||
.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
|
||||
.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
|
||||
.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
|
||||
.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
|
||||
.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
|
||||
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
|
||||
.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
|
||||
.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
|
||||
.ui-draggable .ui-dialog-titlebar { cursor: move; }
|
||||
/*
|
||||
* jQuery UI Slider 1.8.17
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Slider#theming
|
||||
*/
|
||||
.ui-slider { position: relative; text-align: left; }
|
||||
.ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
|
||||
.ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
|
||||
|
||||
.ui-slider-horizontal { height: .8em; }
|
||||
.ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
|
||||
.ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
|
||||
.ui-slider-horizontal .ui-slider-range-min { left: 0; }
|
||||
.ui-slider-horizontal .ui-slider-range-max { right: 0; }
|
||||
|
||||
.ui-slider-vertical { width: .8em; height: 100px; }
|
||||
.ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
|
||||
.ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
|
||||
.ui-slider-vertical .ui-slider-range-min { bottom: 0; }
|
||||
.ui-slider-vertical .ui-slider-range-max { top: 0; }/*
|
||||
* jQuery UI Tabs 1.8.17
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Tabs#theming
|
||||
*/
|
||||
.ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
|
||||
.ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
|
||||
.ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }
|
||||
.ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
|
||||
.ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; }
|
||||
.ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
|
||||
.ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
|
||||
.ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
|
||||
.ui-tabs .ui-tabs-hide { display: none !important; }
|
||||
/*
|
||||
* jQuery UI Datepicker 1.8.17
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Datepicker#theming
|
||||
*/
|
||||
.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
|
||||
.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
|
||||
.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
|
||||
.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
|
||||
.ui-datepicker .ui-datepicker-prev { left:2px; }
|
||||
.ui-datepicker .ui-datepicker-next { right:2px; }
|
||||
.ui-datepicker .ui-datepicker-prev-hover { left:1px; }
|
||||
.ui-datepicker .ui-datepicker-next-hover { right:1px; }
|
||||
.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
|
||||
.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
|
||||
.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
|
||||
.ui-datepicker select.ui-datepicker-month-year {width: 100%;}
|
||||
.ui-datepicker select.ui-datepicker-month,
|
||||
.ui-datepicker select.ui-datepicker-year { width: 49%;}
|
||||
.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
|
||||
.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
|
||||
.ui-datepicker td { border: 0; padding: 1px; }
|
||||
.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
|
||||
.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
|
||||
.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
|
||||
.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
|
||||
|
||||
/* with multiple calendars */
|
||||
.ui-datepicker.ui-datepicker-multi { width:auto; }
|
||||
.ui-datepicker-multi .ui-datepicker-group { float:left; }
|
||||
.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
|
||||
.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
|
||||
.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
|
||||
.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
|
||||
.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
|
||||
.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
|
||||
.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
|
||||
.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; }
|
||||
|
||||
/* RTL support */
|
||||
.ui-datepicker-rtl { direction: rtl; }
|
||||
.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
|
||||
.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
|
||||
.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
|
||||
.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
|
||||
.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
|
||||
.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
|
||||
.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
|
||||
.ui-datepicker-rtl .ui-datepicker-group { float:right; }
|
||||
.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
|
||||
.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
|
||||
|
||||
/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
|
||||
.ui-datepicker-cover {
|
||||
display: none; /*sorry for IE5*/
|
||||
display/**/: block; /*sorry for IE5*/
|
||||
position: absolute; /*must have*/
|
||||
z-index: -1; /*must have*/
|
||||
filter: mask(); /*must have*/
|
||||
top: -4px; /*must have*/
|
||||
left: -4px; /*must have*/
|
||||
width: 200px; /*must have*/
|
||||
height: 200px; /*must have*/
|
||||
}/*
|
||||
* jQuery UI Progressbar 1.8.17
|
||||
*
|
||||
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
||||
* Dual licensed under the MIT or GPL Version 2 licenses.
|
||||
* http://jquery.org/license
|
||||
*
|
||||
* http://docs.jquery.com/UI/Progressbar#theming
|
||||
*/
|
||||
.ui-progressbar { height:2em; text-align: left; overflow: hidden; }
|
||||
.ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
|
||||
@@ -1,126 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<installation>
|
||||
<steps type="array">
|
||||
<step>
|
||||
<title>Configuration Management options</title>
|
||||
<description><![CDATA[<h2>The options below allow you to configure the type of elements that are to be managed inside iTop.</h2>]]></description>
|
||||
<banner>/images/modules.png</banner>
|
||||
<options type="array">
|
||||
<choice>
|
||||
<title>Configuration Management Base</title>
|
||||
<description>This module is always installed, it contains all the base objects that are mandatory in the iTop CMDB: Organizations, Locations, Teams, Persons, etc.</description>
|
||||
<modules type="array">
|
||||
<module>itop-config-mgmt</module>
|
||||
<module>itop-profiles</module>
|
||||
<module>itop-welcome-itil</module>
|
||||
</modules>
|
||||
<mandatory>true</mandatory>
|
||||
</choice>
|
||||
<choice>
|
||||
<title>End-User Devices</title>
|
||||
<description>This optional module manages end-user devices like Phones, Printers, Desktop PCs.</description>
|
||||
<modules type="array">
|
||||
<module>cmdb-end-user</module>
|
||||
</modules>
|
||||
</choice>
|
||||
<choice>
|
||||
<title>Data Center Management</title>
|
||||
<description>This optional modules manages data center devices like Power Supplies, Racks, Enclosures.</description>
|
||||
<default>true</default>
|
||||
<modules type="array">
|
||||
<module>cmdb-datacenter</module>
|
||||
</modules>
|
||||
</choice>
|
||||
</options>
|
||||
</step>
|
||||
<step>
|
||||
<title>Service Management options</title>
|
||||
<description><![CDATA[<h2>Select the choice that best describes the relationships between the services and the IT infrastructure in your IT environment.</h2>]]></description>
|
||||
<banner>./wizard_icons/service.png</banner>
|
||||
<alternatives type="array">
|
||||
<choice>
|
||||
<title>Service Management for Enterprises</title>
|
||||
<description>Select this option if the IT delivers services based on a shared infrastructure. For example if different organizations within your company subscribe to services (like Mail and Print services) delivered by a single shared backend.</description>
|
||||
<modules type="array">
|
||||
<module>itop-service-mgmt-enterprise</module>
|
||||
</modules>
|
||||
<default>true</default>
|
||||
</choice>
|
||||
<choice>
|
||||
<title>Service Management for Service Providers</title>
|
||||
<description>Select this option if the IT manages the infrastructure of independent customers. This is the most flexible model, since the services can be delivered with a mix of shared and customer specific infrastructure devices.</description>
|
||||
<modules type="array">
|
||||
<module>itop-service-mgmt-provider</module>
|
||||
</modules>
|
||||
</choice>
|
||||
</alternatives>
|
||||
</step>
|
||||
<step>
|
||||
<title>Incident Management options</title>
|
||||
<description>Select the type of tickets you want to use in order to respond to user requests and incidents.</description>
|
||||
<banner></banner>
|
||||
<alternatives type="array">
|
||||
<choice>
|
||||
<title>Simple Ticket Management</title>
|
||||
<description>Select this option to use one single type of tickets for all kind of requests.</description>
|
||||
<modules type="array">
|
||||
<module>itop-simple-tickets</module>
|
||||
</modules>
|
||||
<default>true</default>
|
||||
</choice>
|
||||
<choice>
|
||||
<title>ITIL Compliant Tickets Management</title>
|
||||
<description>Select this option to have different types of ticket for managing user requests and incidents.</description>
|
||||
<modules type="array">
|
||||
<module>itop-itil-tickets</module>
|
||||
</modules>
|
||||
<sub_options>
|
||||
<options type="array">
|
||||
<choice>
|
||||
<title>Problem Management</title>
|
||||
<description>Manage problem ticket to solve recurring incidents.</description>
|
||||
<modules type="array">
|
||||
<module>itop-problem-management</module>
|
||||
</modules>
|
||||
</choice>
|
||||
<choice>
|
||||
<title>Known Error Database</title>
|
||||
<description>Manage Known Error tickets to document the possible root causes of incidents.</description>
|
||||
<modules type="array">
|
||||
<module>itop-kedb-management</module>
|
||||
</modules>
|
||||
</choice>
|
||||
</options>
|
||||
</sub_options>
|
||||
</choice>
|
||||
<choice>
|
||||
<title>None</title>
|
||||
<description>Don't manage incidents in iTop</description>
|
||||
<modules type="array">
|
||||
</modules>
|
||||
</choice>
|
||||
</alternatives>
|
||||
</step>
|
||||
<step>
|
||||
<title>Change Management options</title>
|
||||
<description><![CDATA[<h2>Select the type of tickets you want to use in order to manage changes to the IT infrastructure.</h2>]]></description>
|
||||
<banner>./itop-change-mgmt-1.0.0/images/change.png</banner>
|
||||
<alternatives type="array">
|
||||
<choice>
|
||||
<title>ITIL Change Management</title>
|
||||
<description>Select this option to use Normal/Routine/Emergency change tickets.</description>
|
||||
<modules type="array">
|
||||
<module>itop-change-mgmt</module>
|
||||
</modules>
|
||||
<default>true</default>
|
||||
</choice>
|
||||
<choice>
|
||||
<title>None</title>
|
||||
<description>Don't manage changes in iTop</description>
|
||||
<modules type="array">
|
||||
</modules>
|
||||
</choice>
|
||||
</alternatives>
|
||||
</step>
|
||||
</steps>
|
||||
</installation>
|
||||
@@ -1,200 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<classes>
|
||||
<class id="Attachment" _delta="define">
|
||||
<parent>DBObject</parent>
|
||||
<properties>
|
||||
<comment><![CDATA[/**
|
||||
* Module attachments
|
||||
*
|
||||
* A quick and easy way to upload and attach files to *any* (see Configuration below) object in the CMBD in one click
|
||||
*
|
||||
* Configuration: the list of classes for which the "Attachments" tab is visible is defined via the module's 'allowed_classes'
|
||||
* configuration parameter. By default the tab is active for all kind of Tickets.
|
||||
*
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/]]></comment>
|
||||
<category>addon,bizmodel</category>
|
||||
<abstract>false</abstract>
|
||||
<key_type>autoincrement</key_type>
|
||||
<db_table>attachment</db_table>
|
||||
<db_key_field>id</db_key_field>
|
||||
<db_final_class_field></db_final_class_field>
|
||||
<naming>
|
||||
<format>%1$s %2$s</format>
|
||||
<attributes>
|
||||
<attribute id="item_class"/>
|
||||
<attribute id="temp_id"/>
|
||||
</attributes>
|
||||
</naming>
|
||||
<display_template></display_template>
|
||||
<icon></icon>
|
||||
<reconciliation>
|
||||
<attributes>
|
||||
<attribute id=""/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="expire" xsi:type="AttributeDateTime">
|
||||
<sql>expire</sql>
|
||||
<default_value></default_value>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
<field id="temp_id" xsi:type="AttributeString">
|
||||
<sql>temp_id</sql>
|
||||
<default_value></default_value>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
</field>
|
||||
<field id="item_class" xsi:type="AttributeString">
|
||||
<sql>item_class</sql>
|
||||
<default_value></default_value>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
<field id="item_id" xsi:type="AttributeString">
|
||||
<sql>item_id</sql>
|
||||
<default_value></default_value>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
</field>
|
||||
<field id="item_org_id" xsi:type="AttributeInteger">
|
||||
<sql>item_org_id</sql>
|
||||
<default_value>0</default_value>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
</field>
|
||||
<field id="contents" xsi:type="AttributeBlob"/>
|
||||
</fields>
|
||||
<methods>
|
||||
<method id="MapContextParam">
|
||||
<comment><![CDATA[/**
|
||||
* Maps the given context parameter name to the appropriate filter/search code for this class
|
||||
* @param string $sContextParam Name of the context parameter, e.g. 'org_id'
|
||||
* @return string Filter code, e.g. 'customer_id'
|
||||
*/]]></comment>
|
||||
<static>true</static>
|
||||
<access>public</access>
|
||||
<type>Overload-ExNihilo</type>
|
||||
<code><![CDATA[ public static function MapContextParam($sContextParam)
|
||||
{
|
||||
if ($sContextParam == 'org_id')
|
||||
{
|
||||
return 'item_org_id';
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}]]></code>
|
||||
</method>
|
||||
<method id="SetItem">
|
||||
<comment><![CDATA[/**
|
||||
* Set/Update all of the '_item' fields
|
||||
* @param object $oItem Container item
|
||||
* @return void
|
||||
*/]]></comment>
|
||||
<static>false</static>
|
||||
<access>public</access>
|
||||
<type>Overload-ExNihilo</type>
|
||||
<code><![CDATA[ public function SetItem($oItem, $bUpdateOnChange = false)
|
||||
{
|
||||
$sClass = get_class($oItem);
|
||||
$iItemId = $oItem->GetKey();
|
||||
|
||||
$this->Set('item_class', $sClass);
|
||||
$this->Set('item_id', $iItemId);
|
||||
|
||||
$aCallSpec = array($sClass, 'MapContextParam');
|
||||
if (is_callable($aCallSpec))
|
||||
{
|
||||
$sAttCode = call_user_func($aCallSpec, 'org_id'); // Returns null when there is no mapping for this parameter
|
||||
if (MetaModel::IsValidAttCode($sClass, $sAttCode))
|
||||
{
|
||||
$iOrgId = $oItem->Get($sAttCode);
|
||||
if ($iOrgId > 0)
|
||||
{
|
||||
if ($iOrgId != $this->Get('item_org_id'))
|
||||
{
|
||||
$this->Set('item_org_id', $iOrgId);
|
||||
if ($bUpdateOnChange)
|
||||
{
|
||||
$this->DBUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}]]></code>
|
||||
</method>
|
||||
<method id="SetDefaultOrgId">
|
||||
<comment>/**
|
||||
* Give a default value for item_org_id (if relevant...)
|
||||
* @return void
|
||||
*/</comment>
|
||||
<static>false</static>
|
||||
<access>public</access>
|
||||
<type>Overload-ExNihilo</type>
|
||||
<code><![CDATA[ public function SetDefaultOrgId()
|
||||
{
|
||||
// First check that the organization CAN be fetched from the target class
|
||||
//
|
||||
$sClass = $this->Get('item_class');
|
||||
$aCallSpec = array($sClass, 'MapContextParam');
|
||||
if (is_callable($aCallSpec))
|
||||
{
|
||||
$sAttCode = call_user_func($aCallSpec, 'org_id'); // Returns null when there is no mapping for this parameter
|
||||
if (MetaModel::IsValidAttCode($sClass, $sAttCode))
|
||||
{
|
||||
// Second: check that the organization CAN be fetched from the current user
|
||||
//
|
||||
if (MetaModel::IsValidClass('Person'))
|
||||
{
|
||||
$aCallSpec = array($sClass, 'MapContextParam');
|
||||
if (is_callable($aCallSpec))
|
||||
{
|
||||
$sAttCode = call_user_func($aCallSpec, 'org_id'); // Returns null when there is no mapping for this parameter
|
||||
if (MetaModel::IsValidAttCode($sClass, $sAttCode))
|
||||
{
|
||||
// OK - try it
|
||||
//
|
||||
$oCurrentPerson = MetaModel::GetObject('Person', UserRights::GetContactId(), false);
|
||||
if ($oCurrentPerson)
|
||||
{
|
||||
$this->Set('item_org_id', $oCurrentPerson->Get($sAttCode));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}]]></code>
|
||||
</method>
|
||||
</methods>
|
||||
<presentation>
|
||||
<details>
|
||||
<items>
|
||||
<item>temp_id</item>
|
||||
<item>item_class</item>
|
||||
<item>item_id</item>
|
||||
<item>item_org_id</item>
|
||||
</items>
|
||||
</details>
|
||||
<search>
|
||||
<items>
|
||||
<item>temp_id</item>
|
||||
<item>item_class</item>
|
||||
<item>item_id</item>
|
||||
</items>
|
||||
</search>
|
||||
<list>
|
||||
<items>
|
||||
<item>temp_id</item>
|
||||
<item>item_class</item>
|
||||
<item>item_id</item>
|
||||
</items>
|
||||
</list>
|
||||
</presentation>
|
||||
</class>
|
||||
</classes>
|
||||
</itop_design>
|
||||
@@ -1,128 +0,0 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-attachments/1.0.0',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
'label' => 'Tickets attachments',
|
||||
'category' => 'business',
|
||||
|
||||
// Setup
|
||||
//
|
||||
'dependencies' => array(
|
||||
|
||||
),
|
||||
'mandatory' => false,
|
||||
'visible' => true,
|
||||
'installer' => 'AttachmentInstaller',
|
||||
|
||||
// Components
|
||||
//
|
||||
'datamodel' => array(
|
||||
'model.itop-attachments.php',
|
||||
'main.attachments.php',
|
||||
),
|
||||
'webservice' => array(
|
||||
|
||||
),
|
||||
'dictionary' => array(
|
||||
'en.dict.attachments.php',
|
||||
'fr.dict.attachments.php',
|
||||
),
|
||||
'data.struct' => array(
|
||||
// add your 'structure' definition XML files here,
|
||||
),
|
||||
'data.sample' => array(
|
||||
// add your sample data XML files here,
|
||||
),
|
||||
|
||||
// Documentation
|
||||
//
|
||||
'doc.manual_setup' => '', // hyperlink to manual setup documentation, if any
|
||||
'doc.more_information' => '', // hyperlink to more information, if any
|
||||
|
||||
// Default settings
|
||||
//
|
||||
'settings' => array(
|
||||
'allowed_classes' => array('Ticket'), // List of classes for which to manage "Attachments"
|
||||
'position' => 'relations', // Where to display the attachments: relations | properties
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
if (!class_exists('AttachmentInstaller'))
|
||||
{
|
||||
// Module installation handler
|
||||
//
|
||||
class AttachmentInstaller extends ModuleInstallerAPI
|
||||
{
|
||||
public static function BeforeWritingConfig(Config $oConfiguration)
|
||||
{
|
||||
// If you want to override/force some configuration values, do it here
|
||||
return $oConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler called before creating or upgrading the database schema
|
||||
* @param $oConfiguration Config The new configuration of the application
|
||||
* @param $sPreviousVersion string PRevious version number of the module (empty string in case of first install)
|
||||
* @param $sCurrentVersion string Current version number of the module
|
||||
*/
|
||||
public static function BeforeDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
// If you want to migrate data from one format to another, do it here
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler called after the creation/update of the database schema
|
||||
* @param $oConfiguration Config The new configuration of the application
|
||||
* @param $sPreviousVersion string PRevious version number of the module (empty string in case of first install)
|
||||
* @param $sCurrentVersion string Current version number of the module
|
||||
*/
|
||||
public static function AfterDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
// For each record having item_org_id unset,
|
||||
// get the org_id from the container object
|
||||
//
|
||||
// Prerequisite: change null into 0 (workaround to the fact that we cannot use IS NULL in OQL)
|
||||
SetupPage::log_info("Initializing attachment/item_org_id - null to zero");
|
||||
$sTableName = MetaModel::DBGetTable('Attachment');
|
||||
$sRepair = "UPDATE `$sTableName` SET `item_org_id` = 0 WHERE `item_org_id` IS NULL";
|
||||
CMDBSource::Query($sRepair);
|
||||
|
||||
SetupPage::log_info("Initializing attachment/item_org_id - zero to the container");
|
||||
$oSearch = DBObjectSearch::FromOQL("SELECT Attachment WHERE item_org_id = 0");
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
$iUpdated = 0;
|
||||
while ($oAttachment = $oSet->Fetch())
|
||||
{
|
||||
$oContainer = MetaModel::GetObject($oAttachment->Get('item_class'), $oAttachment->Get('item_id'), false /* must be found */, true /* allow all data */);
|
||||
if ($oContainer)
|
||||
{
|
||||
$oAttachment->SetItem($oContainer, true /*updateonchange*/);
|
||||
$iUpdated++;
|
||||
}
|
||||
}
|
||||
|
||||
SetupPage::log_info("Initializing attachment/item_org_id - $iUpdated records have been adjusted");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,17 +0,0 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
?>
|
||||
@@ -1,99 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-change-mgmt/1.0.0',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
'label' => 'Change Management',
|
||||
'category' => 'business',
|
||||
|
||||
// Setup
|
||||
//
|
||||
'dependencies' => array(
|
||||
'itop-config-mgmt/1.0.0',
|
||||
'itop-tickets/1.0.0',
|
||||
),
|
||||
'mandatory' => false,
|
||||
'visible' => true,
|
||||
'installer' => 'ChangeManagementInstaller',
|
||||
|
||||
// Components
|
||||
//
|
||||
'datamodel' => array(
|
||||
'model.itop-change-mgmt.php',
|
||||
'main.itop-change-mgmt.php',
|
||||
),
|
||||
'data.struct' => array(
|
||||
//'data.struct.itop-change-mgmt.xml',
|
||||
),
|
||||
'data.sample' => array(
|
||||
//'data.sample.itop-change-mgmt.xml',
|
||||
),
|
||||
|
||||
// Documentation
|
||||
//
|
||||
'doc.manual_setup' => '',
|
||||
'doc.more_information' => '/doc/itop-documentation.htm#ChangeMgmt',
|
||||
|
||||
// Default settings
|
||||
//
|
||||
'settings' => array(
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
if (!class_exists('ChangeManagementInstaller'))
|
||||
{
|
||||
// Module installation handler
|
||||
//
|
||||
class ChangeManagementInstaller extends ModuleInstallerAPI
|
||||
{
|
||||
public static function BeforeWritingConfig(Config $oConfiguration)
|
||||
{
|
||||
// If you want to override/force some configuration values, do it here
|
||||
return $oConfiguration;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler called before creating or upgrading the database schema
|
||||
* @param $oConfiguration Config The new configuration of the application
|
||||
* @param $sPreviousVersion string PRevious version number of the module (empty string in case of first install)
|
||||
* @param $sCurrentVersion string Current version number of the module
|
||||
*/
|
||||
public static function BeforeDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
// If you want to migrate data from one format to another, do it here
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler called after the creation/update of the database schema
|
||||
* @param $oConfiguration Config The new configuration of the application
|
||||
* @param $sPreviousVersion string PRevious version number of the module (empty string in case of first install)
|
||||
* @param $sCurrentVersion string Current version number of the module
|
||||
*/
|
||||
public static function AfterDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
// Bug #464 - start_date was both in Ticket and Change tables
|
||||
//
|
||||
$sSourceTable = 'change';
|
||||
$sSourceKeyField = 'id';
|
||||
|
||||
$sTargetTable = 'ticket';
|
||||
$sTargetKeyField = 'id';
|
||||
|
||||
$sField = 'start_date';
|
||||
|
||||
if (CMDBSource::IsField($sSourceTable, $sField) && CMDBSource::IsField($sTargetTable, $sField) && CMDBSource::IsField($sSourceTable, $sSourceKeyField) && CMDBSource::IsField($sTargetTable, $sTargetKeyField))
|
||||
{
|
||||
SetupPage::log_info("Issue #464 - Copying change/start_date into ticket/start_date");
|
||||
$sRepair = "UPDATE `$sTargetTable`, `$sSourceTable` SET `$sTargetTable`.`$sField` = `$sSourceTable`.`$sField` WHERE `$sTargetTable`.`$sField` IS NULL AND`$sTargetTable`.`$sTargetKeyField` = `$sSourceTable`.`$sSourceKeyField`";
|
||||
CMDBSource::Query($sRepair);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,27 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<dashboard xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<layout>DashboardLayoutTwoCols</layout>
|
||||
<title></title>
|
||||
<cells>
|
||||
<cell>
|
||||
<dashlet id="1" xsi:type="DashletGroupByBars">
|
||||
<title>UI-ChangeManagementOverview-ChangeByType</title>
|
||||
<query>SELECT Change</query>
|
||||
<group_by>finalclass</group_by>
|
||||
<style>bars</style>
|
||||
</dashlet>
|
||||
</cell>
|
||||
<cell>
|
||||
<dashlet id="2" xsi:type="DashletObjectList"/>
|
||||
<title>UI-ChangeManagementOverview-ChangeUnassigned</title>
|
||||
<query>SELECT Change WHERE status = 'new'</query>
|
||||
<menu>false</menu>
|
||||
</cell>
|
||||
<cell>
|
||||
<dashlet id="3" xsi:type="DashletObjectList"/>
|
||||
<title>UI-ChangeManagementOverview-ChangeWithOutage</title>
|
||||
<query>SELECT Change WHERE outage = 'yes'</query>
|
||||
<menu>false</menu>
|
||||
</cell>
|
||||
</cells>
|
||||
</dashboard>
|
||||
@@ -1,75 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<dashboard xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<layout>DashboardLayoutOneCol</layout>
|
||||
<title></title>
|
||||
<cells>
|
||||
<cell>
|
||||
<dashlet id="1" xsi:type="DashletHeaderDynamic">
|
||||
<title>Menu_ConfigManagement_Devices</title>
|
||||
<icon>itop-config-mgmt-1.0.0/images/server.png</icon>
|
||||
<subtitle>Menu_ConfigManagement_AllDevices</subtitle>
|
||||
<query>SELECT FunctionalCI</query>
|
||||
<group_by>status</group_by>
|
||||
<values>implementation,production,obsolete</values>
|
||||
</dashlet>
|
||||
<dashlet id="2" xsi:type="DashletBadge">
|
||||
<class>Server</class>
|
||||
</dashlet>
|
||||
<dashlet id="3" xsi:type="DashletBadge">
|
||||
<class>NetworkDevice</class>
|
||||
</dashlet>
|
||||
<dashlet id="5" xsi:type="DashletBadge">
|
||||
<class>PC</class>
|
||||
</dashlet>
|
||||
<dashlet id="6" xsi:type="DashletBadge">
|
||||
<class>MobilePhone</class>
|
||||
</dashlet>
|
||||
<dashlet id="7" xsi:type="DashletBadge">
|
||||
<class>Printer</class>
|
||||
</dashlet>
|
||||
</cell>
|
||||
<cell>
|
||||
<dashlet id="8" xsi:type="DashletHeaderStatic">
|
||||
<title>Menu:ConfigManagement:SWAndApps</title>
|
||||
<icon>itop-config-mgmt-1.0.0/images/application.png</icon>
|
||||
</dashlet>
|
||||
<dashlet id="9" xsi:type="DashletBadge">
|
||||
<class>ApplicationInstance</class>
|
||||
</dashlet>
|
||||
<dashlet id="10" xsi:type="DashletBadge">
|
||||
<class>DBServerInstance</class>
|
||||
</dashlet>
|
||||
<dashlet id="11" xsi:type="DashletBadge">
|
||||
<class>DatabaseInstance</class>
|
||||
</dashlet>
|
||||
<dashlet id="12" xsi:type="DashletBadge">
|
||||
<class>Patch</class>
|
||||
</dashlet>
|
||||
<dashlet id="13" xsi:type="DashletBadge">
|
||||
<class>Licence</class>
|
||||
</dashlet>
|
||||
</cell>
|
||||
<cell>
|
||||
<dashlet id="14" xsi:type="DashletHeaderStatic">
|
||||
<title>Menu:ConfigManagement:Misc</title>
|
||||
<icon>itop-config-mgmt-1.0.0/images/subnet.png</icon>
|
||||
</dashlet>
|
||||
<dashlet id="15" xsi:type="DashletBadge">
|
||||
<class>NetworkInterface</class>
|
||||
</dashlet>
|
||||
<dashlet id="16" xsi:type="DashletBadge">
|
||||
<class>Subnet</class>
|
||||
</dashlet>
|
||||
<dashlet id="17" xsi:type="DashletBadge">
|
||||
<class>BusinessProcess</class>
|
||||
</dashlet>
|
||||
<dashlet id="18" xsi:type="DashletBadge">
|
||||
<class>ApplicationSolution</class>
|
||||
</dashlet>
|
||||
<dashlet id="19" xsi:type="DashletBadge">
|
||||
<class>Group</class>
|
||||
</dashlet>
|
||||
</cell>
|
||||
</cells>
|
||||
</dashboard>
|
||||
|
||||
@@ -1,31 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<dashboard xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<title>UI:ConfigMgmtMenuOverview:Title</title>
|
||||
<layout>DashboardLayoutTwoCols</layout>
|
||||
<cells>
|
||||
<cell>
|
||||
<dashlet id="1" xsi:type="DashletGroupByPie">
|
||||
<title>UI-ConfigMgmtMenuOverview-FunctionalCIbyStatus</title>
|
||||
<query>SELECT FunctionalCI</query>
|
||||
<group_by>status</group_by>
|
||||
<style>pie</style>
|
||||
</dashlet>
|
||||
</cell>
|
||||
<cell>
|
||||
<dashlet id="2" xsi:type="DashletGroupByBars">
|
||||
<title>UI-ConfigMgmtMenuOverview-FunctionalCIByType</title>
|
||||
<query>SELECT FunctionalCI</query>
|
||||
<group_by>finalclass</group_by>
|
||||
<style>bars</style>
|
||||
</dashlet>
|
||||
</cell>
|
||||
<cell>
|
||||
<dashlet id="3" xsi:type="DashletGroupByTable">
|
||||
<title>UI-ConfigMgmtMenuOverview-FunctionalCIByType</title>
|
||||
<query>SELECT FunctionalCI</query>
|
||||
<group_by>finalclass</group_by>
|
||||
<style>table</style>
|
||||
</dashlet>
|
||||
</cell>
|
||||
</cells>
|
||||
</dashboard>
|
||||
@@ -1,32 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<dashboard xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<layout>DashboardLayoutOneCol</layout>
|
||||
<title></title>
|
||||
<cells>
|
||||
<cell>
|
||||
<dashlet id="1" xsi:type="DashletHeaderDynamic">
|
||||
<title>UI:ContactsMenu</title>
|
||||
<icon>itop-config-mgmt-1.0.0/images/team.png</icon>
|
||||
<subtitle>Menu:ConfigManagement:AllContacts</subtitle>
|
||||
<query>SELECT Contact</query>
|
||||
<group_by>status</group_by>
|
||||
<values>active,inactive</values>
|
||||
</dashlet>
|
||||
<dashlet id="2" xsi:type="DashletBadge">
|
||||
<class>Team</class>
|
||||
</dashlet>
|
||||
<dashlet id="3" xsi:type="DashletBadge">
|
||||
<class>Person</class>
|
||||
</dashlet>
|
||||
</cell>
|
||||
<cell>
|
||||
<dashlet id="4" xsi:type="DashletGroupByPie">
|
||||
<title>UI-ContactsMenu-ContactsByLocation</title>
|
||||
<query>SELECT Contact</query>
|
||||
<group_by>location_id</group_by>
|
||||
<style>pie</style>
|
||||
</dashlet>
|
||||
</cell>
|
||||
</cells>
|
||||
</dashboard>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,25 +0,0 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
MetaModel::RegisterRelation("impacts", array("description"=>"Objects impacted by", "verb_down"=>"impacts", "verb_up"=>"depends on"));
|
||||
MetaModel::RegisterRelation("depends on", array("description"=>"That impacts ", "verb_down"=>"depends on", "verb_up"=>"impacts"));
|
||||
|
||||
// Starting with iTop 1.2 you can restrict the list of organizations displayed in the drop-down list
|
||||
// by specifying a query as shown below. Note that this is NOT a security settings, since the
|
||||
// choice 'All Organizations' will always be available in the menu
|
||||
ApplicationMenu::SetFavoriteSiloQuery('SELECT Organization');
|
||||
|
||||
?>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,29 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<dashboard xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<title>UI:IncidentMgmtMenuOverview:Title</title>
|
||||
<layout>DashboardLayoutTwoCols</layout>
|
||||
<cells>
|
||||
<cell>
|
||||
<dashlet id="1" xsi:type="DashletGroupByBars">
|
||||
<title>UI-IncidentManagementOverview-IncidentByService</title>
|
||||
<query>SELECT Incident</query>
|
||||
<group_by>service_id</group_by>
|
||||
<style>bars</style>
|
||||
</dashlet>
|
||||
</cell>
|
||||
<cell>
|
||||
<dashlet id="2" xsi:type="DashletGroupByPie">
|
||||
<title>UI-IncidentManagementOverview-IncidentByPriority</title>
|
||||
<query>SELECT Incident</query>
|
||||
<group_by>priority</group_by>
|
||||
<style>pie</style>
|
||||
</dashlet>
|
||||
</cell>
|
||||
<cell>
|
||||
<dashlet id="3" xsi:type="DashletObjectList">
|
||||
<title>UI-IncidentManagementOverview-IncidentUnassigned</title>
|
||||
<query>SELECT Incident WHERE status IN ("new", "escalated_tto")</query>
|
||||
</dashlet>
|
||||
</cell>
|
||||
</cells>
|
||||
</dashboard>
|
||||
@@ -1,351 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<classes>
|
||||
<class id="KnownError" _delta="define">
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
<properties>
|
||||
<comment>/**
|
||||
* Description of known error
|
||||
*/</comment>
|
||||
<category>bizmodel,searchable,knownerrormgmt</category>
|
||||
<abstract>false</abstract>
|
||||
<key_type>autoincrement</key_type>
|
||||
<db_table>known_error</db_table>
|
||||
<db_key_field>id</db_key_field>
|
||||
<db_final_class_field></db_final_class_field>
|
||||
<naming>
|
||||
<format>%1$s</format>
|
||||
<attributes>
|
||||
<attribute id="name"/>
|
||||
</attributes>
|
||||
</naming>
|
||||
<display_template></display_template>
|
||||
<icon>images/known-error.png</icon>
|
||||
<reconciliation>
|
||||
<attributes>
|
||||
<attribute id="org_id"/>
|
||||
<attribute id="name"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="name" xsi:type="AttributeString">
|
||||
<sql>name</sql>
|
||||
<default_value></default_value>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
<field id="org_id" xsi:type="AttributeExternalKey">
|
||||
<sql>cust_id</sql>
|
||||
<target_class>Organization</target_class>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<on_target_delete>DEL_MANUAL</on_target_delete>
|
||||
<jointype></jointype>
|
||||
</field>
|
||||
<field id="cust_name" xsi:type="AttributeExternalField">
|
||||
<extkey_attcode>org_id</extkey_attcode>
|
||||
<target_attcode>name</target_attcode>
|
||||
</field>
|
||||
<field id="problem_id" xsi:type="AttributeExternalKey">
|
||||
<sql>problem_id</sql>
|
||||
<target_class>Problem</target_class>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
<on_target_delete>DEL_MANUAL</on_target_delete>
|
||||
<jointype></jointype>
|
||||
</field>
|
||||
<field id="problem_ref" xsi:type="AttributeExternalField">
|
||||
<extkey_attcode>problem_id</extkey_attcode>
|
||||
<target_attcode>ref</target_attcode>
|
||||
</field>
|
||||
<field id="symptom" xsi:type="AttributeText">
|
||||
<sql>symptom</sql>
|
||||
<default_value></default_value>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
<field id="root_cause" xsi:type="AttributeText">
|
||||
<sql>rootcause</sql>
|
||||
<default_value></default_value>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
</field>
|
||||
<field id="workaround" xsi:type="AttributeText">
|
||||
<sql>workaround</sql>
|
||||
<default_value></default_value>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
</field>
|
||||
<field id="solution" xsi:type="AttributeText">
|
||||
<sql>solution</sql>
|
||||
<default_value></default_value>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
</field>
|
||||
<field id="error_code" xsi:type="AttributeString">
|
||||
<sql>error_code</sql>
|
||||
<default_value></default_value>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
</field>
|
||||
<field id="domain" xsi:type="AttributeEnum">
|
||||
<values>
|
||||
<value>Network</value>
|
||||
<value>Server</value>
|
||||
<value>Application</value>
|
||||
<value>Desktop</value>
|
||||
</values>
|
||||
<sql>domain</sql>
|
||||
<default_value>Application</default_value>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
<field id="vendor" xsi:type="AttributeString">
|
||||
<sql>vendor</sql>
|
||||
<default_value></default_value>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
</field>
|
||||
<field id="model" xsi:type="AttributeString">
|
||||
<sql>model</sql>
|
||||
<default_value></default_value>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
</field>
|
||||
<field id="version" xsi:type="AttributeString">
|
||||
<sql>version</sql>
|
||||
<default_value></default_value>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
</field>
|
||||
<field id="ci_list" xsi:type="AttributeLinkedSetIndirect">
|
||||
<linked_class>lnkInfraError</linked_class>
|
||||
<ext_key_to_me>error_id</ext_key_to_me>
|
||||
<count_min>0</count_min>
|
||||
<count_max>0</count_max>
|
||||
<ext_key_to_remote>infra_id</ext_key_to_remote>
|
||||
</field>
|
||||
<field id="document_list" xsi:type="AttributeLinkedSetIndirect">
|
||||
<linked_class>lnkDocumentError</linked_class>
|
||||
<ext_key_to_me>error_id</ext_key_to_me>
|
||||
<count_min>0</count_min>
|
||||
<count_max>0</count_max>
|
||||
<ext_key_to_remote>doc_id</ext_key_to_remote>
|
||||
</field>
|
||||
</fields>
|
||||
<methods/>
|
||||
<presentation>
|
||||
<details>
|
||||
<items>
|
||||
<item>name</item>
|
||||
<item>org_id</item>
|
||||
<item>problem_id</item>
|
||||
<item>error_code</item>
|
||||
<item>domain</item>
|
||||
<item>vendor</item>
|
||||
<item>model</item>
|
||||
<item>version</item>
|
||||
<item>symptom</item>
|
||||
<item>root_cause</item>
|
||||
<item>workaround</item>
|
||||
<item>solution</item>
|
||||
<item>ci_list</item>
|
||||
<item>document_list</item>
|
||||
</items>
|
||||
</details>
|
||||
<search>
|
||||
<items>
|
||||
<item>name</item>
|
||||
<item>org_id</item>
|
||||
<item>problem_id</item>
|
||||
<item>error_code</item>
|
||||
<item>domain</item>
|
||||
<item>symptom</item>
|
||||
</items>
|
||||
</search>
|
||||
<list>
|
||||
<items>
|
||||
<item>org_id</item>
|
||||
<item>problem_id</item>
|
||||
<item>error_code</item>
|
||||
<item>symptom</item>
|
||||
</items>
|
||||
</list>
|
||||
</presentation>
|
||||
</class>
|
||||
<class id="lnkInfraError" _delta="define">
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
<properties>
|
||||
<comment>/**
|
||||
* n-n link between any Infra and a Known Error
|
||||
*/</comment>
|
||||
<is_link>1</is_link>
|
||||
<category>bizmodel,searchable,knownerrormgmt,lnkknownerror</category>
|
||||
<abstract>false</abstract>
|
||||
<key_type>autoincrement</key_type>
|
||||
<db_table>infra_error_links</db_table>
|
||||
<db_key_field>link_id</db_key_field>
|
||||
<db_final_class_field></db_final_class_field>
|
||||
<naming>
|
||||
<format>lnkInfraError</format>
|
||||
<attributes/>
|
||||
</naming>
|
||||
<display_template></display_template>
|
||||
<icon></icon>
|
||||
<reconciliation>
|
||||
<attributes>
|
||||
<attribute id="infra_id"/>
|
||||
<attribute id="error_id"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="infra_id" xsi:type="AttributeExternalKey">
|
||||
<sql>infra_id</sql>
|
||||
<target_class>FunctionalCI</target_class>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<on_target_delete>DEL_AUTO</on_target_delete>
|
||||
<jointype></jointype>
|
||||
</field>
|
||||
<field id="infra_name" xsi:type="AttributeExternalField">
|
||||
<extkey_attcode>infra_id</extkey_attcode>
|
||||
<target_attcode>name</target_attcode>
|
||||
</field>
|
||||
<field id="infra_status" xsi:type="AttributeExternalField">
|
||||
<extkey_attcode>infra_id</extkey_attcode>
|
||||
<target_attcode>status</target_attcode>
|
||||
</field>
|
||||
<field id="error_id" xsi:type="AttributeExternalKey">
|
||||
<sql>error_id</sql>
|
||||
<target_class>KnownError</target_class>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<on_target_delete>DEL_AUTO</on_target_delete>
|
||||
<jointype></jointype>
|
||||
</field>
|
||||
<field id="error_name" xsi:type="AttributeExternalField">
|
||||
<extkey_attcode>error_id</extkey_attcode>
|
||||
<target_attcode>name</target_attcode>
|
||||
</field>
|
||||
<field id="reason" xsi:type="AttributeString">
|
||||
<sql>dummy</sql>
|
||||
<default_value></default_value>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
</field>
|
||||
</fields>
|
||||
<methods/>
|
||||
<presentation>
|
||||
<details>
|
||||
<items>
|
||||
<item>infra_id</item>
|
||||
<item>error_id</item>
|
||||
<item>reason</item>
|
||||
</items>
|
||||
</details>
|
||||
<search>
|
||||
<items>
|
||||
<item>infra_id</item>
|
||||
<item>error_id</item>
|
||||
</items>
|
||||
</search>
|
||||
<list>
|
||||
<items>
|
||||
<item>infra_id</item>
|
||||
<item>infra_status</item>
|
||||
<item>error_id</item>
|
||||
<item>reason</item>
|
||||
</items>
|
||||
</list>
|
||||
</presentation>
|
||||
</class>
|
||||
<class id="lnkDocumentError" _delta="define">
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
<properties>
|
||||
<comment>/**
|
||||
* n-n link between any Contract and a Document
|
||||
*/</comment>
|
||||
<is_link>1</is_link>
|
||||
<category>bizmodel,searchable,knownerrormgmt,lnkknownerror</category>
|
||||
<abstract>false</abstract>
|
||||
<key_type>autoincrement</key_type>
|
||||
<db_table>documents_error_link</db_table>
|
||||
<db_key_field>link_id</db_key_field>
|
||||
<db_final_class_field></db_final_class_field>
|
||||
<naming>
|
||||
<format>%1$s</format>
|
||||
<attributes>
|
||||
<attribute id="link_type"/>
|
||||
</attributes>
|
||||
</naming>
|
||||
<display_template>../business/templates/default.html</display_template>
|
||||
<icon></icon>
|
||||
<reconciliation>
|
||||
<attributes>
|
||||
<attribute id="doc_id"/>
|
||||
<attribute id="error_id"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="doc_id" xsi:type="AttributeExternalKey">
|
||||
<sql>doc_id</sql>
|
||||
<target_class>Document</target_class>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<on_target_delete>DEL_AUTO</on_target_delete>
|
||||
<jointype></jointype>
|
||||
</field>
|
||||
<field id="doc_name" xsi:type="AttributeExternalField">
|
||||
<extkey_attcode>doc_id</extkey_attcode>
|
||||
<target_attcode>name</target_attcode>
|
||||
</field>
|
||||
<field id="error_id" xsi:type="AttributeExternalKey">
|
||||
<sql>error_id</sql>
|
||||
<target_class>KnownError</target_class>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<on_target_delete>DEL_AUTO</on_target_delete>
|
||||
<jointype></jointype>
|
||||
</field>
|
||||
<field id="error_name" xsi:type="AttributeExternalField">
|
||||
<extkey_attcode>error_id</extkey_attcode>
|
||||
<target_attcode>name</target_attcode>
|
||||
</field>
|
||||
<field id="link_type" xsi:type="AttributeString">
|
||||
<sql>link_type</sql>
|
||||
<default_value></default_value>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
</field>
|
||||
</fields>
|
||||
<methods/>
|
||||
<presentation>
|
||||
<details>
|
||||
<items>
|
||||
<item>doc_id</item>
|
||||
<item>error_name</item>
|
||||
<item>link_type</item>
|
||||
</items>
|
||||
</details>
|
||||
<list>
|
||||
<items>
|
||||
<item>doc_id</item>
|
||||
<item>error_name</item>
|
||||
<item>link_type</item>
|
||||
</items>
|
||||
</list>
|
||||
</presentation>
|
||||
</class>
|
||||
</classes>
|
||||
<menus>
|
||||
<menu id="ProblemManagement" xsi:type="MenuGroup" _delta="define">
|
||||
<rank>42</rank>
|
||||
</menu>
|
||||
<menu id="NewError" xsi:type="NewObjectMenuNode" _delta="define">
|
||||
<rank>3</rank>
|
||||
<parent>ProblemManagement</parent>
|
||||
<class>KnownError</class>
|
||||
</menu>
|
||||
<menu id="SearchError" xsi:type="SearchMenuNode" _delta="define">
|
||||
<rank>4</rank>
|
||||
<parent>ProblemManagement</parent>
|
||||
<class>KnownError</class>
|
||||
</menu>
|
||||
<menu id="Problem:Shortcuts" xsi:type="TemplateMenuNode" _delta="define">
|
||||
<rank>5</rank>
|
||||
<parent>ProblemManagement</parent>
|
||||
<template_file></template_file>
|
||||
</menu>
|
||||
<menu id="Problem:KnownErrors" xsi:type="OQLMenuNode" _delta="define">
|
||||
<rank>3</rank>
|
||||
<parent>Problem:Shortcuts</parent>
|
||||
<oql>SELECT KnownError</oql>
|
||||
<do_search>1</do_search>
|
||||
</menu>
|
||||
</menus>
|
||||
</itop_design>
|
||||
@@ -1,17 +0,0 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
?>
|
||||
@@ -1,688 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<classes>
|
||||
<class id="Problem" _delta="define">
|
||||
<parent>Ticket</parent>
|
||||
<properties>
|
||||
<comment><![CDATA[/**
|
||||
* Persistent classes for a CMDB
|
||||
*
|
||||
* @author Erwan Taloc <erwan.taloc@combodo.com>
|
||||
* @author Romain Quetiez <romain.quetiez@combodo.com>
|
||||
* @author Denis Flaven <denis.flaven@combodo.com>
|
||||
* @license http://www.opensource.org/licenses/gpl-3.0.html LGPL
|
||||
*/]]></comment>
|
||||
<category>bizmodel,searchable,problemmgmt</category>
|
||||
<abstract>false</abstract>
|
||||
<key_type>autoincrement</key_type>
|
||||
<db_table>ticket_problem</db_table>
|
||||
<db_key_field>id</db_key_field>
|
||||
<db_final_class_field></db_final_class_field>
|
||||
<naming>
|
||||
<format>%1$s</format>
|
||||
<attributes>
|
||||
<attribute id="ref"/>
|
||||
</attributes>
|
||||
</naming>
|
||||
<display_template></display_template>
|
||||
<icon>images/problem.png</icon>
|
||||
<reconciliation>
|
||||
<attributes>
|
||||
<attribute id="ref"/>
|
||||
</attributes>
|
||||
</reconciliation>
|
||||
<order>
|
||||
<columns>
|
||||
<column id="ref" order="0">
|
||||
<ascending>false</ascending>
|
||||
</column>
|
||||
</columns>
|
||||
</order>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="status" xsi:type="AttributeEnum">
|
||||
<values>
|
||||
<value>new</value>
|
||||
<value>assigned</value>
|
||||
<value>resolved</value>
|
||||
<value>closed</value>
|
||||
</values>
|
||||
<sql>status</sql>
|
||||
<default_value>new</default_value>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
<field id="org_id" xsi:type="AttributeExternalKey">
|
||||
<sql>org_id</sql>
|
||||
<target_class>Organization</target_class>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<on_target_delete>DEL_AUTO</on_target_delete>
|
||||
<jointype></jointype>
|
||||
</field>
|
||||
<field id="org_name" xsi:type="AttributeExternalField">
|
||||
<extkey_attcode>org_id</extkey_attcode>
|
||||
<target_attcode>name</target_attcode>
|
||||
</field>
|
||||
<field id="service_id" xsi:type="AttributeExternalKey">
|
||||
<filter><![CDATA[SELECT Service AS s JOIN SLA AS sla ON sla.service_id=s.id JOIN lnkContractToSLA AS ln ON ln.sla_id=sla.id JOIN CustomerContract AS cc ON ln.contract_id=cc.id WHERE cc.org_id =:this->org_id]]></filter>
|
||||
<dependencies>
|
||||
<attribute id="org_id"/>
|
||||
</dependencies>
|
||||
<sql>service_id</sql>
|
||||
<target_class>Service</target_class>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<on_target_delete>DEL_MANUAL</on_target_delete>
|
||||
<jointype></jointype>
|
||||
</field>
|
||||
<field id="service_name" xsi:type="AttributeExternalField">
|
||||
<extkey_attcode>service_id</extkey_attcode>
|
||||
<target_attcode>name</target_attcode>
|
||||
</field>
|
||||
<field id="servicesubcategory_id" xsi:type="AttributeExternalKey">
|
||||
<filter><![CDATA[SELECT ServiceSubcategory WHERE service_id = :this->service_id]]></filter>
|
||||
<dependencies>
|
||||
<attribute id="service_id"/>
|
||||
</dependencies>
|
||||
<sql>servicesubcategory_id</sql>
|
||||
<target_class>ServiceSubcategory</target_class>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<on_target_delete>DEL_MANUAL</on_target_delete>
|
||||
<jointype></jointype>
|
||||
</field>
|
||||
<field id="servicesubcategory_name" xsi:type="AttributeExternalField">
|
||||
<extkey_attcode>servicesubcategory_id</extkey_attcode>
|
||||
<target_attcode>name</target_attcode>
|
||||
</field>
|
||||
<field id="product" xsi:type="AttributeString">
|
||||
<sql>product</sql>
|
||||
<default_value></default_value>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
</field>
|
||||
<field id="impact" xsi:type="AttributeEnum">
|
||||
<values>
|
||||
<value>1</value>
|
||||
<value>2</value>
|
||||
<value>3</value>
|
||||
</values>
|
||||
<sql>impact</sql>
|
||||
<default_value>1</default_value>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
<field id="urgency" xsi:type="AttributeEnum">
|
||||
<values>
|
||||
<value>1</value>
|
||||
<value>2</value>
|
||||
<value>3</value>
|
||||
</values>
|
||||
<sql>urgency</sql>
|
||||
<default_value>1</default_value>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
<field id="priority" xsi:type="AttributeEnum">
|
||||
<values>
|
||||
<value>1</value>
|
||||
<value>2</value>
|
||||
<value>3</value>
|
||||
</values>
|
||||
<sql>priority</sql>
|
||||
<default_value>1</default_value>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
<field id="workgroup_id" xsi:type="AttributeExternalKey">
|
||||
<filter><![CDATA[SELECT Team AS t JOIN CustomerContract AS cc ON cc.support_team_id=t.id JOIN lnkContractToSLA AS ln ON ln.contract_id=cc.id JOIN SLA AS sla ON ln.sla_id=sla.id WHERE sla.service_id = :this->service_id AND cc.org_id = :this->org_id]]></filter>
|
||||
<dependencies>
|
||||
<attribute id="org_id"/>
|
||||
<attribute id="service_id"/>
|
||||
</dependencies>
|
||||
<sql>workgroup_id</sql>
|
||||
<target_class>Team</target_class>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
<on_target_delete>DEL_MANUAL</on_target_delete>
|
||||
<jointype></jointype>
|
||||
</field>
|
||||
<field id="workgroup_name" xsi:type="AttributeExternalField">
|
||||
<extkey_attcode>workgroup_id</extkey_attcode>
|
||||
<target_attcode>name</target_attcode>
|
||||
</field>
|
||||
<field id="agent_id" xsi:type="AttributeExternalKey">
|
||||
<filter><![CDATA[SELECT Person AS p JOIN lnkTeamToContact AS l ON l.contact_id=p.id JOIN Team AS t ON l.team_id=t.id WHERE t.id = :this->workgroup_id]]></filter>
|
||||
<dependencies>
|
||||
<attribute id="workgroup_id"/>
|
||||
</dependencies>
|
||||
<sql>agent_id</sql>
|
||||
<target_class>Person</target_class>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
<on_target_delete>DEL_MANUAL</on_target_delete>
|
||||
<jointype></jointype>
|
||||
</field>
|
||||
<field id="agent_name" xsi:type="AttributeExternalField">
|
||||
<extkey_attcode>agent_id</extkey_attcode>
|
||||
<target_attcode>name</target_attcode>
|
||||
</field>
|
||||
<field id="agent_email" xsi:type="AttributeExternalField">
|
||||
<extkey_attcode>agent_id</extkey_attcode>
|
||||
<target_attcode>email</target_attcode>
|
||||
</field>
|
||||
<field id="related_change_id" xsi:type="AttributeExternalKey">
|
||||
<sql>related_change_id</sql>
|
||||
<target_class>Change</target_class>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
<on_target_delete>DEL_MANUAL</on_target_delete>
|
||||
<jointype></jointype>
|
||||
</field>
|
||||
<field id="related_change_ref" xsi:type="AttributeExternalField">
|
||||
<extkey_attcode>related_change_id</extkey_attcode>
|
||||
<target_attcode>ref</target_attcode>
|
||||
</field>
|
||||
<field id="close_date" xsi:type="AttributeDateTime">
|
||||
<sql>close_date</sql>
|
||||
<default_value></default_value>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
</field>
|
||||
<field id="last_update" xsi:type="AttributeDateTime">
|
||||
<sql>last_update</sql>
|
||||
<default_value></default_value>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
</field>
|
||||
<field id="assignment_date" xsi:type="AttributeDateTime">
|
||||
<sql>assignment_date</sql>
|
||||
<default_value></default_value>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
</field>
|
||||
<field id="resolution_date" xsi:type="AttributeDateTime">
|
||||
<sql>resolution_date</sql>
|
||||
<default_value></default_value>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
</field>
|
||||
<field id="knownerrors_list" xsi:type="AttributeLinkedSet">
|
||||
<linked_class>KnownError</linked_class>
|
||||
<ext_key_to_me>problem_id</ext_key_to_me>
|
||||
<count_min>0</count_min>
|
||||
<count_max>0</count_max>
|
||||
</field>
|
||||
</fields>
|
||||
<lifecycle>
|
||||
<attribute>status</attribute>
|
||||
<stimuli>
|
||||
<stimulus id="ev_assign" xsi:type="StimulusUserAction"/>
|
||||
<stimulus id="ev_reassign" xsi:type="StimulusUserAction"/>
|
||||
<stimulus id="ev_resolve" xsi:type="StimulusUserAction"/>
|
||||
<stimulus id="ev_close" xsi:type="StimulusUserAction"/>
|
||||
</stimuli>
|
||||
<states>
|
||||
<state id="new">
|
||||
<flags>
|
||||
<attribute id="ref">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="description">
|
||||
<must_change/>
|
||||
</attribute>
|
||||
<attribute id="ticket_log">
|
||||
<hidden/>
|
||||
</attribute>
|
||||
<attribute id="start_date">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="org_id">
|
||||
<must_change/>
|
||||
</attribute>
|
||||
<attribute id="service_id">
|
||||
<must_change/>
|
||||
</attribute>
|
||||
<attribute id="servicesubcategory_id">
|
||||
<must_change/>
|
||||
</attribute>
|
||||
<attribute id="product">
|
||||
<must_prompt/>
|
||||
</attribute>
|
||||
<attribute id="impact">
|
||||
<must_change/>
|
||||
</attribute>
|
||||
<attribute id="urgency">
|
||||
<must_change/>
|
||||
</attribute>
|
||||
<attribute id="priority">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="workgroup_id">
|
||||
<must_change/>
|
||||
</attribute>
|
||||
<attribute id="agent_id">
|
||||
<hidden/>
|
||||
</attribute>
|
||||
<attribute id="agent_email">
|
||||
<hidden/>
|
||||
</attribute>
|
||||
<attribute id="related_change_id">
|
||||
<hidden/>
|
||||
</attribute>
|
||||
<attribute id="close_date">
|
||||
<hidden/>
|
||||
</attribute>
|
||||
<attribute id="last_update">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="assignment_date">
|
||||
<hidden/>
|
||||
</attribute>
|
||||
<attribute id="resolution_date">
|
||||
<hidden/>
|
||||
</attribute>
|
||||
</flags>
|
||||
<transitions>
|
||||
<transition>
|
||||
<stimulus>ev_assign</stimulus>
|
||||
<target>assigned</target>
|
||||
<actions>
|
||||
<action>
|
||||
<verb>SetAssignedDate</verb>
|
||||
</action>
|
||||
</actions>
|
||||
</transition>
|
||||
</transitions>
|
||||
</state>
|
||||
<state id="assigned">
|
||||
<flags>
|
||||
<attribute id="ref">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="title">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="description">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="start_date">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="org_id">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="priority">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="workgroup_id">
|
||||
<mandatory/>
|
||||
<must_prompt/>
|
||||
</attribute>
|
||||
<attribute id="agent_id">
|
||||
<mandatory/>
|
||||
<must_prompt/>
|
||||
</attribute>
|
||||
<attribute id="agent_email">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="close_date">
|
||||
<hidden/>
|
||||
</attribute>
|
||||
<attribute id="last_update">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="assignment_date">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="resolution_date">
|
||||
<hidden/>
|
||||
</attribute>
|
||||
</flags>
|
||||
<transitions>
|
||||
<transition>
|
||||
<stimulus>ev_reassign</stimulus>
|
||||
<target>assigned</target>
|
||||
<actions/>
|
||||
</transition>
|
||||
<transition>
|
||||
<stimulus>ev_resolve</stimulus>
|
||||
<target>resolved</target>
|
||||
<actions>
|
||||
<action>
|
||||
<verb>SetResolveDate</verb>
|
||||
</action>
|
||||
</actions>
|
||||
</transition>
|
||||
</transitions>
|
||||
</state>
|
||||
<state id="resolved">
|
||||
<flags>
|
||||
<attribute id="ref">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="title">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="description">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="start_date">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="org_id">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="service_id">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="servicesubcategory_id">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="product">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="impact">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="urgency">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="priority">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="workgroup_id">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="agent_id">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="agent_email">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="close_date">
|
||||
<hidden/>
|
||||
</attribute>
|
||||
<attribute id="last_update">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="assignment_date">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="resolution_date">
|
||||
<hidden/>
|
||||
</attribute>
|
||||
</flags>
|
||||
<transitions>
|
||||
<transition>
|
||||
<stimulus>ev_reassign</stimulus>
|
||||
<target>assigned</target>
|
||||
<actions/>
|
||||
</transition>
|
||||
<transition>
|
||||
<stimulus>ev_close</stimulus>
|
||||
<target>closed</target>
|
||||
<actions>
|
||||
<action>
|
||||
<verb>SetClosureDate</verb>
|
||||
</action>
|
||||
</actions>
|
||||
</transition>
|
||||
</transitions>
|
||||
</state>
|
||||
<state id="closed">
|
||||
<flags>
|
||||
<attribute id="ref">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="title">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="description">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="ticket_log">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="start_date">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="org_id">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="service_id">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="servicesubcategory_id">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="product">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="impact">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="urgency">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="priority">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="workgroup_id">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="agent_id">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="agent_email">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="close_date">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="last_update">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="assignment_date">
|
||||
<read_only/>
|
||||
</attribute>
|
||||
<attribute id="resolution_date">
|
||||
<hidden/>
|
||||
</attribute>
|
||||
</flags>
|
||||
<transitions/>
|
||||
</state>
|
||||
</states>
|
||||
</lifecycle>
|
||||
<methods>
|
||||
<method id="SetAssignedDate">
|
||||
<static>false</static>
|
||||
<access>public</access>
|
||||
<type>LifecycleAction</type>
|
||||
<code><![CDATA[ public function SetAssignedDate($sStimulusCode)
|
||||
{
|
||||
$this->Set('assignment_date', time());
|
||||
return true;
|
||||
}]]></code>
|
||||
</method>
|
||||
<method id="SetResolveDate">
|
||||
<static>false</static>
|
||||
<access>public</access>
|
||||
<type>LifecycleAction</type>
|
||||
<code><![CDATA[ public function SetResolveDate($sStimulusCode)
|
||||
{
|
||||
$this->Set('resolution_date', time());
|
||||
return true;
|
||||
}]]></code>
|
||||
</method>
|
||||
<method id="SetClosureDate">
|
||||
<static>false</static>
|
||||
<access>public</access>
|
||||
<type>LifecycleAction</type>
|
||||
<code><![CDATA[ public function SetClosureDate($sStimulusCode)
|
||||
{
|
||||
$this->Set('close_date', time());
|
||||
return true;
|
||||
}]]></code>
|
||||
</method>
|
||||
<method id="ComputePriority">
|
||||
<comment>/** Compute the priority of the ticket based on its impact and urgency
|
||||
* @return integer The priority of the ticket 1(high) .. 3(low)
|
||||
*/</comment>
|
||||
<static>false</static>
|
||||
<access>public</access>
|
||||
<type>LifecycleAction</type>
|
||||
<code><![CDATA[ public function ComputePriority()
|
||||
{
|
||||
// priority[impact][urgency]
|
||||
$aPriorities = array(
|
||||
// single person
|
||||
1 => array(
|
||||
1 => 1,
|
||||
2 => 1,
|
||||
3 => 2,
|
||||
),
|
||||
// a group
|
||||
2 => array(
|
||||
1 => 1,
|
||||
2 => 2,
|
||||
3 => 3,
|
||||
),
|
||||
// a departement!
|
||||
3 => array(
|
||||
1 => 2,
|
||||
2 => 3,
|
||||
3 => 3,
|
||||
),
|
||||
);
|
||||
$iPriority = $aPriorities[(int)$this->Get('impact')][(int)$this->Get('urgency')];
|
||||
return $iPriority;
|
||||
}]]></code>
|
||||
</method>
|
||||
<method id="ComputeValues">
|
||||
<static>false</static>
|
||||
<access>public</access>
|
||||
<type>Overload-DBObject</type>
|
||||
<code><![CDATA[ public function ComputeValues()
|
||||
{
|
||||
// Compute the priority of the ticket
|
||||
$this->Set('priority', $this->ComputePriority());
|
||||
|
||||
$sCurrRef = $this->Get('ref');
|
||||
if (strlen($sCurrRef) == 0)
|
||||
{
|
||||
$iKey = $this->GetKey();
|
||||
if ($iKey < 0)
|
||||
{
|
||||
// Object not yet in the Database
|
||||
$iKey = MetaModel::GetNextKey(get_class($this));
|
||||
}
|
||||
$sName = sprintf('P-%06d', $iKey);
|
||||
$this->Set('ref', $sName);
|
||||
}
|
||||
}]]></code>
|
||||
</method>
|
||||
</methods>
|
||||
<presentation>
|
||||
<details>
|
||||
<items>
|
||||
<item>document_list</item>
|
||||
<item>ci_list</item>
|
||||
<item>contact_list</item>
|
||||
<item>incident_list</item>
|
||||
<item id="col:col1">
|
||||
<items>
|
||||
<item id="fieldset:Ticket:baseinfo">
|
||||
<items>
|
||||
<item>ref</item>
|
||||
<item>title</item>
|
||||
<item>org_id</item>
|
||||
<item>status</item>
|
||||
<item>priority</item>
|
||||
<item>service_id</item>
|
||||
<item>servicesubcategory_id</item>
|
||||
<item>product</item>
|
||||
</items>
|
||||
</item>
|
||||
<item id="fieldset:Ticket:moreinfo">
|
||||
<items>
|
||||
<item>impact</item>
|
||||
<item>urgency</item>
|
||||
<item>description</item>
|
||||
</items>
|
||||
</item>
|
||||
</items>
|
||||
</item>
|
||||
<item id="col:col2">
|
||||
<items>
|
||||
<item id="fieldset:Ticket:date">
|
||||
<items>
|
||||
<item>start_date</item>
|
||||
<item>last_update</item>
|
||||
<item>assignment_date</item>
|
||||
<item>close_date</item>
|
||||
</items>
|
||||
</item>
|
||||
<item id="fieldset:Ticket:contact">
|
||||
<items>
|
||||
<item>workgroup_id</item>
|
||||
<item>agent_id</item>
|
||||
</items>
|
||||
</item>
|
||||
<item id="fieldset:Ticket:relation">
|
||||
<items>
|
||||
<item>related_change_id</item>
|
||||
</items>
|
||||
</item>
|
||||
</items>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
<search>
|
||||
<items>
|
||||
<item>ref</item>
|
||||
<item>title</item>
|
||||
<item>org_id</item>
|
||||
<item>start_date</item>
|
||||
<item>status</item>
|
||||
<item>service_id</item>
|
||||
<item>servicesubcategory_id</item>
|
||||
<item>product</item>
|
||||
<item>impact</item>
|
||||
<item>urgency</item>
|
||||
<item>priority</item>
|
||||
<item>workgroup_id</item>
|
||||
<item>agent_id</item>
|
||||
<item>agent_email</item>
|
||||
<item>close_date</item>
|
||||
</items>
|
||||
</search>
|
||||
<list>
|
||||
<items>
|
||||
<item>title</item>
|
||||
<item>org_id</item>
|
||||
<item>start_date</item>
|
||||
<item>status</item>
|
||||
<item>service_id</item>
|
||||
<item>priority</item>
|
||||
</items>
|
||||
</list>
|
||||
</presentation>
|
||||
</class>
|
||||
</classes>
|
||||
<menus>
|
||||
<menu id="Problem:Overview" xsi:type="DashboardMenuNode" _delta="define">
|
||||
<rank>0</rank>
|
||||
<parent>ProblemManagement</parent>
|
||||
<definition_file>overview.xml</definition_file>
|
||||
</menu>
|
||||
<menu id="NewProblem" xsi:type="NewObjectMenuNode" _delta="define">
|
||||
<rank>1</rank>
|
||||
<parent>ProblemManagement</parent>
|
||||
<class>Problem</class>
|
||||
</menu>
|
||||
<menu id="SearchProblems" xsi:type="SearchMenuNode" _delta="define">
|
||||
<rank>2</rank>
|
||||
<parent>ProblemManagement</parent>
|
||||
<class>Problem</class>
|
||||
</menu>
|
||||
<menu id="Problem:MyProblems" xsi:type="OQLMenuNode" _delta="define">
|
||||
<rank>1</rank>
|
||||
<parent>Problem:Shortcuts</parent>
|
||||
<oql><![CDATA[SELECT Problem WHERE agent_id = :current_contact_id AND status NOT IN ("closed", "resolved")]]></oql>
|
||||
<do_search></do_search>
|
||||
</menu>
|
||||
<menu id="Problem:OpenProblems" xsi:type="OQLMenuNode" _delta="define">
|
||||
<rank>2</rank>
|
||||
<parent>Problem:Shortcuts</parent>
|
||||
<oql><![CDATA[SELECT Problem WHERE status IN ("new", "assigned", "resolved")]]></oql>
|
||||
<do_search></do_search>
|
||||
</menu>
|
||||
</menus>
|
||||
</itop_design>
|
||||
@@ -1,30 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<dashboard xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<layout>DashboardLayoutTwoCols</layout>
|
||||
<title></title>
|
||||
<cells>
|
||||
<cell>
|
||||
<dashlet id="1" xsi:type="DashletGroupByBars">
|
||||
<title>UI-ProblemManagementOverview-ProblemByService</title>
|
||||
<query>SELECT Problem</query>
|
||||
<group_by>service_id</group_by>
|
||||
<style>bars</style>
|
||||
</dashlet>
|
||||
</cell>
|
||||
<cell>
|
||||
<dashlet id="2" xsi:type="DashletGroupByPie">
|
||||
<title>UI-ProblemManagementOverview-ProblemByPriority</title>
|
||||
<query>SELECT Problem</query>
|
||||
<group_by>priority</group_by>
|
||||
<style>pie</style>
|
||||
</dashlet>
|
||||
</cell>
|
||||
<cell>
|
||||
<dashlet id="3" xsi:type="DashletObjectList"/>
|
||||
<title>UI-ProblemManagementOverview-ProblemUnassigned</title>
|
||||
<query>SELECT Problem WHERE status IN ("new")</query>
|
||||
<menu>true</menu>
|
||||
</cell>
|
||||
</cells>
|
||||
</dashboard>
|
||||
|
||||
@@ -1,575 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<classes/>
|
||||
<user_rights>
|
||||
<groups>
|
||||
<group id="General" _delta="define">
|
||||
<classes>
|
||||
<class id="Organization"/>
|
||||
<class id="Location"/>
|
||||
<class id="Contact"/>
|
||||
<class id="Person"/>
|
||||
<class id="Team"/>
|
||||
<class id="lnkTeamToContact"/>
|
||||
</classes>
|
||||
</group>
|
||||
<group id="Documentation" _delta="define">
|
||||
<classes>
|
||||
<class id="Document"/>
|
||||
<class id="WebDoc"/>
|
||||
<class id="Note"/>
|
||||
<class id="FileDoc"/>
|
||||
</classes>
|
||||
</group>
|
||||
<group id="Configuration" _delta="define">
|
||||
<classes>
|
||||
<class id="Licence"/>
|
||||
<class id="Subnet"/>
|
||||
<class id="Patch"/>
|
||||
<class id="Software"/>
|
||||
<class id="Application"/>
|
||||
<class id="DBServer"/>
|
||||
<class id="lnkPatchToCI"/>
|
||||
<class id="FunctionalCI"/>
|
||||
<class id="SoftwareInstance"/>
|
||||
<class id="DBServerInstance"/>
|
||||
<class id="ApplicationInstance"/>
|
||||
<class id="DatabaseInstance"/>
|
||||
<class id="ApplicationSolution"/>
|
||||
<class id="BusinessProcess"/>
|
||||
<class id="ConnectableCI"/>
|
||||
<class id="NetworkInterface"/>
|
||||
<class id="Device"/>
|
||||
<class id="PC"/>
|
||||
<class id="MobileCI"/>
|
||||
<class id="MobilePhone"/>
|
||||
<class id="InfrastructureCI"/>
|
||||
<class id="NetworkDevice"/>
|
||||
<class id="Server"/>
|
||||
<class id="Printer"/>
|
||||
<class id="Group"/>
|
||||
<class id="lnkGroupToCI"/>
|
||||
<class id="lnkCIToDoc"/>
|
||||
<class id="lnkCIToContact"/>
|
||||
<class id="lnkSolutionToCI"/>
|
||||
<class id="lnkProcessToSolution"/>
|
||||
</classes>
|
||||
</group>
|
||||
<group id="Incident" _delta="define">
|
||||
<classes>
|
||||
<class id="lnkTicketToDoc"/>
|
||||
<class id="lnkTicketToContact"/>
|
||||
<class id="lnkTicketToCI"/>
|
||||
<class id="Incident"/>
|
||||
<class id="lnkTicketToIncident"/>
|
||||
</classes>
|
||||
</group>
|
||||
<group id="Problem" _delta="define">
|
||||
<classes>
|
||||
<class id="lnkTicketToDoc"/>
|
||||
<class id="lnkTicketToContact"/>
|
||||
<class id="lnkTicketToCI"/>
|
||||
<class id="Problem"/>
|
||||
</classes>
|
||||
</group>
|
||||
<group id="Change" _delta="define">
|
||||
<classes>
|
||||
<class id="lnkTicketToDoc"/>
|
||||
<class id="lnkTicketToContact"/>
|
||||
<class id="lnkTicketToCI"/>
|
||||
<class id="Change"/>
|
||||
<class id="RoutineChange"/>
|
||||
<class id="ApprovedChange"/>
|
||||
<class id="NormalChange"/>
|
||||
<class id="EmergencyChange"/>
|
||||
</classes>
|
||||
</group>
|
||||
<group id="Service" _delta="define">
|
||||
<classes>
|
||||
<class id="Contract"/>
|
||||
<class id="ProviderContract"/>
|
||||
<class id="CustomerContract"/>
|
||||
<class id="lnkCustomerContractToProviderContract"/>
|
||||
<class id="lnkContractToSLA"/>
|
||||
<class id="lnkContractToDoc"/>
|
||||
<class id="lnkContractToContact"/>
|
||||
<class id="lnkContractToCI"/>
|
||||
<class id="Service"/>
|
||||
<class id="ServiceSubcategory"/>
|
||||
<class id="SLA"/>
|
||||
<class id="SLT"/>
|
||||
<class id="lnkSLTToSLA"/>
|
||||
<class id="lnkServiceToDoc"/>
|
||||
<class id="lnkServiceToContact"/>
|
||||
<class id="lnkServiceToCI"/>
|
||||
</classes>
|
||||
</group>
|
||||
<group id="Call" _delta="define">
|
||||
<classes>
|
||||
<class id="lnkTicketToDoc"/>
|
||||
<class id="lnkTicketToContact"/>
|
||||
<class id="lnkTicketToCI"/>
|
||||
<class id="lnkTicketToIncident"/>
|
||||
<class id="UserRequest"/>
|
||||
</classes>
|
||||
</group>
|
||||
<group id="KnownError" _delta="define">
|
||||
<classes>
|
||||
<class id="KnownError"/>
|
||||
<class id="lnkInfraError"/>
|
||||
<class id="lnkDocumentError"/>
|
||||
</classes>
|
||||
</group>
|
||||
<group id="LnkTickets" _delta="define">
|
||||
<classes>
|
||||
<class id="lnkTicketToDoc"/>
|
||||
<class id="lnkTicketToContact"/>
|
||||
<class id="lnkTicketToCI"/>
|
||||
</classes>
|
||||
</group>
|
||||
<group id="LnkIncidents" _delta="define">
|
||||
<classes>
|
||||
<class id="lnkTicketToIncident"/>
|
||||
</classes>
|
||||
</group>
|
||||
<group id="LnkServices" _delta="define">
|
||||
<classes>
|
||||
<class id="lnkCustomerContractToProviderContract"/>
|
||||
<class id="lnkContractToSLA"/>
|
||||
<class id="lnkContractToDoc"/>
|
||||
<class id="lnkContractToContact"/>
|
||||
<class id="lnkContractToCI"/>
|
||||
<class id="lnkSLTToSLA"/>
|
||||
<class id="lnkServiceToDoc"/>
|
||||
<class id="lnkServiceToContact"/>
|
||||
<class id="lnkServiceToCI"/>
|
||||
</classes>
|
||||
</group>
|
||||
<group id="LnkKnownErrors" _delta="define">
|
||||
<classes>
|
||||
<class id="lnkInfraError"/>
|
||||
<class id="lnkDocumentError"/>
|
||||
</classes>
|
||||
</group>
|
||||
<group id="Portal user - write" _delta="define">
|
||||
<classes>
|
||||
<class id="FileDoc"/>
|
||||
<class id="lnkTicketToDoc"/>
|
||||
<class id="UserRequest"/>
|
||||
</classes>
|
||||
</group>
|
||||
<group id="Portal user - delete" _delta="define">
|
||||
<classes>
|
||||
<class id="lnkTicketToDoc"/>
|
||||
</classes>
|
||||
</group>
|
||||
<group id="class:UserRequest" _delta="define">
|
||||
<classes>
|
||||
<class id="UserRequest"/>
|
||||
</classes>
|
||||
</group>
|
||||
<group id="class:Incident" _delta="define">
|
||||
<classes>
|
||||
<class id="Incident"/>
|
||||
</classes>
|
||||
</group>
|
||||
<group id="class:Problem" _delta="define">
|
||||
<classes>
|
||||
<class id="Problem"/>
|
||||
</classes>
|
||||
</group>
|
||||
<group id="class:NormalChange" _delta="define">
|
||||
<classes>
|
||||
<class id="NormalChange"/>
|
||||
</classes>
|
||||
</group>
|
||||
<group id="class:EmergencyChange" _delta="define">
|
||||
<classes>
|
||||
<class id="EmergencyChange"/>
|
||||
</classes>
|
||||
</group>
|
||||
<group id="class:RoutineChange" _delta="define">
|
||||
<classes>
|
||||
<class id="RoutineChange"/>
|
||||
</classes>
|
||||
</group>
|
||||
</groups>
|
||||
<profiles>
|
||||
<profile id="3" _delta="define">
|
||||
<name>Configuration Manager</name>
|
||||
<description>Person in charge of the documentation of the managed CIs</description>
|
||||
<groups>
|
||||
<group id="General">
|
||||
<actions>
|
||||
<action xsi:type="write">allow</action>
|
||||
<action xsi:type="bulk write">allow</action>
|
||||
<action xsi:type="delete">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="Documentation">
|
||||
<actions>
|
||||
<action xsi:type="write">allow</action>
|
||||
<action xsi:type="bulk write">allow</action>
|
||||
<action xsi:type="delete">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="Configuration">
|
||||
<actions>
|
||||
<action xsi:type="write">allow</action>
|
||||
<action xsi:type="bulk write">allow</action>
|
||||
<action xsi:type="delete">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="*">
|
||||
<actions>
|
||||
<action xsi:type="read">allow</action>
|
||||
<action xsi:type="bulk read">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
</groups>
|
||||
</profile>
|
||||
<profile id="4" _delta="define">
|
||||
<name>Service Desk Agent</name>
|
||||
<description>Person in charge of creating incident reports</description>
|
||||
<groups>
|
||||
<group id="Incident">
|
||||
<actions>
|
||||
<action xsi:type="write">allow</action>
|
||||
<action xsi:type="bulk write">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="Call">
|
||||
<actions>
|
||||
<action xsi:type="write">allow</action>
|
||||
<action xsi:type="bulk write">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="LnkTickets">
|
||||
<actions>
|
||||
<action xsi:type="delete">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="LnkIncidents">
|
||||
<actions>
|
||||
<action xsi:type="delete">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="class:Incident">
|
||||
<actions>
|
||||
<action id="ev_assign" xsi:type="stimulus">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="class:UserRequest">
|
||||
<actions>
|
||||
<action id="ev_assign" xsi:type="stimulus">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="*">
|
||||
<actions>
|
||||
<action xsi:type="read">allow</action>
|
||||
<action xsi:type="bulk read">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
</groups>
|
||||
</profile>
|
||||
<profile id="5" _delta="define">
|
||||
<name>Support Agent</name>
|
||||
<description>Person analyzing and solving the current incidents</description>
|
||||
<groups>
|
||||
<group id="Incident">
|
||||
<actions>
|
||||
<action xsi:type="write">allow</action>
|
||||
<action xsi:type="bulk write">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="Call">
|
||||
<actions>
|
||||
<action xsi:type="write">allow</action>
|
||||
<action xsi:type="bulk write">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="LnkTickets">
|
||||
<actions>
|
||||
<action xsi:type="delete">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="LnkIncidents">
|
||||
<actions>
|
||||
<action xsi:type="delete">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="class:Incident">
|
||||
<actions>
|
||||
<action id="ev_assign" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_reassign" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_resolve" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_close" xsi:type="stimulus">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="class:UserRequest">
|
||||
<actions>
|
||||
<action id="ev_assign" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_reassign" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_resolve" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_close" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_freeze" xsi:type="stimulus">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="*">
|
||||
<actions>
|
||||
<action xsi:type="read">allow</action>
|
||||
<action xsi:type="bulk read">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
</groups>
|
||||
</profile>
|
||||
<profile id="6" _delta="define">
|
||||
<name>Problem Manager</name>
|
||||
<description>Person analyzing and solving the current problems</description>
|
||||
<groups>
|
||||
<group id="Problem">
|
||||
<actions>
|
||||
<action xsi:type="write">allow</action>
|
||||
<action xsi:type="bulk write">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="KnownError">
|
||||
<actions>
|
||||
<action xsi:type="write">allow</action>
|
||||
<action xsi:type="bulk write">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="LnkTickets">
|
||||
<actions>
|
||||
<action xsi:type="delete">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="LnkKnownErrors">
|
||||
<actions>
|
||||
<action xsi:type="delete">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="class:Problem">
|
||||
<actions>
|
||||
<action id="ev_assign" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_reassign" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_resolve" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_close" xsi:type="stimulus">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="*">
|
||||
<actions>
|
||||
<action xsi:type="read">allow</action>
|
||||
<action xsi:type="bulk read">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
</groups>
|
||||
</profile>
|
||||
<profile id="7" _delta="define">
|
||||
<name>Change Implementor</name>
|
||||
<description>Person executing the changes</description>
|
||||
<groups>
|
||||
<group id="Change">
|
||||
<actions>
|
||||
<action xsi:type="write">allow</action>
|
||||
<action xsi:type="bulk write">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="LnkTickets">
|
||||
<actions>
|
||||
<action xsi:type="delete">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="class:NormalChange">
|
||||
<actions>
|
||||
<action id="ev_plan" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_replan" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_implement" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_monitor" xsi:type="stimulus">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="class:EmergencyChange">
|
||||
<actions>
|
||||
<action id="ev_plan" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_replan" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_implement" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_monitor" xsi:type="stimulus">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="class:RoutineChange">
|
||||
<actions>
|
||||
<action id="ev_plan" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_replan" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_implement" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_monitor" xsi:type="stimulus">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="*">
|
||||
<actions>
|
||||
<action xsi:type="read">allow</action>
|
||||
<action xsi:type="bulk read">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
</groups>
|
||||
</profile>
|
||||
<profile id="8" _delta="define">
|
||||
<name>Change Supervisor</name>
|
||||
<description>Person responsible for the overall change execution</description>
|
||||
<groups>
|
||||
<group id="Change">
|
||||
<actions>
|
||||
<action xsi:type="write">allow</action>
|
||||
<action xsi:type="bulk write">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="LnkTickets">
|
||||
<actions>
|
||||
<action xsi:type="delete">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="class:NormalChange">
|
||||
<actions>
|
||||
<action id="ev_validate" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_reject" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_assign" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_reopen" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_finish" xsi:type="stimulus">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="class:EmergencyChange">
|
||||
<actions>
|
||||
<action id="ev_assign" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_reopen" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_finish" xsi:type="stimulus">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="class:RoutineChange">
|
||||
<actions>
|
||||
<action id="ev_assign" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_reopen" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_finish" xsi:type="stimulus">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="*">
|
||||
<actions>
|
||||
<action xsi:type="read">allow</action>
|
||||
<action xsi:type="bulk read">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
</groups>
|
||||
</profile>
|
||||
<profile id="9" _delta="define">
|
||||
<name>Change Approver</name>
|
||||
<description>Person who could be impacted by some changes</description>
|
||||
<groups>
|
||||
<group id="Change">
|
||||
<actions>
|
||||
<action xsi:type="write">allow</action>
|
||||
<action xsi:type="bulk write">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="LnkTickets">
|
||||
<actions>
|
||||
<action xsi:type="delete">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="class:NormalChange">
|
||||
<actions>
|
||||
<action id="ev_approve" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_notapprove" xsi:type="stimulus">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="class:EmergencyChange">
|
||||
<actions>
|
||||
<action id="ev_approve" xsi:type="stimulus">allow</action>
|
||||
<action id="ev_notapprove" xsi:type="stimulus">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="class:RoutineChange">
|
||||
<actions/>
|
||||
</group>
|
||||
<group id="*">
|
||||
<actions>
|
||||
<action xsi:type="read">allow</action>
|
||||
<action xsi:type="bulk read">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
</groups>
|
||||
</profile>
|
||||
<profile id="10" _delta="define">
|
||||
<name>Service Manager</name>
|
||||
<description>Person responsible for the service delivered to the [internal] customer</description>
|
||||
<groups>
|
||||
<group id="Service">
|
||||
<actions>
|
||||
<action xsi:type="write">allow</action>
|
||||
<action xsi:type="bulk write">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="LnkServices">
|
||||
<actions>
|
||||
<action xsi:type="delete">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="*">
|
||||
<actions>
|
||||
<action xsi:type="read">allow</action>
|
||||
<action xsi:type="bulk read">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
</groups>
|
||||
</profile>
|
||||
<profile id="11" _delta="define">
|
||||
<name>Document author</name>
|
||||
<description>Any person who could contribute to documentation</description>
|
||||
<groups>
|
||||
<group id="Documentation">
|
||||
<actions>
|
||||
<action xsi:type="write">allow</action>
|
||||
<action xsi:type="bulk write">allow</action>
|
||||
<action xsi:type="delete">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="LnkTickets">
|
||||
<actions>
|
||||
<action xsi:type="delete">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="*">
|
||||
<actions>
|
||||
<action xsi:type="read">allow</action>
|
||||
<action xsi:type="bulk read">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
</groups>
|
||||
</profile>
|
||||
<profile id="2" _delta="define">
|
||||
<name>Portal user</name>
|
||||
<description>Has the rights to access to the user portal. People having this profile will not be allowed to access the standard application, they will be automatically redirected to the user portal.</description>
|
||||
<groups>
|
||||
<group id="Portal user - write">
|
||||
<actions>
|
||||
<action xsi:type="write">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="Portal user - delete">
|
||||
<actions>
|
||||
<action xsi:type="delete">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="class:UserRequest">
|
||||
<actions>
|
||||
<action id="ev_close" xsi:type="stimulus">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
<group id="*">
|
||||
<actions>
|
||||
<action xsi:type="read">allow</action>
|
||||
<action xsi:type="bulk read">allow</action>
|
||||
</actions>
|
||||
</group>
|
||||
</groups>
|
||||
</profile>
|
||||
</profiles>
|
||||
</user_rights>
|
||||
</itop_design>
|
||||
@@ -1,61 +0,0 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'itop-profiles-itil/1.0.0',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
'label' => 'Create standard ITIL profiles',
|
||||
'category' => 'create_profiles',
|
||||
|
||||
// Setup
|
||||
//
|
||||
'dependencies' => array(
|
||||
),
|
||||
'mandatory' => true,
|
||||
'visible' => false,
|
||||
|
||||
// Components
|
||||
//
|
||||
'datamodel' => array(
|
||||
'model.itop-profiles-itil.php',
|
||||
),
|
||||
'webservice' => array(
|
||||
//'webservices.itop-profiles-itil.php',
|
||||
),
|
||||
'data.struct' => array(
|
||||
//'data.struct.itop-profiles-itil.xml',
|
||||
),
|
||||
'data.sample' => array(
|
||||
//'data.sample.itop-profiles-itil.xml',
|
||||
),
|
||||
|
||||
// Documentation
|
||||
//
|
||||
'doc.manual_setup' => '',
|
||||
'doc.more_information' => '',
|
||||
|
||||
// Default settings
|
||||
//
|
||||
'settings' => array(
|
||||
//'some_setting' => 'some value',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
?>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,17 +0,0 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
?>
|
||||
@@ -1,29 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<dashboard xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<title>UI:RequestMgmtMenuOverview:Title</title>
|
||||
<layout>DashboardLayoutTwoCols</layout>
|
||||
<cells>
|
||||
<cell>
|
||||
<dashlet id="1" xsi:type="DashletGroupByBars">
|
||||
<title>UI-RequestManagementOverview-RequestByService</title>
|
||||
<query>SELECT UserRequest</query>
|
||||
<group_by>service_id</group_by>
|
||||
<style>bars</style>
|
||||
</dashlet>
|
||||
</cell>
|
||||
<cell>
|
||||
<dashlet id="2" xsi:type="DashletGroupByPie">
|
||||
<title>UI-RequestManagementOverview-RequestByPriority</title>
|
||||
<query>SELECT UserRequest</query>
|
||||
<group_by>priority</group_by>
|
||||
<style>pie</style>
|
||||
</dashlet>
|
||||
</cell>
|
||||
<cell>
|
||||
<dashlet id="3" xsi:type="DashletObjectList">
|
||||
<title>UI-RequestManagementOverview-RequestUnassigned</title>
|
||||
<query>SELECT UserRequest WHERE status IN ("new", "escalated_tto")</query>
|
||||
</dashlet>
|
||||
</cell>
|
||||
</cells>
|
||||
</dashboard>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,17 +0,0 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
?>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,79 +0,0 @@
|
||||
<?php
|
||||
// Copyright (C) 2010 Combodo SARL
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; version 3 of the License.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
class ProcessSLAResponseTicket implements iBackgroundProcess
|
||||
{
|
||||
public function GetPeriodicity()
|
||||
{
|
||||
return 2; // seconds
|
||||
}
|
||||
|
||||
public function Process($iTimeLimit)
|
||||
{
|
||||
$oMyChange = new CMDBChange();
|
||||
$oMyChange->Set("date", time());
|
||||
$oMyChange->Set("userinfo", "Automatic updates");
|
||||
$iChangeId = $oMyChange->DBInsertNoReload();
|
||||
|
||||
$aReport = array();
|
||||
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL('SELECT ResponseTicket WHERE status = \'new\' AND tto_escalation_deadline <= NOW()'));
|
||||
while ((time() < $iTimeLimit) && $oToEscalate = $oSet->Fetch())
|
||||
{
|
||||
$oToEscalate->ApplyStimulus('ev_timeout');
|
||||
//$oToEscalate->Set('tto_escalation_deadline', null);
|
||||
$oToEscalate->DBUpdateTracked($oMyChange, true);
|
||||
$aReport['reached TTO ESCALATION deadline'][] = $oToEscalate->Get('ref');
|
||||
}
|
||||
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL('SELECT ResponseTicket WHERE status = \'assigned\' AND ttr_escalation_deadline <= NOW()'));
|
||||
while ((time() < $iTimeLimit) && $oToEscalate = $oSet->Fetch())
|
||||
{
|
||||
$oToEscalate->ApplyStimulus('ev_timeout');
|
||||
//$oToEscalate->Set('ttr_escalation_deadline', null);
|
||||
$oToEscalate->DBUpdateTracked($oMyChange, true);
|
||||
$aReport['reached TTR ESCALATION deadline'][] = $oToEscalate->Get('ref');
|
||||
}
|
||||
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL('SELECT ResponseTicket WHERE status = \'resolved\' AND closure_deadline <= NOW()'));
|
||||
while ((time() < $iTimeLimit) && $oToEscalate = $oSet->Fetch())
|
||||
{
|
||||
$oToEscalate->ApplyStimulus('ev_close');
|
||||
//$oToEscalate->Set('closure_deadline', null);
|
||||
$oToEscalate->DBUpdateTracked($oMyChange, true);
|
||||
$aReport['reached closure deadline'][] = $oToEscalate->Get('ref');
|
||||
}
|
||||
|
||||
$aStringReport = array();
|
||||
foreach ($aReport as $sOperation => $aTicketRefs)
|
||||
{
|
||||
if (count($aTicketRefs) > 0)
|
||||
{
|
||||
$aStringReport[] = $sOperation.': '.count($aTicketRefs).' {'.implode(', ', $aTicketRefs).'}';
|
||||
}
|
||||
}
|
||||
if (count($aStringReport) == 0)
|
||||
{
|
||||
return "No ticket to process";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "Some tickets reached the limit - ".implode('; ', $aStringReport);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
@@ -1,76 +0,0 @@
|
||||
<?php
|
||||
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__,
|
||||
'itop-tickets/1.0.0',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
'label' => 'Tickets - prerequisite for ticket modules',
|
||||
'category' => 'business',
|
||||
|
||||
// Setup
|
||||
//
|
||||
'dependencies' => array(
|
||||
'itop-config-mgmt/1.0.0',
|
||||
),
|
||||
'mandatory' => true,
|
||||
'visible' => false,
|
||||
'installer' => 'TicketsInstaller',
|
||||
|
||||
// Components
|
||||
//
|
||||
'datamodel' => array(
|
||||
'model.itop-tickets.php',
|
||||
'main.itop-tickets.php',
|
||||
),
|
||||
'data.struct' => array(
|
||||
'data.struct.ta-actions.xml',
|
||||
),
|
||||
'data.sample' => array(
|
||||
),
|
||||
|
||||
// Documentation
|
||||
//
|
||||
'doc.manual_setup' => '',
|
||||
'doc.more_information' => '',
|
||||
|
||||
// Default settings
|
||||
//
|
||||
'settings' => array(
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
if (!class_exists('TicketsInstaller'))
|
||||
{
|
||||
// Module installation handler
|
||||
//
|
||||
class TicketsInstaller extends ModuleInstallerAPI
|
||||
{
|
||||
public static function AfterDatabaseCreation(Config $oConfiguration, $sPreviousVersion, $sCurrentVersion)
|
||||
{
|
||||
// Delete all Triggers corresponding to a no more valid class
|
||||
$oSearch = new DBObjectSearch('TriggerOnObject');
|
||||
$oSet = new DBObjectSet($oSearch);
|
||||
$oChange = null;
|
||||
while($oTrigger = $oSet->Fetch())
|
||||
{
|
||||
if (!MetaModel::IsValidClass($oTrigger->Get('target_class')))
|
||||
{
|
||||
if ($oChange == null)
|
||||
{
|
||||
// Create the change for its first use
|
||||
$oChange = new CMDBChange;
|
||||
$oChange->Set("date", time());
|
||||
$oChange->Set("userinfo", "Uninstallation");
|
||||
$oChange->DBInsert();
|
||||
}
|
||||
$oTrigger->DBDeleteTracked($oChange);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -1,66 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<dashboard xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
||||
<layout>DashboardLayoutOneCol</layout>
|
||||
<title></title>
|
||||
<cells>
|
||||
<cell>
|
||||
<dashlet id="1" xsi:type="DashletHeaderDynamic">
|
||||
<title>UI:ConfigurationManagementMenu</title>
|
||||
<icon>itop-config-mgmt-1.0.0/images/database.png</icon>
|
||||
<subtitle>UI:WelcomeMenu:AllConfigItems</subtitle>
|
||||
<query>SELECT FunctionalCI</query>
|
||||
<group_by>status</group_by>
|
||||
<values>implementation,production,obsolete</values>
|
||||
</dashlet>
|
||||
<dashlet id="2" xsi:type="DashletBadge">
|
||||
<class>BusinessProcess</class>
|
||||
</dashlet>
|
||||
<dashlet id="3" xsi:type="DashletBadge">
|
||||
<class>Contact</class>
|
||||
</dashlet>
|
||||
<dashlet id="4" xsi:type="DashletBadge">
|
||||
<class>Location</class>
|
||||
</dashlet>
|
||||
<dashlet id="5" xsi:type="DashletBadge">
|
||||
<class>Server</class>
|
||||
</dashlet>
|
||||
<dashlet id="6" xsi:type="DashletBadge">
|
||||
<class>DatabaseInstance</class>
|
||||
</dashlet>
|
||||
<dashlet id="7" xsi:type="DashletBadge">
|
||||
<class>NetworkDevice</class>
|
||||
</dashlet>
|
||||
</cell>
|
||||
<cell>
|
||||
<dashlet id="8" xsi:type="DashletHeaderDynamic">
|
||||
<title>Menu:RequestManagement</title>
|
||||
<icon>itop-request-mgmt-1.0.0/images/user-request-deadline.png</icon>
|
||||
<subtitle>UI:WelcomeMenu:AllOpenRequests</subtitle>
|
||||
<query>SELECT UserRequest WHERE status != "closed"</query>
|
||||
<group_by>status</group_by>
|
||||
<values>new,assigned,escalated_tto,escalated_ttr,resolved</values>
|
||||
</dashlet>
|
||||
<dashlet id="9" xsi:type="DashletObjectList">
|
||||
<title>UI:WelcomeMenu:MyCalls</title>
|
||||
<query>SELECT UserRequest AS i WHERE i.caller_id = :current_contact_id AND status NOT IN ("closed", "resolved")</query>
|
||||
<menu>true</menu>
|
||||
</dashlet>
|
||||
</cell>
|
||||
<cell>
|
||||
<dashlet id="10" xsi:type="DashletHeaderDynamic">
|
||||
<title>Menu:IncidentManagement</title>
|
||||
<icon>itop-incident-mgmt-1.0.0/images/incident-escalated.png</icon>
|
||||
<subtitle>UI:WelcomeMenu:OpenIncidents</subtitle>
|
||||
<query>SELECT Incident WHERE status != "closed"</query>
|
||||
<group_by>status</group_by>
|
||||
<values>new,assigned,escalated_tto,escalated_ttr,resolved</values>
|
||||
</dashlet>
|
||||
<dashlet id="11" xsi:type="DashletObjectList">
|
||||
<title>UI:WelcomeMenu:MyIncidents</title>
|
||||
<query>SELECT Incident AS i WHERE i.agent_id = :current_contact_id AND status NOT IN ("closed", "resolved")</query>
|
||||
<menu>true</menu>
|
||||
</dashlet>
|
||||
</cell>
|
||||
</cells>
|
||||
</dashboard>
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 8.6 KiB |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -144,7 +144,7 @@ Operators:<br/>
|
||||
'Core:AttributeFriendlyName' => 'Friendly name',
|
||||
'Core:AttributeFriendlyName+' => 'Attribute created automatically ; the friendly name is computed after several attributes',
|
||||
|
||||
'Core:FriendlyName-Label' => 'Name',
|
||||
'Core:FriendlyName-Label' => 'Friendly name',
|
||||
'Core:FriendlyName-Description' => 'Friendly name',
|
||||
));
|
||||
|
||||
|
||||
@@ -353,7 +353,6 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'UI:Button:Search' => ' Search ',
|
||||
'UI:Button:Query' => ' Query ',
|
||||
'UI:Button:Ok' => 'Ok',
|
||||
'UI:Button:Save' => 'Save',
|
||||
'UI:Button:Cancel' => 'Cancel',
|
||||
'UI:Button:Apply' => 'Apply',
|
||||
'UI:Button:Back' => ' << Back ',
|
||||
@@ -484,7 +483,6 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'UI:Login:PasswordChanged' => 'Password successfully set !',
|
||||
'UI:AccessRO-All' => 'iTop is read-only',
|
||||
'UI:AccessRO-Users' => 'iTop is read-only for end-users',
|
||||
'UI:ApplicationEnvironment' => 'Application environment: %1$s',
|
||||
'UI:Login:RetypePwdDoesNotMatch' => 'New password and retyped new password do not match !',
|
||||
'UI:Button:Login' => 'Enter iTop',
|
||||
'UI:Login:Error:AccessRestricted' => 'iTop access is restricted. Please, contact an iTop administrator.',
|
||||
@@ -760,6 +758,14 @@ Dict::Add('EN US', 'English', 'English', array(
|
||||
'UI-ChangeManagementMenu-ChangesByWorkgroup' => 'Changes by workgroup',
|
||||
'UI-ChangeManagementMenu-ChangesNotYetAssigned' => 'Changes not yet assigned',
|
||||
|
||||
'UI:ConfigurationItemsMenu'=> 'Configuration Items',
|
||||
'UI:ConfigurationItemsMenu+'=> 'All Devices',
|
||||
'UI:ConfigurationItemsMenu:Title' => 'Configuration Items Overview',
|
||||
'UI-ConfigurationItemsMenu-ServersByCriticity' => 'Servers by criticity',
|
||||
'UI-ConfigurationItemsMenu-PCsByCriticity' => 'PCs by criticity',
|
||||
'UI-ConfigurationItemsMenu-NWDevicesByCriticity' => 'Network devices by criticity',
|
||||
'UI-ConfigurationItemsMenu-ApplicationsByCriticity' => 'Applications by criticity',
|
||||
|
||||
'UI:ConfigurationManagementMenu' => 'Configuration Management',
|
||||
'UI:ConfigurationManagementMenu+' => 'Configuration Management',
|
||||
'UI:ConfigurationManagementMenu:Title' => 'Infrastructure Overview',
|
||||
@@ -952,122 +958,12 @@ When associated with a trigger, each action is given an "order" number, specifyi
|
||||
'UI:Pagination:All' => 'All',
|
||||
'UI:HierarchyOf_Class' => 'Hierarchy of %1$s',
|
||||
'UI:Preferences' => 'Preferences...',
|
||||
'UI:FavoriteOrganizations' => 'Favorite Organizations',
|
||||
'UI:FavoriteOrganizations' => 'My Favorite Organizations',
|
||||
'UI:FavoriteOrganizations+' => 'Check in the list below the organizations that you want to see in the drop-down menu for a quick access. '.
|
||||
'Note that this is not a security setting, objects from any organization are still visible and can be accessed by selecting "All Organizations" in the drop-down list.',
|
||||
'UI:FavoriteLanguage' => 'Language of the User Interface',
|
||||
'UI:Favorites:SelectYourLanguage' => 'Select your preferred language',
|
||||
'UI:FavoriteOtherSettings' => 'Other Settings',
|
||||
'UI:Favorites:Default_X_ItemsPerPage' => 'Default length for lists: %1$s items per page',
|
||||
'UI:NavigateAwayConfirmationMessage' => 'Any modification will be discarded.',
|
||||
'UI:CancelConfirmationMessage' => 'You will loose your changes. Continue anyway?',
|
||||
'UI:AutoApplyConfirmationMessage' => 'Some changes have not been applied yet. Do you want itop to take them into account?',
|
||||
'UI:Create_Class_InState' => 'Create the %1$s in state: ',
|
||||
'UI:OrderByHint_Values' => 'Sort order: %1$s',
|
||||
'UI:Menu:AddToDashboard' => 'Add To Dashboard...',
|
||||
'UI:Button:Refresh' => 'Refresh',
|
||||
|
||||
'UI:ConfigureThisList' => 'Configure This List...',
|
||||
'UI:ListConfigurationTitle' => 'List Configuration',
|
||||
'UI:ColumnsAndSortOrder' => 'Columns and sort order:',
|
||||
'UI:UseDefaultSettings' => 'Use the Default Settings',
|
||||
'UI:UseSpecificSettings' => 'Use the Following Settings:',
|
||||
'UI:Display_X_ItemsPerPage' => 'Display %1$s items per page',
|
||||
'UI:UseSavetheSettings' => 'Save the Settings',
|
||||
'UI:OnlyForThisList' => 'Only for this list',
|
||||
'UI:ForAllLists' => 'For all lists',
|
||||
'UI:ExtKey_AsLink' => '%1$s (Link)',
|
||||
'UI:ExtKey_AsFriendlyName' => '%1$s (Friendly Name)',
|
||||
'UI:ExtField_AsRemoteField' => '%1$s (%2$s)',
|
||||
'UI:Button:MoveUp' => 'Move Up',
|
||||
'UI:Button:MoveDown' => 'Move Down',
|
||||
|
||||
'UI:OQL:UnknownClassAndFix' => 'Unknown class "%1$s". You may try "%2$s" instead.',
|
||||
'UI:OQL:UnknownClassNoFix' => 'Unknown class "%1$s"',
|
||||
|
||||
'UI:Dashboard:Edit' => 'Edit This Page...',
|
||||
'UI:Dashboard:Revert' => 'Revert To Original Version...',
|
||||
'UI:Dashboard:RevertConfirm' => 'Every changes made to the original version will be lost. Please confirm that you want to do this.',
|
||||
'UI:ExportDashBoard' => 'Export to a file',
|
||||
'UI:ImportDashBoard' => 'Import from a file...',
|
||||
'UI:ImportDashboardTitle' => 'Import From a File',
|
||||
'UI:ImportDashboardText' => 'Select a dashboard file to import:',
|
||||
|
||||
|
||||
'UI:DashletCreation:Title' => 'Create a new Dashlet',
|
||||
'UI:DashletCreation:Dashboard' => 'Dashboard',
|
||||
'UI:DashletCreation:DashletType' => 'Dashlet Type',
|
||||
'UI:DashletCreation:EditNow' => 'Edit the Dashboard',
|
||||
|
||||
'UI:DashboardEdit:Title' => 'Dashboard Editor',
|
||||
'UI:DashboardEdit:DashboardTitle' => 'Title',
|
||||
'UI:DashboardEdit:Layout' => 'Layout',
|
||||
'UI:DashboardEdit:Properties' => 'Dashboard Properties',
|
||||
'UI:DashboardEdit:Dashlets' => 'Available Dashlets',
|
||||
'UI:DashboardEdit:DashletProperties' => 'Dashlet Properties',
|
||||
|
||||
'UI:Form:Property' => 'Property',
|
||||
'UI:Form:Value' => 'Value',
|
||||
|
||||
'UI:DashletPlainText:Label' => 'Text',
|
||||
'UI:DashletPlainText:Description' => 'Plain text (no formatting)',
|
||||
'UI:DashletPlainText:Prop-Text' => 'Text',
|
||||
'UI:DashletPlainText:Prop-Text:Default' => 'Please enter some text here...',
|
||||
|
||||
'UI:DashletObjectList:Label' => 'Object list',
|
||||
'UI:DashletObjectList:Description' => 'Object list dashlet',
|
||||
'UI:DashletObjectList:Prop-Title' => 'Title',
|
||||
'UI:DashletObjectList:Prop-Query' => 'Query',
|
||||
'UI:DashletObjectList:Prop-Menu' => 'Menu',
|
||||
|
||||
'UI:DashletGroupBy:Prop-Title' => 'Title',
|
||||
'UI:DashletGroupBy:Prop-Query' => 'Query',
|
||||
'UI:DashletGroupBy:Prop-Style' => 'Style',
|
||||
'UI:DashletGroupBy:Prop-GroupBy' => 'Group by...',
|
||||
'UI:DashletGroupBy:Prop-GroupBy:Hour' => 'Hour of %1$s (0-23)',
|
||||
'UI:DashletGroupBy:Prop-GroupBy:Month' => 'Month of %1$s (1 - 12)',
|
||||
'UI:DashletGroupBy:Prop-GroupBy:DayOfWeek' => 'Day of week for %1$s',
|
||||
'UI:DashletGroupBy:Prop-GroupBy:DayOfMonth' => 'Day of month for %1$s',
|
||||
'UI:DashletGroupBy:Prop-GroupBy:Select-Hour' => '%1$s (hour)',
|
||||
'UI:DashletGroupBy:Prop-GroupBy:Select-Month' => '%1$s (month)',
|
||||
'UI:DashletGroupBy:Prop-GroupBy:Select-DayOfWeek' => '%1$s (day of week)',
|
||||
'UI:DashletGroupBy:Prop-GroupBy:Select-DayOfMonth' => '%1$s (day of month)',
|
||||
'UI:DashletGroupBy:MissingGroupBy' => 'Please select the field on which the objects will be grouped together',
|
||||
|
||||
'UI:DashletGroupByPie:Label' => 'Pie Chart',
|
||||
'UI:DashletGroupByPie:Description' => 'Pie Chart',
|
||||
'UI:DashletGroupByBars:Label' => 'Bar Chart',
|
||||
'UI:DashletGroupByBars:Description' => 'Bar Chart',
|
||||
'UI:DashletGroupByTable:Label' => 'Group By (table)',
|
||||
'UI:DashletGroupByTable:Description' => 'List (Grouped by a field)',
|
||||
|
||||
'UI:DashletHeaderStatic:Label' => 'Header',
|
||||
'UI:DashletHeaderStatic:Description' => 'Displays an horizontal separator',
|
||||
'UI:DashletHeaderStatic:Prop-Title' => 'Title',
|
||||
'UI:DashletHeaderStatic:Prop-Title:Default' => 'Contacts',
|
||||
'UI:DashletHeaderStatic:Prop-Icon' => 'Icon',
|
||||
|
||||
'UI:DashletHeaderDynamic:Label' => 'Header with statistics',
|
||||
'UI:DashletHeaderDynamic:Description' => 'Header with stats (grouped by...)',
|
||||
'UI:DashletHeaderDynamic:Prop-Title' => 'Title',
|
||||
'UI:DashletHeaderDynamic:Prop-Title:Default' => 'Contacts',
|
||||
'UI:DashletHeaderDynamic:Prop-Icon' => 'Icon',
|
||||
'UI:DashletHeaderDynamic:Prop-Subtitle' => 'Subtitle',
|
||||
'UI:DashletHeaderDynamic:Prop-Subtitle:Default' => 'Contacts',
|
||||
'UI:DashletHeaderDynamic:Prop-Query' => 'Query',
|
||||
'UI:DashletHeaderDynamic:Prop-GroupBy' => 'Group by',
|
||||
'UI:DashletHeaderDynamic:Prop-Values' => 'Values',
|
||||
|
||||
'UI:DashletBadge:Label' => 'Badge',
|
||||
'UI:DashletBadge:Description' => 'Object Icon with new/search',
|
||||
'UI:DashletBadge:Prop-Class' => 'Class',
|
||||
|
||||
'DayOfWeek-Sunday' => 'Sunday',
|
||||
'DayOfWeek-Monday' => 'Monday',
|
||||
'DayOfWeek-Tuesday' => 'Tuesday',
|
||||
'DayOfWeek-Wednesday' => 'Wednesday',
|
||||
'DayOfWeek-Thursday' => 'Thursday',
|
||||
'DayOfWeek-Friday' => 'Friday',
|
||||
'DayOfWeek-Saturday' => 'Saturday',
|
||||
'UI:iTopLogin' => 'iTop Login',
|
||||
));
|
||||
?>
|
||||
|
||||
@@ -723,6 +723,14 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
|
||||
'UI-ChangeManagementMenu-ChangesByWorkgroup' => 'Cambios por grupo de trabajo',
|
||||
'UI-ChangeManagementMenu-ChangesNotYetAssigned' => 'Cambios no asignados aun',
|
||||
|
||||
'UI:ConfigurationItemsMenu'=> 'Elementos de configuracion',
|
||||
'UI:ConfigurationItemsMenu+'=> 'Todos los dispositivos',
|
||||
'UI:ConfigurationItemsMenu:Title' => 'Sumario de Elementos de Configuracion',
|
||||
'UI-ConfigurationItemsMenu-ServersByCriticity' => 'Servidores por criticidad',
|
||||
'UI-ConfigurationItemsMenu-PCsByCriticity' => 'PCs por criticidad',
|
||||
'UI-ConfigurationItemsMenu-NWDevicesByCriticity' => 'Dispositivos de red por criticidad',
|
||||
'UI-ConfigurationItemsMenu-ApplicationsByCriticity' => 'Aplicaciones por criticidad',
|
||||
|
||||
'UI:ConfigurationManagementMenu' => 'Gestion de la Configuracion',
|
||||
'UI:ConfigurationManagementMenu+' => 'Gestion de la Configuracion',
|
||||
'UI:ConfigurationManagementMenu:Title' => 'Sumario de Infrastructura',
|
||||
|
||||
@@ -235,7 +235,6 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'UI:Button:GlobalSearch' => 'Rechercher',
|
||||
'UI:Button:Search' => 'Rechercher',
|
||||
'UI:Button:Query' => ' Lancer la requête ',
|
||||
'UI:Button:Save' => 'Sauver',
|
||||
'UI:Button:Ok' => 'Ok',
|
||||
'UI:Button:Cancel' => 'Annuler',
|
||||
'UI:Button:Apply' => 'Appliquer',
|
||||
@@ -361,7 +360,6 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'UI:Login:PasswordChanged' => 'Mot de passe mis à jour !',
|
||||
'UI:AccessRO-All' => 'iTop est en lecture seule',
|
||||
'UI:AccessRO-Users' => 'iTop est en lecture seule pour les utilisateurs finaux',
|
||||
'UI:ApplicationEnvironment' => 'Environnement applicatif: %1$s',
|
||||
'UI:Login:RetypePwdDoesNotMatch' => 'Les deux saisies du nouveau mot de passe ne sont pas identiques !',
|
||||
'UI:Button:Login' => 'Entrer dans iTop',
|
||||
'UI:Login:Error:AccessRestricted' => 'L\'accès à iTop est soumis à autorisation. Merci de contacter votre administrateur iTop.',
|
||||
@@ -628,6 +626,13 @@ Dict::Add('FR FR', 'French', 'Français', array(
|
||||
'UI-ChangeManagementMenu-ChangesByStatus' => 'Changements par état',
|
||||
'UI-ChangeManagementMenu-ChangesByWorkgroup' => 'Changements par workgroup',
|
||||
'UI-ChangeManagementMenu-ChangesNotYetAssigned' => 'Changements en attente d\'assignation',
|
||||
'UI:ConfigurationItemsMenu' => 'Actifs (CIs)',
|
||||
'UI:ConfigurationItemsMenu+' => 'Tous les actifs',
|
||||
'UI:ConfigurationItemsMenu:Title' => 'Résumé des actifs (CIs)',
|
||||
'UI-ConfigurationItemsMenu-ServersByCriticity' => 'Serveurs par criticité',
|
||||
'UI-ConfigurationItemsMenu-PCsByCriticity' => 'PCs par criticité',
|
||||
'UI-ConfigurationItemsMenu-NWDevicesByCriticity' => 'Equipements réseau par criticité',
|
||||
'UI-ConfigurationItemsMenu-ApplicationsByCriticity' => 'Applications par criticité',
|
||||
'UI:ConfigurationManagementMenu' => 'Gestion de Configuration',
|
||||
'UI:ConfigurationManagementMenu+' => 'Gestion de Configuration',
|
||||
'UI:ConfigurationManagementMenu:Title' => 'Résumé de l\'Infrastructure',
|
||||
@@ -795,122 +800,12 @@ Lors de l\'association à un déclencheur, on attribue à chaque action un numé
|
||||
'UI:Pagination:PagesLabel' => 'Pages:',
|
||||
'UI:Pagination:All' => 'Tous',
|
||||
'UI:HierarchyOf_Class' => 'Hiérarchie de type %1$s',
|
||||
'UI:Preferences' => 'Préférences...',
|
||||
'UI:FavoriteOrganizations' => 'Organisations Favorites',
|
||||
'UI:Preferences' => 'Preferences...',
|
||||
'UI:FavoriteOrganizations' => 'Mes Organisations Favorites',
|
||||
'UI:FavoriteOrganizations+' => 'Cochez dans la liste ci-dessous les organisations que vous voulez voir listées dans le menu principal. '.
|
||||
'Ceci n\'est pas un réglage de sécurité. Les objets de toutes les organisations sont toujours visibles en choisissant "Toutes les Organisations" dans le menu.',
|
||||
'UI:FavoriteLanguage' => 'Langue de l\'interface utilisateur',
|
||||
'UI:Favorites:SelectYourLanguage' => 'Choisissez votre langue préférée',
|
||||
'UI:FavoriteOtherSettings' => 'Autres réglages',
|
||||
'UI:Favorites:Default_X_ItemsPerPage' => 'Longueur par défaut des listes: %1$s éléments par page',
|
||||
'UI:NavigateAwayConfirmationMessage' => 'Toute modification sera perdue.',
|
||||
'UI:CancelConfirmationMessage' => 'Vous allez perdre vos modifications. Voulez-vous continuer ?',
|
||||
'UI:AutoApplyConfirmationMessage' => 'Des modifications n\'ont pas encore été prises en compte. Voulez-vous qu\'elles soient prises en compte automatiquement ?',
|
||||
'UI:Create_Class_InState' => 'Créer l\'objet %1$s dans l\'état: ',
|
||||
'UI:OrderByHint_Values' => 'Ordre de tri: %1$s',
|
||||
'UI:Menu:AddToDashboard' => 'Ajouter au Tableau de Bord...',
|
||||
'UI:Button:Refresh' => 'Rafraîchir',
|
||||
|
||||
'UI:ConfigureThisList' => 'Configurer Cette Liste...',
|
||||
'UI:ListConfigurationTitle' => 'Configuration de la liste',
|
||||
'UI:ColumnsAndSortOrder' => 'Colonnes et ordre de tri:',
|
||||
'UI:UseDefaultSettings' => 'Utiliser les réglages par défaut',
|
||||
'UI:UseSpecificSettings' => 'Utiliser les réglages suivants:',
|
||||
'UI:Display_X_ItemsPerPage' => 'Afficher %1$s éléments par page',
|
||||
'UI:UseSavetheSettings' => 'Enregistrer ces réglages',
|
||||
'UI:OnlyForThisList' => 'Seulement pour cette liste',
|
||||
'UI:ForAllLists' => 'Pour toutes les listes',
|
||||
'UI:ExtKey_AsLink' => '%1$s (Lien)',
|
||||
'UI:ExtKey_AsFriendlyName' => '%1$s (Nom)',
|
||||
'UI:ExtField_AsRemoteField' => '%1$s (%2$s)',
|
||||
'UI:Button:MoveUp' => 'Monter',
|
||||
'UI:Button:MoveDown' => 'Descendre',
|
||||
|
||||
'UI:OQL:UnknownClassAndFix' => 'La classe "%1$s" est inconnue. Essayez plutôt "%2$s".',
|
||||
'UI:OQL:UnknownClassNoFix' => 'La classe "%1$s" est inconnue',
|
||||
|
||||
'UI:Dashboard:Edit' => 'Editer cette page...',
|
||||
'UI:Dashboard:Revert' => 'Revenir à la version d\'origine...',
|
||||
'UI:Dashboard:RevertConfirm' => 'Toutes modifications apportées à la version d\'origine seront perdues. Veuillez confirmer l\'opération.',
|
||||
'UI:ExportDashBoard' => 'Exporter dans un fichier',
|
||||
'UI:ImportDashBoard' => 'Importer depuis un fichier...',
|
||||
'UI:ImportDashboardTitle' => 'Importation depuis un fichier',
|
||||
'UI:ImportDashboardText' => 'Choisissez un fichier de définition de tableau de bord :',
|
||||
|
||||
'UI:DashletCreation:Title' => 'Créer un Indicateur',
|
||||
'UI:DashletCreation:Dashboard' => 'Tableau de bord',
|
||||
'UI:DashletCreation:DashletType' => 'Type d\'Indicateur',
|
||||
'UI:DashletCreation:EditNow' => 'Modifier le tableau de bord',
|
||||
|
||||
'UI:DashboardEdit:Title' => 'Editeur de tableau de bord',
|
||||
'UI:DashboardEdit:DashboardTitle' => 'Titre',
|
||||
'UI:DashboardEdit:Layout' => 'Mise en page',
|
||||
'UI:DashboardEdit:Properties' => 'Propriétés du tableau de bord',
|
||||
'UI:DashboardEdit:Dashlets' => 'Indicateurs',
|
||||
'UI:DashboardEdit:DashletProperties' => 'Propriétés de l\'Indicateur',
|
||||
|
||||
'UI:Form:Property' => 'Propriété',
|
||||
'UI:Form:Value' => 'Valeur',
|
||||
|
||||
'UI:DashletPlainText:Label' => 'Texte',
|
||||
'UI:DashletPlainText:Description' => 'Text pur (pas de mise en forme)',
|
||||
'UI:DashletPlainText:Prop-Text' => 'Texte',
|
||||
'UI:DashletPlainText:Prop-Text:Default' => 'Veuillez saisir votre texte ici...',
|
||||
|
||||
'UI:DashletObjectList:Label' => 'Liste d\'objets',
|
||||
'UI:DashletObjectList:Description' => 'Liste d\'objets',
|
||||
'UI:DashletObjectList:Prop-Title' => 'Titre',
|
||||
'UI:DashletObjectList:Prop-Query' => 'Requête OQL',
|
||||
'UI:DashletObjectList:Prop-Menu' => 'Menu',
|
||||
|
||||
'UI:DashletGroupBy:Prop-Title' => 'Titre',
|
||||
'UI:DashletGroupBy:Prop-Query' => 'Requête OQL',
|
||||
'UI:DashletGroupBy:Prop-Style' => 'Style',
|
||||
'UI:DashletGroupBy:Prop-GroupBy' => 'Grouper par',
|
||||
'UI:DashletGroupBy:Prop-GroupBy:Hour' => 'Heure de %1$s (0-23)',
|
||||
'UI:DashletGroupBy:Prop-GroupBy:Month' => 'Mois de %1$s (1 - 12)',
|
||||
'UI:DashletGroupBy:Prop-GroupBy:DayOfWeek' => 'Jour de la semaine pour %1$s',
|
||||
'UI:DashletGroupBy:Prop-GroupBy:DayOfMonth' => 'Jour du mois pour %1$s',
|
||||
'UI:DashletGroupBy:Prop-GroupBy:Select-Hour' => '%1$s (heure)',
|
||||
'UI:DashletGroupBy:Prop-GroupBy:Select-Month' => '%1$s (mois)',
|
||||
'UI:DashletGroupBy:Prop-GroupBy:Select-DayOfWeek' => '%1$s (jour de la semaine)',
|
||||
'UI:DashletGroupBy:Prop-GroupBy:Select-DayOfMonth' => '%1$s (jour du mois)',
|
||||
'UI:DashletGroupBy:MissingGroupBy' => 'Veuillez sélectionner le champ sur lequel les objets seront groupés',
|
||||
|
||||
'UI:DashletGroupByPie:Label' => 'Secteurs',
|
||||
'UI:DashletGroupByPie:Description' => 'Graphique à secteur',
|
||||
'UI:DashletGroupByBars:Label' => 'Barres',
|
||||
'UI:DashletGroupByBars:Description' => 'Graphique en Barres',
|
||||
'UI:DashletGroupByTable:Label' => 'Table',
|
||||
'UI:DashletGroupByTable:Description' => 'Table',
|
||||
|
||||
'UI:DashletHeaderStatic:Label' => 'En-tête',
|
||||
'UI:DashletHeaderStatic:Description' => 'En-tête présenté comme une barre horizontale',
|
||||
'UI:DashletHeaderStatic:Prop-Title' => 'Titre',
|
||||
'UI:DashletHeaderStatic:Prop-Title:Default' => 'Contacts',
|
||||
'UI:DashletHeaderStatic:Prop-Icon' => 'Icône',
|
||||
|
||||
'UI:DashletHeaderDynamic:Label' => 'En-tête dynamique',
|
||||
'UI:DashletHeaderDynamic:Description' => 'En-tête avec statistiques (regroupements)',
|
||||
'UI:DashletHeaderDynamic:Prop-Title' => 'Titre',
|
||||
'UI:DashletHeaderDynamic:Prop-Title:Default' => 'Contacts',
|
||||
'UI:DashletHeaderDynamic:Prop-Icon' => 'Icône',
|
||||
'UI:DashletHeaderDynamic:Prop-Subtitle' => 'Sous-titre',
|
||||
'UI:DashletHeaderDynamic:Prop-Subtitle:Default' => 'Contacts',
|
||||
'UI:DashletHeaderDynamic:Prop-Query' => 'Requête OQL',
|
||||
'UI:DashletHeaderDynamic:Prop-GroupBy' => 'Grouper par',
|
||||
'UI:DashletHeaderDynamic:Prop-Values' => 'Valeurs',
|
||||
|
||||
'UI:DashletBadge:Label' => 'Badge',
|
||||
'UI:DashletBadge:Description' => 'Icône représentant une classe d\'objets, ainsi que des liens pour créer/rechercher',
|
||||
'UI:DashletBadge:Prop-Class' => 'Classe',
|
||||
|
||||
'DayOfWeek-Sunday' => 'Dimanche',
|
||||
'DayOfWeek-Monday' => 'Lundi',
|
||||
'DayOfWeek-Tuesday' => 'Mardi',
|
||||
'DayOfWeek-Wednesday' => 'Mercredi',
|
||||
'DayOfWeek-Thursday' => 'Jeudi',
|
||||
'DayOfWeek-Friday' => 'Vendredi',
|
||||
'DayOfWeek-Saturday' => 'Samedi',
|
||||
));
|
||||
?>
|
||||
|
||||
@@ -607,6 +607,13 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
|
||||
'UI-ChangeManagementMenu-ChangesByStatus' => 'Változások státusz szerint',
|
||||
'UI-ChangeManagementMenu-ChangesByWorkgroup' => 'Változások csoportok szerint',
|
||||
'UI-ChangeManagementMenu-ChangesNotYetAssigned' => 'Még nem kiosztott változások',
|
||||
'UI:ConfigurationItemsMenu' => 'Konfigurációs elemek',
|
||||
'UI:ConfigurationItemsMenu+' => '',
|
||||
'UI:ConfigurationItemsMenu:Title' => 'Konfigurációs elemek áttekintése',
|
||||
'UI-ConfigurationItemsMenu-ServersByCriticity' => 'Szerverek kritikusság szerint',
|
||||
'UI-ConfigurationItemsMenu-PCsByCriticity' => 'PC-k kritikusság szerint',
|
||||
'UI-ConfigurationItemsMenu-NWDevicesByCriticity' => 'Hálózati eszközök kritikusság szerint',
|
||||
'UI-ConfigurationItemsMenu-ApplicationsByCriticity' => 'Alkalmazások kritikusság szerint',
|
||||
'UI:ConfigurationManagementMenu' => 'Konfiguráció menedzsment',
|
||||
'UI:ConfigurationManagementMenu+' => '',
|
||||
'UI:ConfigurationManagementMenu:Title' => 'Infrastruktúra áttekintő',
|
||||
|
||||
@@ -741,6 +741,13 @@ Dict::Add('IT IT', 'Italian', 'Italiano', array(
|
||||
'UI-ChangeManagementMenu-ChangesByStatus' => 'Cambi per stato',
|
||||
'UI-ChangeManagementMenu-ChangesByWorkgroup' => 'Cambi per gruppi di lavoro',
|
||||
'UI-ChangeManagementMenu-ChangesNotYetAssigned' => 'Cambi non ancora assegnati',
|
||||
'UI:ConfigurationItemsMenu' => 'Configuration Items',
|
||||
'UI:ConfigurationItemsMenu+' => '',
|
||||
'UI:ConfigurationItemsMenu:Title' => 'Configuration Items Panoramica',
|
||||
'UI-ConfigurationItemsMenu-ServersByCriticity' => 'Server per criticità',
|
||||
'UI-ConfigurationItemsMenu-PCsByCriticity' => 'PCs per criticità',
|
||||
'UI-ConfigurationItemsMenu-NWDevicesByCriticity' => 'Dispositivi di rete per criticità',
|
||||
'UI-ConfigurationItemsMenu-ApplicationsByCriticity' => 'Applicazioni per criticità',
|
||||
'UI:ConfigurationManagementMenu' => 'Gestione Configurazione',
|
||||
'UI:ConfigurationManagementMenu+' => '',
|
||||
'UI:ConfigurationManagementMenu:Title' => 'Panoramica delle infrastrutture',
|
||||
|
||||
@@ -731,6 +731,14 @@ Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'UI-ChangeManagementMenu-ChangesByWorkgroup' => 'ワークグループ別変更内容', //'Changes by workgroup',
|
||||
'UI-ChangeManagementMenu-ChangesNotYetAssigned' => 'まだアサインされていない変更', //'Changes not yet assigned',
|
||||
|
||||
'UI:ConfigurationItemsMenu'=> '設定項目', //'Configuration Items',
|
||||
'UI:ConfigurationItemsMenu+'=> 'すべてのデバイス', //'All Devices',
|
||||
'UI:ConfigurationItemsMenu:Title' => '設定項目概観', //'Configuration Items Overview',
|
||||
'UI-ConfigurationItemsMenu-ServersByCriticity' => 'サーバ(by criticity)', // 'Servers by criticity',
|
||||
'UI-ConfigurationItemsMenu-PCsByCriticity' => 'PC (by criticity)', // 'PCs by criticity',
|
||||
'UI-ConfigurationItemsMenu-NWDevicesByCriticity' => 'ネットワークデバイス (by criticity)', // 'Network devices by criticity',
|
||||
'UI-ConfigurationItemsMenu-ApplicationsByCriticity' => 'アプリケーション (by criticity)', // 'Applications by criticity',
|
||||
|
||||
'UI:ConfigurationManagementMenu' => 'コンフィグレーション管理', //'Configuration Management',
|
||||
'UI:ConfigurationManagementMenu+' => 'コンフィグレーション管理', // 'Configuration Management',
|
||||
'UI:ConfigurationManagementMenu:Title' => 'インフラストラクチャ概観', // 'Infrastructure Overview',
|
||||
|
||||
@@ -755,6 +755,14 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
|
||||
'UI-ChangeManagementMenu-ChangesByWorkgroup' => 'Mudanças por grupo de trabalho',
|
||||
'UI-ChangeManagementMenu-ChangesNotYetAssigned' => 'Mudanças ainda não atribuídas',
|
||||
|
||||
'UI:ConfigurationItemsMenu'=> 'Configuração Itens',
|
||||
'UI:ConfigurationItemsMenu+'=> 'Todos dispositivos',
|
||||
'UI:ConfigurationItemsMenu:Title' => 'Configuração Itens visão geral',
|
||||
'UI-ConfigurationItemsMenu-ServersByCriticity' => 'Servidores por criticidade',
|
||||
'UI-ConfigurationItemsMenu-PCsByCriticity' => 'PCs por criticidade',
|
||||
'UI-ConfigurationItemsMenu-NWDevicesByCriticity' => 'Dispositivos de rede por criticidade',
|
||||
'UI-ConfigurationItemsMenu-ApplicationsByCriticity' => 'Aplicativos por criticidade',
|
||||
|
||||
'UI:ConfigurationManagementMenu' => 'Gerenciamento Configurações',
|
||||
'UI:ConfigurationManagementMenu+' => 'Gerenciamento Configurações',
|
||||
'UI:ConfigurationManagementMenu:Title' => 'Infrastructure Overview',
|
||||
|
||||
@@ -717,6 +717,14 @@ Dict::Add('RU RU', 'Russian', 'Русский', array(
|
||||
'UI-ChangeManagementMenu-ChangesByWorkgroup' => 'Изменения по рабочей группе',
|
||||
'UI-ChangeManagementMenu-ChangesNotYetAssigned' => 'Не назначенные изменения',
|
||||
|
||||
'UI:ConfigurationItemsMenu'=> 'Элементы конфигурации',
|
||||
'UI:ConfigurationItemsMenu+'=> 'Все устройства',
|
||||
'UI:ConfigurationItemsMenu:Title' => 'Обзор элементов конфигурации',
|
||||
'UI-ConfigurationItemsMenu-ServersByCriticity' => 'Серверы по критичности',
|
||||
'UI-ConfigurationItemsMenu-PCsByCriticity' => 'ПК по критичности',
|
||||
'UI-ConfigurationItemsMenu-NWDevicesByCriticity' => 'Сетевые устройства по критичности',
|
||||
'UI-ConfigurationItemsMenu-ApplicationsByCriticity' => 'Приложения по критичности',
|
||||
|
||||
'UI:ConfigurationManagementMenu' => 'Управление конфигурациями',
|
||||
'UI:ConfigurationManagementMenu+' => 'Управление конфигурациями',
|
||||
'UI:ConfigurationManagementMenu:Title' => 'Обзор инфраструктуры',
|
||||
|
||||
@@ -716,6 +716,14 @@ Dict::Add('TR TR', 'Turkish', 'Türkçe', array(
|
||||
'UI-ChangeManagementMenu-ChangesByWorkgroup' => 'İş grubuna değişiklikler',
|
||||
'UI-ChangeManagementMenu-ChangesNotYetAssigned' => 'Atanmamış Değişiklikler',
|
||||
|
||||
'UI:ConfigurationItemsMenu'=> 'Konfigürasyon kalemleri',
|
||||
'UI:ConfigurationItemsMenu+'=> 'Tüm cihazlar',
|
||||
'UI:ConfigurationItemsMenu:Title' => 'Konfigürasyon Kalemlerinin Özeti',
|
||||
'UI-ConfigurationItemsMenu-ServersByCriticity' => 'Servers by criticity',
|
||||
'UI-ConfigurationItemsMenu-PCsByCriticity' => 'PCs by criticity',
|
||||
'UI-ConfigurationItemsMenu-NWDevicesByCriticity' => 'Network devices by criticity',
|
||||
'UI-ConfigurationItemsMenu-ApplicationsByCriticity' => 'Applications by criticity',
|
||||
|
||||
'UI:ConfigurationManagementMenu' => 'Konfigürasyon Yönetimi',
|
||||
'UI:ConfigurationManagementMenu+' => 'Konfigürasyon Yönetimi',
|
||||
'UI:ConfigurationManagementMenu:Title' => 'Altyapı Özeti',
|
||||
@@ -865,7 +873,4 @@ Tetikleme gerçekleştiriğinde işlemler tanımlanan sıra numarası ile gerçe
|
||||
'Enum:Undefined' => 'Tanımsız',
|
||||
'UI:Button:Refresh' => 'Yenile',
|
||||
));
|
||||
|
||||
|
||||
|
||||
?>
|
||||
|
||||
@@ -715,6 +715,14 @@ Dict::Add('ZH CN', 'Chinese', '简体中文', array(
|
||||
'UI-ChangeManagementMenu-ChangesByWorkgroup' => '按工作组划分的变更',
|
||||
'UI-ChangeManagementMenu-ChangesNotYetAssigned' => '尚未指派的变更',
|
||||
|
||||
'UI:ConfigurationItemsMenu'=> '配置项目',
|
||||
'UI:ConfigurationItemsMenu+'=> '所有设备',
|
||||
'UI:ConfigurationItemsMenu:Title' => '配置项概览',
|
||||
'UI-ConfigurationItemsMenu-ServersByCriticity' => '按关键性划分服务器',
|
||||
'UI-ConfigurationItemsMenu-PCsByCriticity' => '按关键性划分PC',
|
||||
'UI-ConfigurationItemsMenu-NWDevicesByCriticity' => '按关键性划分网络设备',
|
||||
'UI-ConfigurationItemsMenu-ApplicationsByCriticity' => '按关键性划分应用程序',
|
||||
|
||||
'UI:ConfigurationManagementMenu' => '配置管理',
|
||||
'UI:ConfigurationManagementMenu+' => '配置管理',
|
||||
'UI:ConfigurationManagementMenu:Title' => '基础架构概览',
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 677 B |
Binary file not shown.
|
Before Width: | Height: | Size: 1.6 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user