mirror of
https://github.com/Combodo/iTop.git
synced 2026-02-16 00:44:10 +01:00
Compare commits
438 Commits
3.0.0-beta
...
3.0.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bac2918ceb | ||
|
|
604837c770 | ||
|
|
f32c283c9c | ||
|
|
27d06a712b | ||
|
|
b15050487c | ||
|
|
46f232d561 | ||
|
|
63976df2e1 | ||
|
|
3514e21772 | ||
|
|
3463b1715a | ||
|
|
0287500feb | ||
|
|
e4cbaf7096 | ||
|
|
73c6b4be20 | ||
|
|
fde2103659 | ||
|
|
24500216f6 | ||
|
|
2039b872d3 | ||
|
|
b368c593e5 | ||
|
|
c9c731a2a5 | ||
|
|
8204723b5b | ||
|
|
f93218a80f | ||
|
|
4f5a9c898c | ||
|
|
7ce5712b71 | ||
|
|
90b41e0b81 | ||
|
|
9d2c89f118 | ||
|
|
61137a6f65 | ||
|
|
a26c8fbd48 | ||
|
|
0080a2e733 | ||
|
|
992ee3a74b | ||
|
|
e45013891c | ||
|
|
ea043960ff | ||
|
|
d0f83046cd | ||
|
|
7f4fddb378 | ||
|
|
9cd076131f | ||
|
|
a71cb97db3 | ||
|
|
0c80a4e430 | ||
|
|
779211e638 | ||
|
|
4c99f497cc | ||
|
|
d1e2be97d2 | ||
|
|
93c6cfffda | ||
|
|
b50ba0ad49 | ||
|
|
0205cdf713 | ||
|
|
39fc59a8b2 | ||
|
|
107c9adf60 | ||
|
|
143c30b099 | ||
|
|
d29880b1b8 | ||
|
|
3edfc2016d | ||
|
|
5f80be75ed | ||
|
|
0d4796ae2b | ||
|
|
2d156bd77b | ||
|
|
5908ec5197 | ||
|
|
d122dbfdd6 | ||
|
|
46d58e6512 | ||
|
|
6cf781da33 | ||
|
|
0f2cbaf186 | ||
|
|
7ddb47dc83 | ||
|
|
304e379c01 | ||
|
|
93a138606f | ||
|
|
70074ee1cb | ||
|
|
d28ccb264f | ||
|
|
9f95d45f51 | ||
|
|
8ab38854a8 | ||
|
|
bceb570d84 | ||
|
|
138fa569f2 | ||
|
|
1f65ab5a92 | ||
|
|
7cfac7300b | ||
|
|
ede720c9b9 | ||
|
|
684efee5d2 | ||
|
|
e347989dcb | ||
|
|
e1051e7a47 | ||
|
|
7e8eb26866 | ||
|
|
6775a3e928 | ||
|
|
faa38155e5 | ||
|
|
558bbc3357 | ||
|
|
cd7f9e478f | ||
|
|
e3586cff65 | ||
|
|
106127e6b7 | ||
|
|
2299983db3 | ||
|
|
2fab7de34b | ||
|
|
c0ab79971c | ||
|
|
03ed9c9deb | ||
|
|
7152277760 | ||
|
|
14d05da9f6 | ||
|
|
69a0bd0c34 | ||
|
|
c09cee994a | ||
|
|
50ee0b3eed | ||
|
|
84169a864c | ||
|
|
9f27cf2b84 | ||
|
|
f78986009f | ||
|
|
4fdbec72d4 | ||
|
|
94d31827e7 | ||
|
|
45a8eb93e7 | ||
|
|
6ac3539373 | ||
|
|
a5d8425fe7 | ||
|
|
3608c6b8ab | ||
|
|
2b1e583dc7 | ||
|
|
3081aa473a | ||
|
|
809ea2eb49 | ||
|
|
2f98a3e7ac | ||
|
|
c737fc46ff | ||
|
|
619c0d34e8 | ||
|
|
bdc7ed6f8e | ||
|
|
d9819d9c2a | ||
|
|
f24f8a2f34 | ||
|
|
3890b1a020 | ||
|
|
2e08cff9ee | ||
|
|
968a0e5f3a | ||
|
|
4694e8152e | ||
|
|
4b731dd336 | ||
|
|
5e0c7c211b | ||
|
|
815870fe6b | ||
|
|
33ceab86fb | ||
|
|
fe1bf3bfc1 | ||
|
|
3727223db3 | ||
|
|
5b96d9f778 | ||
|
|
162b15236d | ||
|
|
83e98ef2b8 | ||
|
|
d783954d13 | ||
|
|
7207dc657c | ||
|
|
f1cce8e430 | ||
|
|
3da49e6603 | ||
|
|
5048421bfa | ||
|
|
b9c5f2c523 | ||
|
|
ec75195a2f | ||
|
|
e971d628dd | ||
|
|
bbd50ba73b | ||
|
|
ba71c1bcd5 | ||
|
|
16be8fd3d3 | ||
|
|
cacae0a2b3 | ||
|
|
b1ed15f31c | ||
|
|
788caf9c50 | ||
|
|
1728dcc40c | ||
|
|
35165568af | ||
|
|
cb5554ddb1 | ||
|
|
6a5840ed82 | ||
|
|
4a67819f87 | ||
|
|
81c39c35cd | ||
|
|
4caf52f1ae | ||
|
|
0c5b845c8a | ||
|
|
cdfdb1f2ca | ||
|
|
f29a8792af | ||
|
|
b494ff2ce6 | ||
|
|
a65c55fc48 | ||
|
|
01b94f42fe | ||
|
|
df1e19dc43 | ||
|
|
cbef9bb267 | ||
|
|
9ad341f73a | ||
|
|
03e9bcd47a | ||
|
|
55effea0a3 | ||
|
|
dfaa973359 | ||
|
|
2e45b20fc4 | ||
|
|
e89090f0ec | ||
|
|
c9d02826a0 | ||
|
|
47db04bcb7 | ||
|
|
a49c451ae4 | ||
|
|
25c3704990 | ||
|
|
3000659e86 | ||
|
|
ce36c00b83 | ||
|
|
2a3e6384d9 | ||
|
|
dd7e73e413 | ||
|
|
1709082e39 | ||
|
|
41f6e85673 | ||
|
|
3ef3166bd5 | ||
|
|
0d26211dbe | ||
|
|
3b99006159 | ||
|
|
299ad7e753 | ||
|
|
94a2421186 | ||
|
|
923c3a27a3 | ||
|
|
c1a1186bf7 | ||
|
|
b360514646 | ||
|
|
541794ca9c | ||
|
|
5fbcae1f55 | ||
|
|
0f6e0e5085 | ||
|
|
3541a9e1db | ||
|
|
1f95a4ee21 | ||
|
|
af5a0d5006 | ||
|
|
84280a3b5f | ||
|
|
e3bce622e5 | ||
|
|
ef9392a8d5 | ||
|
|
15087ab848 | ||
|
|
7bb7445c91 | ||
|
|
6a4ce3c3b1 | ||
|
|
7df27de5c1 | ||
|
|
b4fc647845 | ||
|
|
de053eed72 | ||
|
|
17612f88d3 | ||
|
|
e14845728c | ||
|
|
4e80fc0f76 | ||
|
|
fcfcf85e0d | ||
|
|
f0715baf7d | ||
|
|
2733e7966f | ||
|
|
52327d1086 | ||
|
|
81cf3df5e2 | ||
|
|
45b5c39af7 | ||
|
|
4463e91d85 | ||
|
|
ce87bf9e23 | ||
|
|
dbc3da7bc3 | ||
|
|
ebc9fa684a | ||
|
|
606bdc1909 | ||
|
|
7495fb9af4 | ||
|
|
75dbad7406 | ||
|
|
c95064b76d | ||
|
|
f0933eaf1e | ||
|
|
b9ea7d4913 | ||
|
|
9c75a705f3 | ||
|
|
3381c085f4 | ||
|
|
b89d181125 | ||
|
|
c3a2713bba | ||
|
|
99b73fe1ee | ||
|
|
151f42ceef | ||
|
|
627c0070c1 | ||
|
|
3a56824cde | ||
|
|
9b6f7d94f4 | ||
|
|
9a6d40e9db | ||
|
|
64e8aa5fee | ||
|
|
a839b1c4ae | ||
|
|
b58df7150f | ||
|
|
1cd230a543 | ||
|
|
fc47e031b6 | ||
|
|
477128ad53 | ||
|
|
3b4ba2aafd | ||
|
|
70f67068f4 | ||
|
|
4fec344799 | ||
|
|
cc5f7608e3 | ||
|
|
468de06fe1 | ||
|
|
aa20289dfe | ||
|
|
4449fdbbc5 | ||
|
|
04a690caff | ||
|
|
0156eb0dda | ||
|
|
e8448332f4 | ||
|
|
e8e6ceb29e | ||
|
|
1f42f897d8 | ||
|
|
aa66bec783 | ||
|
|
1da52a8517 | ||
|
|
cbd2181862 | ||
|
|
102528195b | ||
|
|
7def094291 | ||
|
|
ffb3edced5 | ||
|
|
17e8c53236 | ||
|
|
910638d93f | ||
|
|
d005ff0099 | ||
|
|
4fdf8803a5 | ||
|
|
06af788480 | ||
|
|
7aa1719514 | ||
|
|
81c0951c2a | ||
|
|
89ecdeb13b | ||
|
|
c6211cde09 | ||
|
|
739001eca4 | ||
|
|
7243da3576 | ||
|
|
c9d547030f | ||
|
|
4923ac7015 | ||
|
|
c1c264d6d8 | ||
|
|
0940741568 | ||
|
|
041a938fc0 | ||
|
|
839048fab2 | ||
|
|
4180a41f27 | ||
|
|
8ada56fc53 | ||
|
|
6c5ca614e0 | ||
|
|
4ddee0b624 | ||
|
|
135ddbf37d | ||
|
|
a43adcd202 | ||
|
|
e8e170fb06 | ||
|
|
5ac5d649aa | ||
|
|
ec0c98bb0f | ||
|
|
decb802df4 | ||
|
|
cacc3a3085 | ||
|
|
0fd2ea6a47 | ||
|
|
ab7e73ef9b | ||
|
|
31e7a5383c | ||
|
|
64afa07ff5 | ||
|
|
656bbfe46d | ||
|
|
426f275c03 | ||
|
|
b55ba2ac7f | ||
|
|
693a861e7d | ||
|
|
0ee6c60e94 | ||
|
|
a663e9fded | ||
|
|
b3bf516b20 | ||
|
|
c2408b74cd | ||
|
|
6855c2f83a | ||
|
|
b11bf30881 | ||
|
|
64736f1463 | ||
|
|
930b224ca2 | ||
|
|
c87de1024d | ||
|
|
24e6840a8b | ||
|
|
06ed048983 | ||
|
|
937313495d | ||
|
|
9493e31a5d | ||
|
|
92b61c7491 | ||
|
|
3a4c4cd33d | ||
|
|
9aa399894c | ||
|
|
bde5dc825d | ||
|
|
8578d18e7f | ||
|
|
9b0e55210d | ||
|
|
e530cbb4f2 | ||
|
|
ddb8378fe6 | ||
|
|
47db23d91c | ||
|
|
fc1f701bf6 | ||
|
|
ece31855af | ||
|
|
d57ef77758 | ||
|
|
365c7bb89e | ||
|
|
bf2c4dee1b | ||
|
|
11b812b5fc | ||
|
|
b073e4385c | ||
|
|
c37c46a4a8 | ||
|
|
f592d94af3 | ||
|
|
f9359431fe | ||
|
|
25e560fdaa | ||
|
|
0ce805b192 | ||
|
|
6bf25f90bc | ||
|
|
30d36fca81 | ||
|
|
ffd0bbb1a4 | ||
|
|
3db20e8028 | ||
|
|
ed12f98075 | ||
|
|
19eef5bd72 | ||
|
|
7b2bcd1055 | ||
|
|
108c1fcb2b | ||
|
|
ced29dea8e | ||
|
|
20a07d61c6 | ||
|
|
682c821d0e | ||
|
|
5f382ee053 | ||
|
|
dc81630b16 | ||
|
|
f84c095b22 | ||
|
|
9bfa60d272 | ||
|
|
3e51d010d2 | ||
|
|
b190d0e385 | ||
|
|
0bd64ef700 | ||
|
|
9665c7c947 | ||
|
|
dcf872bcd5 | ||
|
|
6254617814 | ||
|
|
fc4d19be5e | ||
|
|
88d6b63e12 | ||
|
|
60b24bad64 | ||
|
|
cde2f333b4 | ||
|
|
427ec288ef | ||
|
|
18041527c5 | ||
|
|
f58e2ce6c0 | ||
|
|
6312063cd3 | ||
|
|
d0c1f650d1 | ||
|
|
4511883baf | ||
|
|
1e6a4621ea | ||
|
|
2a0fc227de | ||
|
|
05e98be6c7 | ||
|
|
fe7fa2035d | ||
|
|
a00f4156ea | ||
|
|
4d37e2267f | ||
|
|
5055397024 | ||
|
|
2bb142e8ee | ||
|
|
93f273a287 | ||
|
|
04e7616c84 | ||
|
|
219b970703 | ||
|
|
408ca6d427 | ||
|
|
ae323d393d | ||
|
|
76c139253e | ||
|
|
2a50a543bf | ||
|
|
ee54d6869b | ||
|
|
bd753d65a4 | ||
|
|
2fe8f0e43b | ||
|
|
94cb5d3439 | ||
|
|
0ed2388cf8 | ||
|
|
b91dee6c0c | ||
|
|
02b09c2535 | ||
|
|
10cfb373f2 | ||
|
|
69578d5d07 | ||
|
|
97d6d413bb | ||
|
|
4f27f3ac37 | ||
|
|
4771908f42 | ||
|
|
d1751a042e | ||
|
|
99a0e0c58e | ||
|
|
7e0d5d64ce | ||
|
|
3f8f57fa9a | ||
|
|
434ce57b7e | ||
|
|
c1eb928893 | ||
|
|
97cf0a2534 | ||
|
|
ec02657113 | ||
|
|
600a629734 | ||
|
|
9acdb45482 | ||
|
|
e51bd4c95f | ||
|
|
71b3eb0ec7 | ||
|
|
c14c851e94 | ||
|
|
011ac0222c | ||
|
|
00580856ae | ||
|
|
9b6dabf5fb | ||
|
|
eb2a615bd2 | ||
|
|
cfc3a82c44 | ||
|
|
b23dac591e | ||
|
|
de004af288 | ||
|
|
f48cdd51f4 | ||
|
|
10d303f43f | ||
|
|
6a7c953344 | ||
|
|
0432727ace | ||
|
|
d0a4e541c3 | ||
|
|
d515816488 | ||
|
|
25a5ec4bcf | ||
|
|
4fbe391243 | ||
|
|
c9ef543e2e | ||
|
|
cd5286d03b | ||
|
|
e6d61d1ebd | ||
|
|
f916f9cde8 | ||
|
|
be06adc794 | ||
|
|
271c51f1f4 | ||
|
|
28e9f95f7c | ||
|
|
d4da1b99d8 | ||
|
|
28ecb77bf1 | ||
|
|
85effd0fb0 | ||
|
|
c89c47d671 | ||
|
|
6de4511601 | ||
|
|
00acf271e2 | ||
|
|
0e03e78490 | ||
|
|
99cbb6c996 | ||
|
|
0e36070f0a | ||
|
|
bc349253cf | ||
|
|
f3ed286ee0 | ||
|
|
efcd0654c7 | ||
|
|
d413ebff2d | ||
|
|
33f94b7886 | ||
|
|
817aded5aa | ||
|
|
5e61388b65 | ||
|
|
9e9cdd3d56 | ||
|
|
d7d430e2a3 | ||
|
|
09c4ba4044 | ||
|
|
3f795c7555 | ||
|
|
c451e61972 | ||
|
|
afc0a02058 | ||
|
|
a5bf059e23 | ||
|
|
9f0e2c0a3a | ||
|
|
910bbe1160 | ||
|
|
9addc4a7ca | ||
|
|
5ed71ecb96 | ||
|
|
e4c68936a0 | ||
|
|
3511867ba3 | ||
|
|
dcfdb2d0a9 | ||
|
|
0cbf34ba5a | ||
|
|
f1037147a9 | ||
|
|
bea52d5fb9 | ||
|
|
865f9f4f67 | ||
|
|
a7e54d4bad | ||
|
|
2fe4265223 | ||
|
|
ed719e13c7 | ||
|
|
2d705c6697 | ||
|
|
c98ad106c4 |
@@ -36,18 +36,24 @@ clearstatcache();
|
||||
$oiTopComposer = new iTopComposer();
|
||||
$aDeniedButStillPresent = $oiTopComposer->ListDeniedButStillPresent();
|
||||
|
||||
echo "\n";
|
||||
foreach ($aDeniedButStillPresent as $sDir)
|
||||
{
|
||||
if (! preg_match('#[tT]ests?/?$#', $sDir))
|
||||
if (false === iTopComposer::IsTestDir($sDir))
|
||||
{
|
||||
echo "\nfound INVALID denied test dir: '$sDir'\n";
|
||||
echo "ERROR found INVALID denied test dir: '$sDir'\n";
|
||||
throw new \Exception("$sDir must end with /Test/ or /test/");
|
||||
}
|
||||
|
||||
if (false === file_exists($sDir)) {
|
||||
echo "INFO $sDir is in denied list, but not existing on disk => skipping !\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
SetupUtils::rrmdir($sDir);
|
||||
echo "Remove denied test dir: '$sDir'\n";
|
||||
echo "OK Remove denied test dir: '$sDir'\n";
|
||||
}
|
||||
catch (\Exception $e)
|
||||
{
|
||||
|
||||
@@ -25,8 +25,8 @@ require_once (__DIR__.DIRECTORY_SEPARATOR.'update.classes.inc.php');
|
||||
/** @var \FileVersionUpdater[] $aFilesUpdaters */
|
||||
$aFilesUpdaters = array(
|
||||
new iTopVersionFileUpdater(),
|
||||
new CssVariablesFileUpdater(),
|
||||
new DatamodelsModulesFiles(),
|
||||
new ConstantFileUpdater('ITOP_CORE_VERSION', 'approot.inc.php'),
|
||||
);
|
||||
|
||||
if (count($argv) === 1)
|
||||
|
||||
@@ -69,6 +69,40 @@ abstract class AbstractSingleFileVersionUpdater extends FileVersionUpdater
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°4714
|
||||
*/
|
||||
class ConstantFileUpdater extends AbstractSingleFileVersionUpdater {
|
||||
/** @var string */
|
||||
private $sConstantName;
|
||||
|
||||
/**
|
||||
* @param $sConstantName constant to search, for example `ITOP_CORE_VERSION`
|
||||
* @param $sFileToUpdate file containing constant definition
|
||||
*/
|
||||
public function __construct($sConstantName, $sFileToUpdate)
|
||||
{
|
||||
$this->sConstantName = $sConstantName;
|
||||
parent::__construct($sFileToUpdate);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function UpdateFileContent($sVersionLabel, $sFileContent, $sFileFullPath)
|
||||
{
|
||||
$sConstantSearchPattern = <<<REGEXP
|
||||
/define\('{$this->sConstantName}', ?'[^']+'\);/
|
||||
REGEXP;
|
||||
|
||||
return preg_replace(
|
||||
$sConstantSearchPattern,
|
||||
"define('{$this->sConstantName}', '{$sVersionLabel}');",
|
||||
$sFileContent
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class iTopVersionFileUpdater extends AbstractSingleFileVersionUpdater
|
||||
{
|
||||
public function __construct()
|
||||
@@ -89,26 +123,6 @@ class iTopVersionFileUpdater extends AbstractSingleFileVersionUpdater
|
||||
}
|
||||
}
|
||||
|
||||
class CssVariablesFileUpdater extends AbstractSingleFileVersionUpdater
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('css/css-variables.scss');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function UpdateFileContent($sVersionLabel, $sFileContent, $sFileFullPath)
|
||||
{
|
||||
return preg_replace(
|
||||
'/(\$version: "v)[^"]*(";)/',
|
||||
'${1}'.$sVersionLabel.'${2}',
|
||||
$sFileContent
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
abstract class AbstractGlobFileVersionUpdater extends FileVersionUpdater
|
||||
{
|
||||
protected $sGlobPattern;
|
||||
|
||||
11
README.md
11
README.md
@@ -78,18 +78,19 @@ We would like to give a special thank you 🤗 to the people from the community
|
||||
|
||||
- Alves, David
|
||||
- Beck, Pedro
|
||||
- Beer, Christian (a.k.a [@ChristianBeer](https://www.github.com/ChristianBeer))
|
||||
- Bilger, Jean-François
|
||||
- Bostoen, Jeffrey (a.k.a @jbostoen)
|
||||
- Bostoen, Jeffrey (a.k.a [@jbostoen](https://www.github.com/jbostoen))
|
||||
- Cardoso, Anderson
|
||||
- Cassaro, Bruno
|
||||
- Casteleyn, Thomas (a.k.a @Hipska)
|
||||
- Casteleyn, Thomas (a.k.a [@Hipska](https://www.github.com/Hipska))
|
||||
- Castro, Randall Badilla
|
||||
- Colantoni, Maria Laura
|
||||
- Couronné, Guy
|
||||
- Dvořák, Lukáš
|
||||
- Goethals, Stefan
|
||||
- Gumble, David
|
||||
- Kaltefleiter, Lars (a.k.a @larhip)
|
||||
- Kaltefleiter, Lars (a.k.a [@larhip](https://www.github.com/larhip))
|
||||
- Khamit, Shamil
|
||||
- Kincel, Martin
|
||||
- Konečný, Kamil
|
||||
@@ -98,12 +99,12 @@ We would like to give a special thank you 🤗 to the people from the community
|
||||
- Lazcano, Federico
|
||||
- Lucas, Jonathan
|
||||
- Malik, Remie
|
||||
- Mindêllo de Andrade, Lucas (a.k.a @rokam)
|
||||
- Mindêllo de Andrade, Lucas (a.k.a [@rokam](https://www.github.com/rokam))
|
||||
- Raenker, Martin
|
||||
- Rosenke, Stephan
|
||||
- Seki, Shoji
|
||||
- Shilov, Vladimir
|
||||
- Stukalov, Ilya (a.k.a @ilya-stukalov)
|
||||
- Stukalov, Ilya (a.k.a [@ilya](https://www.github.com/ilya)-stukalov)
|
||||
- Tulio, Marco
|
||||
- Turrubiates, Miguel
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ define('PORTAL_PROFILE_NAME', 'Portal user');
|
||||
class UserRightsBaseClassGUI extends cmdbAbstractObject
|
||||
{
|
||||
// Whenever something changes, reload the privileges
|
||||
|
||||
|
||||
protected function AfterInsert()
|
||||
{
|
||||
UserRights::FlushPrivileges();
|
||||
@@ -59,7 +59,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
}
|
||||
|
||||
protected static $m_aCacheProfiles = null;
|
||||
|
||||
|
||||
public static function DoCreateProfile($sName, $sDescription)
|
||||
{
|
||||
if (is_null(self::$m_aCacheProfiles))
|
||||
@@ -71,7 +71,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
{
|
||||
self::$m_aCacheProfiles[$oProfile->Get('name')] = $oProfile->GetKey();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$sCacheKey = $sName;
|
||||
if (isset(self::$m_aCacheProfiles[$sCacheKey]))
|
||||
@@ -82,10 +82,10 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
$oNewObj->Set('name', $sName);
|
||||
$oNewObj->Set('description', $sDescription);
|
||||
$iId = $oNewObj->DBInsertNoReload();
|
||||
self::$m_aCacheProfiles[$sCacheKey] = $iId;
|
||||
self::$m_aCacheProfiles[$sCacheKey] = $iId;
|
||||
return $iId;
|
||||
}
|
||||
|
||||
|
||||
function GetGrantAsHtml($oUserRights, $sClass, $sAction)
|
||||
{
|
||||
$bGrant = $oUserRights->GetProfileActionGrant($this->GetKey(), $sClass, $sAction);
|
||||
@@ -102,7 +102,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
return '<span style="background-color: #ffdddd;">'.Dict::S('UI:UserManagement:ActionAllowed:No').'</span>';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function DoShowGrantSumary($oPage)
|
||||
{
|
||||
if ($this->GetRawName() == "Administrator")
|
||||
@@ -114,7 +114,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
|
||||
// Note: for sure, we assume that the instance is derived from UserRightsProfile
|
||||
$oUserRights = UserRights::GetModuleInstance();
|
||||
|
||||
|
||||
$aDisplayData = array();
|
||||
foreach (MetaModel::GetClasses('bizmodel,grant_by_profile') as $sClass)
|
||||
{
|
||||
@@ -123,12 +123,12 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
{
|
||||
$bGrant = $oUserRights->GetClassStimulusGrant($this->GetKey(), $sClass, $sStimulusCode);
|
||||
if ($bGrant === true)
|
||||
{
|
||||
{
|
||||
$aStimuli[] = '<span title="'.$sStimulusCode.': '.htmlentities($oStimulus->GetDescription(), ENT_QUOTES, 'UTF-8').'">'.htmlentities($oStimulus->GetLabel(), ENT_QUOTES, 'UTF-8').'</span>';
|
||||
}
|
||||
}
|
||||
$sStimuli = implode(', ', $aStimuli);
|
||||
|
||||
|
||||
$aDisplayData[] = array(
|
||||
'class' => MetaModel::GetName($sClass),
|
||||
'read' => $this->GetGrantAsHtml($oUserRights, $sClass, 'r'),
|
||||
@@ -140,7 +140,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
'stimuli' => $sStimuli,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
$aDisplayConfig = array();
|
||||
$aDisplayConfig['class'] = array('label' => Dict::S('UI:UserManagement:Class'), 'description' => Dict::S('UI:UserManagement:Class+'));
|
||||
$aDisplayConfig['read'] = array('label' => Dict::S('UI:UserManagement:Action:Read'), 'description' => Dict::S('UI:UserManagement:Action:Read+'));
|
||||
@@ -198,7 +198,7 @@ class URP_Profiles extends UserRightsBaseClassGUI
|
||||
* @param $aReasons array To store the reasons why the attribute is read-only (info about the synchro replicas)
|
||||
* @param $sTargetState string The target state in which to evalutate the flags, if empty the current state will be used
|
||||
* @return integer Flags: the binary combination of the flags applicable to this attribute
|
||||
*/
|
||||
*/
|
||||
public function GetAttributeFlags($sAttCode, &$aReasons = array(), $sTargetState = '')
|
||||
{
|
||||
$iFlags = parent::GetAttributeFlags($sAttCode, $aReasons, $sTargetState);
|
||||
@@ -404,7 +404,7 @@ class URP_UserOrg extends UserRightsBaseClassGUI
|
||||
{
|
||||
if (!UserRights::IsLoggedIn() || UserRights::IsAdministrator()) { return; }
|
||||
|
||||
$oUser = UserRights::GetUserObject();
|
||||
$oUser = UserRights::GetUserObject();
|
||||
$oAddon = UserRights::GetModuleInstance();
|
||||
$aOrgs = $oAddon->GetUserOrgs($oUser, '');
|
||||
if (count($aOrgs) > 0)
|
||||
@@ -528,7 +528,7 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
$oSearch->AllowAllData();
|
||||
$oCondition = new BinaryExpression(new FieldExpression('userid'), '=', new VariableExpression('userid'));
|
||||
$oSearch->AddConditionExpression($oCondition);
|
||||
|
||||
|
||||
$oUserOrgSet = new DBObjectSet($oSearch, array(), array('userid' => $iUser));
|
||||
while ($oUserOrg = $oUserOrgSet->Fetch())
|
||||
{
|
||||
@@ -738,8 +738,10 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
// load and cache permissions for the current user on the given class
|
||||
//
|
||||
$iUser = $oUser->GetKey();
|
||||
$aTest = @$this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode];
|
||||
if (is_array($aTest)) return $aTest;
|
||||
if (isset($this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode])){
|
||||
$aTest = $this->m_aObjectActionGrants[$iUser][$sClass][$iActionCode];
|
||||
if (is_array($aTest)) return $aTest;
|
||||
}
|
||||
|
||||
$sAction = self::$m_aActionCodes[$iActionCode];
|
||||
|
||||
@@ -905,8 +907,8 @@ class UserRightsProfile extends UserRightsAddOnAPI
|
||||
|
||||
/**
|
||||
* Find out which attribute is corresponding the the dimension 'owner org'
|
||||
* returns null if no such attribute has been found (no filtering should occur)
|
||||
*/
|
||||
* returns null if no such attribute has been found (no filtering should occur)
|
||||
*/
|
||||
public static function GetOwnerOrganizationAttCode($sClass)
|
||||
{
|
||||
$sAttCode = null;
|
||||
|
||||
@@ -1367,6 +1367,38 @@ interface iBackofficeStyleExtension
|
||||
public function GetStyle(): string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement this interface to add Dict entries
|
||||
*
|
||||
* @see \iTopWebPage::$a_dict_entries
|
||||
* @api
|
||||
* @since 3.0.0
|
||||
*/
|
||||
interface iBackofficeDictEntriesExtension
|
||||
{
|
||||
/**
|
||||
* @see \iTopWebPage::a_dict_entries
|
||||
* @return array
|
||||
*/
|
||||
public function GetDictEntries(): array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement this interface to add Dict entries prefixes
|
||||
*
|
||||
* @see \iTopWebPage::$a_dict_entries_prefixes
|
||||
* @api
|
||||
* @since 3.0.0
|
||||
*/
|
||||
interface iBackofficeDictEntriesPrefixesExtension
|
||||
{
|
||||
/**
|
||||
* @see \iTopWebPage::a_dict_entries_prefixes
|
||||
* @return array
|
||||
*/
|
||||
public function GetDictEntriesPrefixes(): array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement this interface to add content to any enhanced portal page
|
||||
*
|
||||
|
||||
@@ -251,7 +251,7 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param \DBObject $oObj
|
||||
* @param \cmdbAbstractObject $oObj
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
@@ -285,6 +285,7 @@ JS
|
||||
);
|
||||
|
||||
$oObj->Reload();
|
||||
$oObj->SetDisplayMode(static::ENUM_DISPLAY_MODE_VIEW);
|
||||
$oObj->DisplayDetails($oPage, false);
|
||||
}
|
||||
|
||||
@@ -390,7 +391,8 @@ JS
|
||||
$oSingletonFilter = new DBObjectSearch(get_class($this));
|
||||
$oSingletonFilter->AddCondition('id', $this->GetKey(), '=');
|
||||
$oBlock = new MenuBlock($oSingletonFilter, 'details', false);
|
||||
$oActionMenuBlock = $oBlock->GetRenderContent($oPage);
|
||||
$sActionMenuId = utils::Sanitize(uniqid('', true), '', utils::ENUM_SANITIZATION_FILTER_ELEMENT_IDENTIFIER);
|
||||
$oActionMenuBlock = $oBlock->GetRenderContent($oPage, [], $sActionMenuId);
|
||||
$aHeaderBlocks['toolbar'][$oActionMenuBlock->GetId()] = $oActionMenuBlock;
|
||||
}
|
||||
|
||||
@@ -648,11 +650,17 @@ HTML
|
||||
if ($oAttDef instanceof AttributeDashboard) {
|
||||
if (!$this->IsNew()) {
|
||||
$sHostContainerInEditionUrlParam = ($bEditMode) ? '&host_container_in_edition=true' : '';
|
||||
$oPage->AddAjaxTab($oAttDef->GetLabel(),
|
||||
utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=dashboard&class='.get_class($this).'&id='.$this->GetKey().'&attcode='.$oAttDef->GetCode().$sHostContainerInEditionUrlParam,
|
||||
true,
|
||||
$oPage->AddAjaxTab(
|
||||
'Class:'.$sClass.'/Attribute:'.$sAttCode,
|
||||
AjaxTab::ENUM_TAB_PLACEHOLDER_DASHBOARD);
|
||||
utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=dashboard&class='
|
||||
.get_class($this)
|
||||
.'&id='.$this->GetKey()
|
||||
.'&attcode='.$oAttDef->GetCode()
|
||||
.$sHostContainerInEditionUrlParam,
|
||||
true,
|
||||
$oAttDef->GetLabel(),
|
||||
AjaxTab::ENUM_TAB_PLACEHOLDER_DASHBOARD
|
||||
);
|
||||
// Add graphs dependencies
|
||||
WebResourcesHelper::EnableC3JSToWebPage($oPage);
|
||||
}
|
||||
@@ -936,6 +944,7 @@ HTML
|
||||
$aFieldsComments = (isset($aExtraParams['fieldsComments'])) ? $aExtraParams['fieldsComments'] : array();
|
||||
$aExtraFlags = (isset($aExtraParams['fieldsFlags'])) ? $aExtraParams['fieldsFlags'] : array();
|
||||
|
||||
$bHasFieldsWithRichTextEditor = false;
|
||||
foreach ($aDetailsStruct as $sTab => $aCols) {
|
||||
ksort($aCols);
|
||||
$oPage->SetCurrentTab($sTab);
|
||||
@@ -960,6 +969,10 @@ HTML
|
||||
continue;
|
||||
}
|
||||
|
||||
if (($oAttDef instanceof AttributeText) && ($oAttDef->GetFormat() === 'html')) {
|
||||
$bHasFieldsWithRichTextEditor = true;
|
||||
}
|
||||
|
||||
$sAttDefClass = get_class($oAttDef);
|
||||
$sAttLabel = MetaModel::GetLabel($sClass, $sAttCode);
|
||||
|
||||
@@ -1023,7 +1036,7 @@ HTML
|
||||
// Attribute description
|
||||
$sDescription = $oAttDef->GetDescription();
|
||||
$sDescriptionForHTMLTag = utils::HtmlEntities($sDescription);
|
||||
$sDescriptionHTMLTag = (empty($sDescriptionForHTMLTag) || $sDescription === $oAttDef->GetLabel()) ? '' : 'class="ibo-has-description" data-tooltip-content="'.$sDescriptionForHTMLTag.'"';
|
||||
$sDescriptionHTMLTag = (empty($sDescriptionForHTMLTag) || $sDescription === $oAttDef->GetLabel()) ? '' : 'class="ibo-has-description" data-tooltip-content="'.$sDescriptionForHTMLTag.'" data-tooltip-max-width="600px"';
|
||||
|
||||
$val = array(
|
||||
'label' => '<span '.$sDescriptionHTMLTag.' >'.$oAttDef->GetLabel().'</span>',
|
||||
@@ -1040,7 +1053,7 @@ HTML
|
||||
// Attribute description
|
||||
$sDescription = $oAttDef->GetDescription();
|
||||
$sDescriptionForHTMLTag = utils::HtmlEntities($sDescription);
|
||||
$sDescriptionHTMLTag = (empty($sDescriptionForHTMLTag) || $sDescription === $oAttDef->GetLabel()) ? '' : 'class="ibo-has-description" data-tooltip-content="'.$sDescriptionForHTMLTag.'"';
|
||||
$sDescriptionHTMLTag = (empty($sDescriptionForHTMLTag) || $sDescription === $oAttDef->GetLabel()) ? '' : 'class="ibo-has-description" data-tooltip-content="'.$sDescriptionForHTMLTag.' "data-tooltip-max-width="600px"';
|
||||
|
||||
$val = array(
|
||||
'label' => '<span '.$sDescriptionHTMLTag.' >'.$oAttDef->GetLabel().'</span>',
|
||||
@@ -1100,6 +1113,11 @@ HTML
|
||||
}
|
||||
}
|
||||
|
||||
// Fields with CKEditor need to have the highlight.js lib loaded even if they are in read-only, as it is needed to format code snippets
|
||||
if ($bHasFieldsWithRichTextEditor) {
|
||||
WebResourcesHelper::EnableCKEditorToWebPage($oPage);
|
||||
}
|
||||
|
||||
return $aFieldsMap;
|
||||
}
|
||||
|
||||
@@ -1728,6 +1746,9 @@ HTML
|
||||
* @param array $aParams
|
||||
*
|
||||
* @throws \Exception
|
||||
* only used in old and deprecated export.php
|
||||
*
|
||||
* @internal Only to be used by `/webservices/export.php` : this is a legacy method that produces wrong HTML (no TR on table body rows)
|
||||
*/
|
||||
public static function DisplaySetAsHTMLSpreadsheet(WebPage $oPage, CMDBObjectSet $oSet, $aParams = array())
|
||||
{
|
||||
@@ -1748,6 +1769,8 @@ HTML
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \Exception
|
||||
*
|
||||
* @internal Only to be used by `/webservices/export.php` : this is a legacy method that produces wrong HTML (no TR on table body rows)
|
||||
*/
|
||||
public static function GetSetAsHTMLSpreadsheet(DBObjectSet $oSet, $aParams = array())
|
||||
{
|
||||
@@ -2298,8 +2321,7 @@ EOF
|
||||
);
|
||||
break;
|
||||
|
||||
// TODO 3.0.0: Isn't this part obsolete now that we have the activity panel or should we keep it for devs using it in custom extensions or maybe *transition forms* as a caselog can be MUST_PROMPT?
|
||||
// used for bulk modify in 3.0
|
||||
// In 3.0 not used for activity panel but kept for bulk modify and bulk-event extension
|
||||
case 'CaseLog':
|
||||
$sInputType = self::ENUM_INPUT_TYPE_HTML_EDITOR;
|
||||
$aStyles = array();
|
||||
@@ -2316,16 +2338,15 @@ EOF
|
||||
$sStyle = 'style="'.implode('; ', $aStyles).'"';
|
||||
}
|
||||
|
||||
$sHeader = '<div class="caselog_input_header"></div>'; // will be hidden in CSS (via :empty) if it remains empty
|
||||
$sHeader = '<div class="ibo-caselog-entry-form--actions"><div class="""ibo-caselog-entry-form--actions" data-role="ibo-caselog-entry-form--action-buttons--extra-actions"></div></div>'; // will be hidden in CSS (via :empty) if it remains empty
|
||||
$sEditValue = is_object($value) ? $value->GetModifiedEntry('html') : '';
|
||||
$sPreviousLog = is_object($value) ? $value->GetAsHTML($oPage, true /* bEditMode */,
|
||||
array('AttributeText', 'RenderWikiHtml')) : '';
|
||||
$sPreviousLog = is_object($value) ? $value->GetAsHTML($oPage, true /* bEditMode */, array('AttributeText', 'RenderWikiHtml')) : '';
|
||||
$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=\"field_input_zone field_input_caselog caselog\" $sStyle>$sHeader<textarea class=\"htmlEditor\" 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</div>{$sValidationSpan}{$sReloadSpan}$sHidden";
|
||||
$sHTMLValue = "$sHeader<div class=\"ibo-caselog-entry-form--text-input\" $sStyle data-role=\"ibo-caselog-entry-form--text-input\">";
|
||||
$sHTMLValue .= "<textarea class=\"htmlEditor ibo-input-richtext-placeholder\" 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>";
|
||||
$sHTMLValue .= "$sPreviousLog</div>{$sValidationSpan}{$sReloadSpan}$sHidden";
|
||||
|
||||
// Note: This should be refactored for all types of attribute (see at the end of this function) but as we are doing this for a maintenance release, we are scheduling it for the next main release in to order to avoid regressions as much as possible.
|
||||
$sNullValue = $oAttDef->GetNullValue();
|
||||
@@ -3616,7 +3637,7 @@ EOF
|
||||
// - Attribute description
|
||||
$sDescription = $oAttDef->GetDescription();
|
||||
$sDescriptionForHTMLAttributes = utils::HtmlEntities($sDescription);
|
||||
$sDescriptionHTMLAttributes = (empty($sDescriptionForHTMLAttributes) || $sDescription === $oAttDef->GetLabel()) ? '' : 'class="ibo-has-description" data-tooltip-content="'.$sDescriptionForHTMLAttributes.'"';
|
||||
$sDescriptionHTMLAttributes = (empty($sDescriptionForHTMLAttributes) || $sDescription === $oAttDef->GetLabel()) ? '' : 'class="ibo-has-description" data-tooltip-content="'.$sDescriptionForHTMLAttributes.'" data-tooltip-max-width="600px"';
|
||||
|
||||
// - Fullscreen toggler for large fields
|
||||
$sFullscreenTogglerTooltip = Dict::S('UI:ToggleFullScreen');
|
||||
@@ -4222,13 +4243,20 @@ HTML;
|
||||
if (!is_null($oImage->GetData()))
|
||||
{
|
||||
$aSize = utils::GetImageSize($oImage->GetData());
|
||||
$oImage = utils::ResizeImageToFit(
|
||||
$oImage,
|
||||
$aSize[0],
|
||||
$aSize[1],
|
||||
$oAttDef->Get('storage_max_width'),
|
||||
$oAttDef->Get('storage_max_height')
|
||||
);
|
||||
if (is_array($aSize) && $aSize[0] > 0 && $aSize[1] > 0)
|
||||
{
|
||||
$oImage = utils::ResizeImageToFit(
|
||||
$oImage,
|
||||
$aSize[0],
|
||||
$aSize[1],
|
||||
$oAttDef->Get('storage_max_width'),
|
||||
$oAttDef->Get('storage_max_height')
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
IssueLog::Warning($sClass . ':' . $this->GetKey() . '/' . $sAttCode . ': Image could not be resized. Mimetype: ' . $oImage->GetMimeType() . ', filename: ' . $oImage->GetFileName());
|
||||
}
|
||||
}
|
||||
$aOtherData = utils::ReadPostedParam("attr_{$sFormPrefix}{$sAttCode}", null, 'raw_data');
|
||||
if (is_array($aOtherData))
|
||||
@@ -5656,7 +5684,7 @@ EOF
|
||||
oOwnershipLockModal.text(data.popup_message);
|
||||
oOwnershipLockModal.dialog('open');
|
||||
}
|
||||
$('.object-details form .ibo-toolbar .ibo-button:not([name="cancel"])').prop('disabled', true);
|
||||
$('.ibo-object-details .ibo-toolbar .ibo-button:not([name="cancel"])').prop('disabled', true);
|
||||
clearInterval(hOwnershipLockHandlerInterval);
|
||||
}
|
||||
else if ((data.operation == 'lost') || (data.operation == 'expired'))
|
||||
@@ -5667,7 +5695,7 @@ EOF
|
||||
oOwnershipLockModal.text(data.popup_message);
|
||||
oOwnershipLockModal.dialog('open');
|
||||
}
|
||||
$('.object-details form .ibo-toolbar .ibo-button:not([name="cancel"])').prop('disabled', true);
|
||||
$('.ibo-object-details .ibo-toolbar .ibo-button:not([name="cancel"])').prop('disabled', true);
|
||||
clearInterval(hOwnershipLockHandlerInterval);
|
||||
}
|
||||
}, 'json');
|
||||
|
||||
@@ -583,7 +583,7 @@ JS
|
||||
$oPage->add('<div id="select_dashlet" class="ibo-dashboard--available-dashlets--list" data-role="ibo-dashboard--available-dashlets--list">');
|
||||
$aAvailableDashlets = $this->GetAvailableDashlets();
|
||||
foreach ($aAvailableDashlets as $sDashletClass => $aInfo) {
|
||||
$oPage->add('<span dashlet_class="'.$sDashletClass.'" class="ibo-dashboard-editor--available-dashlet-icon dashlet_icon ui-widget-content ui-corner-all" data-role="ibo-dashboard-editor--available-dashlet-icon" id="dashlet_'.$sDashletClass.'" title="'.$aInfo['label'].'"><img src="'.$sUrl.$aInfo['icon'].'" /></span>');
|
||||
$oPage->add('<span dashlet_class="'.$sDashletClass.'" class="ibo-dashboard-editor--available-dashlet-icon dashlet_icon ui-widget-content ui-corner-all" data-role="ibo-dashboard-editor--available-dashlet-icon" id="dashlet_'.$sDashletClass.'" data-tooltip-content="'.$aInfo['label'].'" title="'.$aInfo['label'].'"><img src="'.$sUrl.$aInfo['icon'].'" /></span>');
|
||||
}
|
||||
$oPage->add('</div>');
|
||||
|
||||
@@ -1066,11 +1066,11 @@ EOF
|
||||
dashboard.html(data);
|
||||
dashboard.unblock();
|
||||
if ($('#ibo-dashboard-selector$sDivId input').prop("checked")) {
|
||||
$('#ibo-dashboard-selector$sDivId').data('tooltip-content', '$sSwitchToStandard');
|
||||
$('#ibo-dashboard-selector$sDivId').attr('data-tooltip-content', '$sSwitchToStandard');
|
||||
} else {
|
||||
$('#ibo-dashboard-selector$sDivId').data('tooltip-content', '$sSwitchToCustom');
|
||||
$('#ibo-dashboard-selector$sDivId').attr('data-tooltip-content', '$sSwitchToCustom');
|
||||
}
|
||||
CombodoTooltip.InitAllNonInstantiatedTooltips($('#ibo-dashboard-selector$sDivId').parent());
|
||||
CombodoTooltip.InitAllNonInstantiatedTooltips($('#ibo-dashboard-selector$sDivId').parent(), true);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -174,6 +174,8 @@ class DisplayBlock
|
||||
/** string Max. height of the list, if not specified will occupy all the available height no matter the pagination */
|
||||
'localize_values',
|
||||
/** param for export.php */
|
||||
'refresh_action',
|
||||
/**to add refresh button in datatable*/
|
||||
], DataTableUIBlockFactory::GetAllowedParams()),
|
||||
'list_search' => array_merge([
|
||||
'update_history',
|
||||
@@ -537,8 +539,10 @@ class DisplayBlock
|
||||
* @throws DictExceptionMissingString
|
||||
* @throws MySQLException
|
||||
* @throws Exception
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 add type hinting to $aExtraParams
|
||||
*/
|
||||
public function GetRenderContent(WebPage $oPage, array $aExtraParams = [], string $sId = null)
|
||||
public function GetRenderContent(WebPage $oPage, array $aExtraParams, string $sId)
|
||||
{
|
||||
$sHtml = '';
|
||||
$oBlock = null;
|
||||
@@ -851,7 +855,7 @@ JS
|
||||
{
|
||||
$oField = new FieldExpression($sFilterCode, $oFilter->GetClassAlias());
|
||||
$sListExpr = '('.implode(', ', CMDBSource::Quote($condition)).')';
|
||||
$sOQLCondition = $oField->Render()." IN $sListExpr";
|
||||
$sOQLCondition = $oField->RenderExpression()." IN $sListExpr";
|
||||
$oNewCondition = Expression::FromOQL($sOQLCondition);
|
||||
return $oNewCondition;
|
||||
}
|
||||
@@ -1050,6 +1054,11 @@ JS
|
||||
$oBlock->AddSubBlock($oPill);
|
||||
}
|
||||
$aExtraParams['query_params'] = $this->m_oFilter->GetInternalParams();
|
||||
if(isset($aExtraParams['query_params']['this->object()'])){
|
||||
$aExtraParams['query_params']['this->class'] = get_class($aExtraParams['query_params']['this->object()']);
|
||||
$aExtraParams['query_params']['this->id'] = $aExtraParams['query_params']['this->object()']->GetKey();
|
||||
unset($aExtraParams['query_params']['this->object()']);
|
||||
}
|
||||
$aRefreshParams = ['filter' => $this->m_oFilter->ToOQL(), "extra_params" => json_encode($aExtraParams)];
|
||||
$oBlock->SetJSRefresh(
|
||||
"$('#".$oBlock->GetId()."').block();
|
||||
@@ -1728,7 +1737,24 @@ class HistoryBlock extends DisplayBlock
|
||||
$this->iLimitCount = $iCount;
|
||||
}
|
||||
|
||||
public function GetRenderContent(WebPage $oPage, array $aExtraParams = [], string $sId = null)
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param array $aExtraParams
|
||||
* @param string $sId
|
||||
*
|
||||
* @return string
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $aExtraParams and add type hinting for PHP 8.0 compatibility
|
||||
* (var is unused, and all calls were already made using a default value)
|
||||
*/
|
||||
public function GetRenderContent(WebPage $oPage, array $aExtraParams, string $sId)
|
||||
{
|
||||
$sHtml = '';
|
||||
$bTruncated = false;
|
||||
@@ -1869,11 +1895,10 @@ class MenuBlock extends DisplayBlock
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
* @throws \ReflectionException
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value and add type hinting on $aExtraParams for PHP 8.0 compatibility
|
||||
*/
|
||||
public function GetRenderContent(WebPage $oPage, array $aExtraParams = [], string $sId = null)
|
||||
public function GetRenderContent(WebPage $oPage, array $aExtraParams, string $sId)
|
||||
{
|
||||
$oRenderBlock = new UIContentBlock();
|
||||
|
||||
@@ -1884,7 +1909,7 @@ class MenuBlock extends DisplayBlock
|
||||
|
||||
$sClass = $this->m_oFilter->GetClass();
|
||||
$oSet = new CMDBObjectSet($this->m_oFilter);
|
||||
$sRefreshAction = $aExtraParams['sRefreshAction'] ?? '';
|
||||
$sRefreshAction = $aExtraParams['refresh_action'] ?? '';
|
||||
|
||||
/** @var array $aRegularActions Any action other than a transition */
|
||||
$aRegularActions = [];
|
||||
@@ -2220,8 +2245,14 @@ class MenuBlock extends DisplayBlock
|
||||
}
|
||||
if ($oPopupMenuItemsBlock->HasSubBlocks()) {
|
||||
$oRenderBlock->AddSubBlock($oPopupMenuItemsBlock);
|
||||
} else {
|
||||
foreach ($oPopupMenuItemsBlock->GetJsFilesRelPaths() as $sJsPath) {
|
||||
$oRenderBlock->AddJsFileRelPath($sJsPath);
|
||||
}
|
||||
foreach ($oPopupMenuItemsBlock->GetCssFilesRelPaths() as $sCssPath) {
|
||||
$oRenderBlock->AddCssFileRelPath($sCssPath);
|
||||
}
|
||||
}
|
||||
|
||||
// Extract favorite actions from their menus
|
||||
$aFavoriteRegularActions = [];
|
||||
$aFavoriteTransitionActions = [];
|
||||
|
||||
@@ -483,6 +483,7 @@ class LoginWebPage extends NiceWebPage
|
||||
$iResponse = $oLoginFSMExtensionInstance->LoginAction($sLoginState, $iErrorCode);
|
||||
if ($iResponse == self::LOGIN_FSM_RETURN)
|
||||
{
|
||||
Session::WriteClose();
|
||||
return $iErrorCode; // Asked to exit FSM, generally login OK
|
||||
}
|
||||
if ($iResponse == self::LOGIN_FSM_ERROR)
|
||||
|
||||
@@ -77,17 +77,28 @@ function _MaintenanceHtmlMessage($sMessage)
|
||||
*/
|
||||
function _MaintenanceJsonMessage($sTitle, $sMessage)
|
||||
{
|
||||
@include_once(APPROOT."/application/ajaxwebpage.class.inc.php");
|
||||
if (class_exists('ajax_page'))
|
||||
if (class_exists('JsonPage'))
|
||||
{
|
||||
$oP = new ajax_page($sTitle);
|
||||
$oP = new JsonPage($sTitle);
|
||||
$oP->add_header('Access-Control-Allow-Origin: *');
|
||||
$oP->SetContentType('application/json');
|
||||
$oP->add('{"code":100, "message":"'.$sMessage.'"}');
|
||||
|
||||
$aMessage = [
|
||||
'code' => 100,
|
||||
'message' =>$sMessage
|
||||
];
|
||||
|
||||
$oP->AddData($aMessage);
|
||||
$oP->Output();
|
||||
}
|
||||
else
|
||||
{
|
||||
_MaintenanceTextMessage($sMessage);
|
||||
} else {
|
||||
@include_once(APPROOT."/application/ajaxwebpage.class.inc.php");
|
||||
if (class_exists('ajax_page')) {
|
||||
$oP = new ajax_page($sTitle);
|
||||
$oP->add_header('Access-Control-Allow-Origin: *');
|
||||
$oP->SetContentType('application/json');
|
||||
$oP->add('{"code":100, "message":"'.$sMessage.'"}');
|
||||
$oP->Output();
|
||||
} else {
|
||||
_MaintenanceTextMessage($sMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\Helper\WebResourcesHelper;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Title\Title;
|
||||
use Combodo\iTop\Application\UI\Base\Component\Title\TitleUIBlockFactory;
|
||||
|
||||
require_once(APPROOT.'/application/utils.inc.php');
|
||||
@@ -1126,16 +1127,20 @@ class OQLMenuNode extends MenuNode
|
||||
{
|
||||
$sUsageId = utils::GetSafeId($sUsageId);
|
||||
$oSearch = DBObjectSearch::FromOQL($sOql);
|
||||
|
||||
$sClass= $oSearch->GetClass();
|
||||
$sIcon = MetaModel::GetClassIcon($sClass, false);
|
||||
if ($bSearchPane) {
|
||||
$aParams = array_merge(['open' => $bSearchOpen, 'table_id' => $sUsageId, 'submit_on_load' => false], $aExtraParams);
|
||||
$oBlock = new DisplayBlock($oSearch, 'search', false /* Asynchronous */, $aParams);
|
||||
$oBlock->Display($oPage, 0);
|
||||
$oPage->add("<div class='sf_results_area ibo-add-margin-top-250' data-target='search_results'>");
|
||||
}
|
||||
|
||||
$oPage->add("<div class='sf_results_area' data-target='search_results'>");
|
||||
$oTitle = TitleUIBlockFactory::MakeForPage($sTitle);
|
||||
$oPage->AddUiBlock($oTitle);
|
||||
else {
|
||||
$oPage->add("<div class='sf_results_area' data-target='search_results'>");
|
||||
}
|
||||
$aExtraParams['panel_class'] =$sClass;
|
||||
$aExtraParams['panel_title'] = $sTitle;
|
||||
$aExtraParams['panel_icon'] = $sIcon;
|
||||
|
||||
$aParams = array_merge(array('table_id' => $sUsageId), $aExtraParams);
|
||||
$oBlock = new DisplayBlock($oSearch, 'list', false /* Asynchronous */, $aParams);
|
||||
|
||||
@@ -288,7 +288,8 @@ class ShortcutOQL extends Shortcut
|
||||
$oPage->add_ready_script(
|
||||
<<<JS
|
||||
// Note: the title gets deleted by the validation mechanism
|
||||
$("#attr_auto_reload_sec").tooltip({items: 'input', content: '$sRateTitle'});
|
||||
$("#attr_auto_reload_sec").attr('data-tooltip-content', '$sRateTitle');
|
||||
CombodoTooltip.InitTooltipFromMarkup($("#attr_auto_reload_sec"));
|
||||
$("#attr_auto_reload_sec").prop('disabled', !$('#attr_auto_reload').is(':checked'));
|
||||
|
||||
$('#attr_auto_reload').change( function(ev) {
|
||||
|
||||
@@ -66,7 +66,6 @@ register_shutdown_function(function()
|
||||
});
|
||||
$oKPI = new ExecutionKPI();
|
||||
Session::Start();
|
||||
Session::WriteClose();
|
||||
$oKPI->ComputeAndReport("Session Start");
|
||||
|
||||
$sSwitchEnv = utils::ReadParam('switch_env', null);
|
||||
|
||||
@@ -29,7 +29,7 @@ class ThemeHandlerService
|
||||
{
|
||||
}
|
||||
|
||||
public function CompileTheme($sThemeId, $bSetup = false, $sSetupCompilationTimestamp="", $aThemeParameters = null, $aImportsPaths = null, $sWorkingPath = null){
|
||||
return ThemeHandler::CompileTheme($sThemeId, $bSetup, $sSetupCompilationTimestamp="", $aThemeParameters, $aImportsPaths, $sWorkingPath);
|
||||
public function CompileTheme($sThemeId, $bSetup = false, $sSetupCompilationTimestamp = "", $aThemeParameters = null, $aImportsPaths = null, $sWorkingPath = null){
|
||||
return ThemeHandler::CompileTheme($sThemeId, $bSetup, $sSetupCompilationTimestamp, $aThemeParameters, $aImportsPaths, $sWorkingPath);
|
||||
}
|
||||
}
|
||||
@@ -196,16 +196,19 @@ class privUITransactionSession
|
||||
*/
|
||||
class privUITransactionFile
|
||||
{
|
||||
/** @var int Value to use when no user logged */
|
||||
const UNAUTHENTICATED_USER_ID = -666;
|
||||
|
||||
/**
|
||||
* @return int
|
||||
* @throws \SecurityException if no connected user
|
||||
* @return int current user id, or {@see self::UNAUTHENTICATED_USER_ID} if no user logged
|
||||
*
|
||||
* @since 2.6.5 2.7.6 3.0.0 N°4289 method creation
|
||||
*/
|
||||
private static function GetCurrentUserId() {
|
||||
private static function GetCurrentUserId()
|
||||
{
|
||||
$iCurrentUserId = UserRights::GetConnectedUserId();
|
||||
if ('' === $iCurrentUserId) {
|
||||
throw new SecurityException('Cannot creation transaction_id when no user logged');
|
||||
$iCurrentUserId = static::UNAUTHENTICATED_USER_ID;
|
||||
}
|
||||
|
||||
return $iCurrentUserId;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Combodo\iTop;
|
||||
|
||||
use AttributeDate;
|
||||
use AttributeDateTime;
|
||||
use Dict;
|
||||
use Exception;
|
||||
@@ -55,6 +56,10 @@ class TwigExtension
|
||||
{
|
||||
return AttributeDateTime::GetFormat()->Format($sDate);
|
||||
}
|
||||
if (preg_match('@^\d\d\d\d-\d\d-\d\d$@', trim($sDate)))
|
||||
{
|
||||
return AttributeDate::GetFormat()->Format($sDate);
|
||||
}
|
||||
}
|
||||
catch (Exception $e)
|
||||
{
|
||||
|
||||
@@ -61,6 +61,8 @@ class UIExtKeyWidget
|
||||
protected $sAttCode;
|
||||
protected $bSearchMode;
|
||||
|
||||
//public function __construct($sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sNameSuffix = '', $sFieldPrefix = '', $sFormPrefix = '')
|
||||
|
||||
/**
|
||||
* @param \WebPage $oPage
|
||||
* @param string $sAttCode
|
||||
@@ -80,18 +82,13 @@ class UIExtKeyWidget
|
||||
* @throws \Exception
|
||||
*
|
||||
* @since 3.0.0 N°3750 new $sInputType parameter
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Add default value for $aArgs for PHP 8.0 compat
|
||||
*/
|
||||
public static function DisplayFromAttCode(
|
||||
$oPage, $sAttCode, $sClass, $sTitle, $oAllowedValues, $value, $iInputId, $bMandatory, $sFieldName = '', $sFormPrefix = '',
|
||||
$aArgs = [], $bSearchMode = false, &$sInputType = ''
|
||||
)
|
||||
{
|
||||
// we will only use key & name, so let's reduce fields loaded !
|
||||
$aAttToLoad = [
|
||||
$sClass => [], // nothing, id and friendlyname are automatically added by the API
|
||||
];
|
||||
$oAllowedValues->OptimizeColumnLoad($aAttToLoad);
|
||||
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
$sTargetClass = $oAttDef->GetTargetClass();
|
||||
$iMaxComboLength = $oAttDef->GetMaximumComboLength();
|
||||
@@ -254,7 +251,7 @@ class UIExtKeyWidget
|
||||
$aOption['picture_url'] = $oImage->GetDisplayURL($sClassAllowed, $oObj->GetKey(), $sObjectImageAttCode);
|
||||
$aOption['initials'] = '';
|
||||
} else {
|
||||
$aOption['initials'] = utils::ToAcronym($oObj->Get('friendlyname'));
|
||||
$aOption['initials'] = utils::FormatInitialsForMedallion(utils::ToAcronym($oObj->Get('friendlyname')));
|
||||
}
|
||||
}
|
||||
array_push($aOptions, $aOption);
|
||||
@@ -704,7 +701,7 @@ JS
|
||||
HTML
|
||||
);
|
||||
|
||||
$sDialogTitleSanitized = utils::HtmlToText($sTitle);
|
||||
$sDialogTitleSanitized = addslashes(utils::HtmlToText($sTitle));
|
||||
$oPage->add_ready_script(<<<JS
|
||||
$('#ac_dlg_{$this->iId}').dialog({
|
||||
width: $(window).width()*0.8,
|
||||
@@ -776,9 +773,11 @@ JS
|
||||
*
|
||||
* @throws CoreException
|
||||
* @throws OQLException
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $oObj for PHP 8.0 compatibility
|
||||
*/
|
||||
public function AutoComplete(
|
||||
WebPage $oP, $sFilter, $oObj = null, $sContains = '', $sOutputFormat = self::ENUM_OUTPUT_FORMAT_CSV, $sOperation = null
|
||||
WebPage $oP, $sFilter, $oObj, $sContains, $sOutputFormat = self::ENUM_OUTPUT_FORMAT_CSV, $sOperation = null
|
||||
)
|
||||
{
|
||||
if (is_null($sFilter)) {
|
||||
@@ -830,7 +829,7 @@ JS
|
||||
}
|
||||
|
||||
if (array_key_exists('initials', $aValue)) {
|
||||
$aElt['initials'] = $aValue['initials'];
|
||||
$aElt['initials'] = utils::FormatInitialsForMedallion($aValue['initials']);
|
||||
if (array_key_exists('picture_url', $aValue)) {
|
||||
$aElt['picture_url'] = $aValue['picture_url'];
|
||||
}
|
||||
@@ -913,8 +912,8 @@ JS
|
||||
$oClassForm = FormUIBlockFactory::MakeStandard();
|
||||
$oBlock->AddSubBlock($oClassForm);
|
||||
$oClassForm->AddSubBlock(cmdbAbstractObject::DisplayBlockSelectClassToCreate( $sClassLabel, $this->sTargetClass, $aPossibleClasses));
|
||||
|
||||
$oPage->add_ready_script("$('#ac_create_$this->iId').dialog({ width: 'auto', height: 'auto', maxHeight: $(window).height() - 50, autoOpen: false, modal: true, title: '$sDialogTitle'});\n");
|
||||
$sDialogTitleEscaped = addslashes($sDialogTitle);
|
||||
$oPage->add_ready_script("$('#ac_create_$this->iId').dialog({ width: 'auto', height: 'auto', maxHeight: $(window).height() - 50, autoOpen: false, modal: true, title: '$sDialogTitleEscaped'});\n");
|
||||
$oPage->add_ready_script("$('#ac_create_{$this->iId} form').removeAttr('onsubmit');");
|
||||
$oPage->add_ready_script("$('#ac_create_{$this->iId} form').on('submit.uilinksWizard', oACWidget_{$this->iId}.DoSelectObjectClass);");
|
||||
}
|
||||
@@ -1008,16 +1007,46 @@ JS
|
||||
|
||||
if ($bHasChildLeafs)
|
||||
{
|
||||
$oPage->add('<div class="treecontrol" id="treecontrolid"><a href="?#">'.Dict::S("UI:Treeview:CollapseAll").'</a> | <a href="?#">'.Dict::S("UI:Treeview:ExpandAll").'</a></div>');
|
||||
$oPage->add('<span class="treecontrol ibo-button-group" id="treecontrolid"><a class="ibo-button ibo-is-regular ibo-is-neutral" href="?#">'.Dict::S("UI:Treeview:CollapseAll").'</a><a class="ibo-button ibo-is-regular ibo-is-neutral" href="?#">'.Dict::S("UI:Treeview:ExpandAll").'</a></span>');
|
||||
}
|
||||
|
||||
$oPage->add("<input type=\"button\" class=\"ibo-button ibo-is-regular ibo-is-neutral\" id=\"btn_cancel_{$this->iId}\" value=\"".Dict::S('UI:Button:Cancel')."\" onClick=\"$('#dlg_tree_{$this->iId}').dialog('close');\"> ");
|
||||
$oPage->add("<input type=\"button\" class=\"ibo-button ibo-is-regular ibo-is-primary\" id=\"btn_ok_{$this->iId}\" value=\"".Dict::S('UI:Button:Ok')."\" onClick=\"oACWidget_{$this->iId}.DoHKOk();\">");
|
||||
|
||||
|
||||
$oPage->add('</div></div>');
|
||||
|
||||
|
||||
$sOkButtonLabel = Dict::S('UI:Button:Ok');
|
||||
$sCancelButtonLabel = Dict::S('UI:Button:Cancel');
|
||||
$oPage->add_ready_script("\$('#tree_$this->iId ul').treeview({ control: '#treecontrolid', persist: 'false'});\n");
|
||||
$oPage->add_ready_script("\$('#dlg_tree_$this->iId').dialog({ width: 'auto', height: 'auto', autoOpen: true, modal: true, title: '$sDialogTitle', resizeStop: oACWidget_{$this->iId}.OnHKResize, close: oACWidget_{$this->iId}.OnHKClose });\n");
|
||||
$oPage->add_ready_script(<<<JS
|
||||
$('#dlg_tree_$this->iId').dialog({
|
||||
width: 'auto',
|
||||
height: 'auto',
|
||||
autoOpen: true,
|
||||
modal: true,
|
||||
title: '$sDialogTitle',
|
||||
open: function() {
|
||||
$(this).css("max-height", parseInt($(window).height()*0.7)+'px');
|
||||
},
|
||||
buttons: [
|
||||
{
|
||||
text: "$sCancelButtonLabel",
|
||||
click: function() { $(this).dialog( "close" ); }
|
||||
},
|
||||
{
|
||||
text: "$sOkButtonLabel",
|
||||
class: "ibo-is-primary",
|
||||
click: function() {
|
||||
oACWidget_{$this->iId}.DoHKOk();
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
resizeStop: oACWidget_{$this->iId}.OnHKResize,
|
||||
close: oACWidget_{$this->iId}.OnHKClose
|
||||
});
|
||||
|
||||
$('#dlg_tree_$this->iId + .ui-dialog-buttonpane .ui-dialog-buttonset').prepend($('#treecontrolid'));
|
||||
|
||||
JS
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -75,9 +75,15 @@ class UILinksWidgetDirect
|
||||
* @param array $aArgs
|
||||
* @param string $sFormPrefix
|
||||
* @param DBObject $oCurrentObj
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $aArgs for PHP 8.0 compatibility (handling wrong values at method start)
|
||||
*/
|
||||
public function Display(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj)
|
||||
public function Display(WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj)
|
||||
{
|
||||
if (empty($aArgs)) {
|
||||
$aArgs = [];
|
||||
}
|
||||
|
||||
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
|
||||
switch($oLinksetDef->GetEditMode())
|
||||
{
|
||||
@@ -127,8 +133,10 @@ class UILinksWidgetDirect
|
||||
* @param string $sFormPrefix
|
||||
* @param DBObject $oCurrentObj
|
||||
* @param bool $bDisplayMenu
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $aArgs for PHP 8.0 compatibility (protected method, always called with default value)
|
||||
*/
|
||||
protected function DisplayAsBlock(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $bDisplayMenu)
|
||||
protected function DisplayAsBlock(WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj, $bDisplayMenu)
|
||||
{
|
||||
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
|
||||
$sTargetClass = $oLinksetDef->GetLinkedClass();
|
||||
@@ -197,7 +205,6 @@ class UILinksWidgetDirect
|
||||
|
||||
if ($sRealClass != '')
|
||||
{
|
||||
$oPage->add("<h1>".MetaModel::GetClassIcon($sRealClass)." ".Dict::Format('UI:CreationTitle_Class', MetaModel::GetName($sRealClass))."</h1>\n");
|
||||
$oLinksetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
|
||||
$sExtKeyToMe = $oLinksetDef->GetExtKeyToMe();
|
||||
$aFieldFlags = array( $sExtKeyToMe => OPT_ATT_HIDDEN);
|
||||
@@ -229,8 +236,10 @@ class UILinksWidgetDirect
|
||||
* @param string $sFormPrefix
|
||||
* @param DBObject $oCurrentObj
|
||||
* @param array $aButtons
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $aArgs for PHP 8.0 compatibility (protected method, caller already handles it)
|
||||
*/
|
||||
protected function DisplayEditInPlace(WebPage $oPage, $oValue, $aArgs = array(), $sFormPrefix, $oCurrentObj, $aButtons = array('create', 'delete'))
|
||||
protected function DisplayEditInPlace(WebPage $oPage, $oValue, $aArgs, $sFormPrefix, $oCurrentObj, $aButtons = array('create', 'delete'))
|
||||
{
|
||||
$aAttribs = $this->GetTableConfig();
|
||||
$oValue->Rewind();
|
||||
@@ -297,7 +306,7 @@ class UILinksWidgetDirect
|
||||
}
|
||||
$oHiddenCriteria = $oHiddenFilter->GetCriteria();
|
||||
$aArgs = $oHiddenFilter->GetInternalParams();
|
||||
$sHiddenCriteria = $oHiddenCriteria->Render($aArgs);
|
||||
$sHiddenCriteria = $oHiddenCriteria->RenderExpression(false, $aArgs);
|
||||
|
||||
$oLinkSetDef = MetaModel::GetAttributeDef($this->sClass, $this->sAttCode);
|
||||
$valuesDef = $oLinkSetDef->GetValuesDef();
|
||||
@@ -474,6 +483,33 @@ HTML
|
||||
}
|
||||
return $oPage->GetTableRow($aRow, $aAttribs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WebPage $oPage
|
||||
* @param $sRealClass
|
||||
* @param $aValues
|
||||
* @param int $iTempId
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function GetFormRow($oPage, $sRealClass, $aValues, $iTempId)
|
||||
{
|
||||
if ($sRealClass == '')
|
||||
{
|
||||
$sRealClass = $this->sLinkedClass;
|
||||
}
|
||||
$oLinkObj = new $sRealClass();
|
||||
$oLinkObj->UpdateObjectFromPostedForm($this->sInputid);
|
||||
|
||||
$aAttribs = $this->GetTableConfig();
|
||||
$aRow = array();
|
||||
$aRow[] = '<input type="checkbox" class="selectList'.$this->sInputid.'" value="'.($iTempId).'"/>';
|
||||
foreach($this->aZlist as $sLinkedAttCode)
|
||||
{
|
||||
$aRow[] = $oLinkObj->GetAsHTML($sLinkedAttCode);
|
||||
}
|
||||
return $aRow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the default search parameters based on 1) a 'current' object and 2) the silos defined by the context
|
||||
|
||||
@@ -375,6 +375,7 @@ JS
|
||||
|
||||
$oValue->Rewind();
|
||||
$aForm = array();
|
||||
$iMaxAddedId = 0;
|
||||
$iAddedId = -1; // Unique id for new links
|
||||
while ($oCurrentLink = $oValue->Fetch())
|
||||
{
|
||||
@@ -395,8 +396,12 @@ JS
|
||||
} else {
|
||||
$key = $oCurrentLink->GetKey();
|
||||
}
|
||||
|
||||
$iMaxAddedId = max($iMaxAddedId, $key);
|
||||
$aForm[$key] = $this->GetFormRow($oPage, $oLinkedObj, $oCurrentLink, $aArgs, $oCurrentObj, $key, $bReadOnly);
|
||||
}
|
||||
$oBlock->iMaxAddedId = (int) $iMaxAddedId;
|
||||
|
||||
$oDataTable = DataTableUIBlockFactory::MakeForForm("{$this->m_sAttCode}{$this->m_sNameSuffix}", $this->m_aTableConfig, $aForm);
|
||||
$oDataTable->SetOptions(['select_mode' => 'custom']);
|
||||
$oBlock->AddSubBlock($oDataTable);
|
||||
|
||||
@@ -2118,11 +2118,21 @@ class utils
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the relative (to MODULESROOT) path of the root directory of the module containing the file where the call to
|
||||
* this function is made
|
||||
* or an empty string if no such module is found (or not called within a module file)
|
||||
* @param number $iCallDepth The depth of the module in the callstack. Zero when called directly from within the module
|
||||
* @return string
|
||||
* **Warning** : returned result can be invalid as we're using backtrace to find the module dir name
|
||||
*
|
||||
* @param int $iCallDepth The depth of the module in the callstack. Zero when called directly from within the module
|
||||
*
|
||||
* @return string the relative (to MODULESROOT) path of the root directory of the module containing the file where the call to
|
||||
* this function is made
|
||||
* or an empty string if no such module is found (or not called within a module file)
|
||||
*
|
||||
* @uses \debug_backtrace()
|
||||
*
|
||||
* @since 3.0.0 Before writing model.*.php file, compiler will now always delete it.
|
||||
* If you have symlinks enabled, base dir will be original module dir, but since this behavior change this won't be true anymore for model.*.php
|
||||
* In consequence the backtrace analysis won't be possible for this file
|
||||
* See N°4854
|
||||
* @link https://www.itophub.io/wiki/page?id=3_0_0%3Arelease%3A3_0_whats_new#compiler_always_generate_new_model_php compiler behavior change documentation
|
||||
*/
|
||||
public static function GetCurrentModuleDir($iCallDepth)
|
||||
{
|
||||
@@ -2147,9 +2157,14 @@ class utils
|
||||
}
|
||||
|
||||
/**
|
||||
* **Warning** : as this method uses {@see GetCurrentModuleDir} it produces hazardous results.
|
||||
* You should better uses directly {@see GetAbsoluteUrlModulesRoot} and add the module dir name yourself ! See N°4573
|
||||
*
|
||||
* @return string the base URL for all files in the current module from which this method is called
|
||||
* or an empty string if no such module is found (or not called within a module file)
|
||||
* @throws \Exception
|
||||
*
|
||||
* @uses GetCurrentModuleDir
|
||||
*/
|
||||
public static function GetCurrentModuleUrl()
|
||||
{
|
||||
@@ -2404,43 +2419,19 @@ class utils
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string eg : '2_7_0' ITOP_VERSION is '2.7.1-dev'
|
||||
* @return string eg : '2_7_0' if iTop core version is '2.7.5-2'
|
||||
* @throws \ApplicationException if constant value is invalid
|
||||
* @uses ITOP_CORE_VERSION
|
||||
*/
|
||||
public static function GetItopVersionWikiSyntax() {
|
||||
$sMinorVersion = self::GetItopMinorVersion();
|
||||
public static function GetItopVersionWikiSyntax($sItopVersion = ITOP_CORE_VERSION)
|
||||
{
|
||||
$aExplodedVersion = explode('.', $sItopVersion);
|
||||
|
||||
return str_replace('.', '_', $sMinorVersion).'_0';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sPatchVersion if non provided, will call GetItopPatchVersion
|
||||
*
|
||||
* @return string eg 2.7 if ITOP_VERSION is '2.7.0-dev'
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function GetItopMinorVersion($sPatchVersion = null) {
|
||||
if (is_null($sPatchVersion)) {
|
||||
$sPatchVersion = self::GetItopPatchVersion();
|
||||
}
|
||||
$aExplodedVersion = explode('.', $sPatchVersion);
|
||||
|
||||
if (count($aExplodedVersion) < 2) {
|
||||
throw new Exception('iTop version is wrongfully configured!');
|
||||
}
|
||||
if (($aExplodedVersion[0] == '') || ($aExplodedVersion[1] == '')) {
|
||||
throw new Exception('iTop version is wrongfully configured!');
|
||||
if ((false === isset($aExplodedVersion[0])) || (false === isset($aExplodedVersion[1]))) {
|
||||
throw new ApplicationException('iTop version is wrongfully configured!');
|
||||
}
|
||||
|
||||
return sprintf('%d.%d', $aExplodedVersion[0], $aExplodedVersion[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string eg '2.7.0' if ITOP_VERSION is '2.7.0-dev'
|
||||
*/
|
||||
public static function GetItopPatchVersion() {
|
||||
$aExplodedVersion = explode('-', ITOP_VERSION);
|
||||
|
||||
return $aExplodedVersion[0];
|
||||
return "{$aExplodedVersion[0]}_{$aExplodedVersion[1]}_0";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3059,6 +3050,20 @@ HTML;
|
||||
return $aMentionedObjects;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: This method is not ideal, but other solutions seemed even less ideal:
|
||||
* * Add a "$sMaxLength" param. to utils::ToAcronym(): Does not work for every use cases (see corresponding ticket) as in some parts utils::ToAcronym isn't necessarly meant to be used in a medallion.
|
||||
*
|
||||
* @param string $sInitials
|
||||
*
|
||||
* @return string Truncates $sInitials so it can fit in medallions
|
||||
* @since 3.0.1 N°4913
|
||||
*/
|
||||
public static function FormatInitialsForMedallion(string $sInitials): string
|
||||
{
|
||||
return mb_substr($sInitials, 0, 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sUrl
|
||||
* @param string $sParamName
|
||||
|
||||
@@ -4,8 +4,25 @@ define('APPROOT', dirname(__FILE__).'/');
|
||||
define('APPCONF', APPROOT.'conf/');
|
||||
|
||||
/**
|
||||
* iTop framework Version
|
||||
* iTop Datamodel XML format version
|
||||
*
|
||||
* It was also used in iTop 3.0.0 to get iTop core version (instead of {@see ITOP_VERSION} which gives the application version).
|
||||
* To address this need you should now use {@see ITOP_CORE_VERSION}
|
||||
*
|
||||
* @see ITOP_CORE_VERSION to get full iTop core version
|
||||
*/
|
||||
define('ITOP_DESIGN_LATEST_VERSION', '3.0');
|
||||
|
||||
/**
|
||||
* Constant containing the iTop core version, whatever application was built
|
||||
*
|
||||
* Note that in iTop 3.0.0 we used {@see ITOP_DESIGN_LATEST_VERSION} to get core version.
|
||||
* When releasing, both constants should be updated : see `.make/release/update-versions.php` for that !
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°4714 constant creation
|
||||
* @used-by utils::GetItopVersionWikiSyntax()
|
||||
* @used-by iTopModulesPhpVersionIntegrationTest
|
||||
*/
|
||||
define('ITOP_CORE_VERSION', '3.0.1');
|
||||
|
||||
require_once APPROOT.'bootstrap.inc.php';
|
||||
|
||||
@@ -16,16 +16,16 @@
|
||||
"pelago/emogrifier": "3.1.0",
|
||||
"scssphp/scssphp": "1.0.6",
|
||||
"swiftmailer/swiftmailer": "5.4.12",
|
||||
"symfony/console": "3.4.*",
|
||||
"symfony/dotenv": "3.4.*",
|
||||
"symfony/framework-bundle": "3.4.*",
|
||||
"symfony/console": "~3.4.47",
|
||||
"symfony/dotenv": "~3.4.47",
|
||||
"symfony/framework-bundle": "~3.4.47",
|
||||
"symfony/polyfill-php70": "1.*",
|
||||
"symfony/twig-bundle": "3.4.*",
|
||||
"symfony/yaml": "3.4.*"
|
||||
"symfony/twig-bundle": "~3.4.47",
|
||||
"symfony/yaml": "~3.4.47"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/stopwatch": "3.4.*",
|
||||
"symfony/web-profiler-bundle": "3.4.*"
|
||||
"symfony/stopwatch": "~3.4.47",
|
||||
"symfony/web-profiler-bundle": "~3.4.47"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-libsodium": "Required to use the AttributeEncryptedString.",
|
||||
|
||||
905
composer.lock
generated
905
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -118,6 +118,39 @@ abstract class Action extends cmdbAbstractObject
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function AfterInsert()
|
||||
{
|
||||
parent::AfterInsert();
|
||||
$this->DoCheckIfHasTrigger();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public function AfterUpdate()
|
||||
{
|
||||
parent::AfterUpdate();
|
||||
$this->DoCheckIfHasTrigger();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the Action has at least 1 trigger linked. Otherwise, it adds a warning.
|
||||
* @return void
|
||||
* @since 3.0.0
|
||||
*/
|
||||
protected function DoCheckIfHasTrigger()
|
||||
{
|
||||
$oTriggersSet = $this->Get('trigger_list');
|
||||
if ($oTriggersSet->Count() === 0) {
|
||||
$this->m_aCheckWarnings[] = Dict::S('Action:WarningNoTriggerLinked');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,6 +200,17 @@ abstract class ActionNotification extends Action
|
||||
*/
|
||||
class ActionEmail extends ActionNotification
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.1
|
||||
*/
|
||||
const ENUM_HEADER_NAME_MESSAGE_ID = 'Message-ID';
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.1
|
||||
*/
|
||||
const ENUM_HEADER_NAME_REFERENCES = 'References';
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@@ -174,13 +218,13 @@ class ActionEmail extends ActionNotification
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "grant_by_profile,core/cmdb,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('name'),
|
||||
"db_table" => "priv_action_email",
|
||||
"db_key_field" => "id",
|
||||
"category" => "grant_by_profile,core/cmdb,application",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "name",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array('name'),
|
||||
"db_table" => "priv_action_email",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
@@ -383,9 +427,8 @@ 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 = $this->GenerateIdentifierForHeaders($oObj, static::ENUM_HEADER_NAME_MESSAGE_ID);
|
||||
$sReference = $this->GenerateIdentifierForHeaders($oObj, static::ENUM_HEADER_NAME_REFERENCES);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
/** @noinspection PhpUnhandledExceptionInspection */
|
||||
@@ -423,8 +466,7 @@ class ActionEmail extends ActionNotification
|
||||
|
||||
$oEmail = new EMail();
|
||||
|
||||
if ($this->IsBeingTested())
|
||||
{
|
||||
if ($this->IsBeingTested()) {
|
||||
$oEmail->SetSubject('TEST['.$sSubject.']');
|
||||
$sTestBody = $sBody;
|
||||
$sTestBody .= "<div style=\"border: dashed;\">\n";
|
||||
@@ -434,8 +476,8 @@ class ActionEmail extends ActionNotification
|
||||
$sTestBody .= "<li>TO: $sTo</li>\n";
|
||||
$sTestBody .= "<li>CC: $sCC</li>\n";
|
||||
$sTestBody .= "<li>BCC: $sBCC</li>\n";
|
||||
$sTestBody .= empty($sFromLabel) ? "<li>From: $sFrom</li>\n": "<li>From: $sFromLabel <$sFrom></li>\n";
|
||||
$sTestBody .= empty($sReplyToLabel) ? "<li>Reply-To: $sReplyTo</li>\n": "<li>Reply-To: $sReplyToLabel <$sReplyTo></li>\n";
|
||||
$sTestBody .= empty($sFromLabel) ? "<li>From: $sFrom</li>\n" : "<li>From: $sFromLabel <$sFrom></li>\n";
|
||||
$sTestBody .= empty($sReplyToLabel) ? "<li>Reply-To: $sReplyTo</li>\n" : "<li>Reply-To: $sReplyToLabel <$sReplyTo></li>\n";
|
||||
$sTestBody .= "<li>References: $sReference</li>\n";
|
||||
$sTestBody .= "</ul>\n";
|
||||
$sTestBody .= "</p>\n";
|
||||
@@ -445,9 +487,9 @@ class ActionEmail extends ActionNotification
|
||||
$oEmail->SetRecipientFrom($sFrom, $sFromLabel);
|
||||
$oEmail->SetReferences($sReference);
|
||||
$oEmail->SetMessageId($sMessageId);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Note: N°4849 We pass the "References" identifier instead of the "Message-ID" on purpose as we want notifications emails to group around the triggering iTop object, not just the users' replies to the notification
|
||||
$oEmail->SetInReplyTo($sReference);
|
||||
} else {
|
||||
$oEmail->SetSubject($sSubject);
|
||||
$oEmail->SetBody($sBody, 'text/html', $sStyles);
|
||||
$oEmail->SetRecipientTO($sTo);
|
||||
@@ -457,6 +499,8 @@ class ActionEmail extends ActionNotification
|
||||
$oEmail->SetRecipientReplyTo($sReplyTo, $sReplyToLabel);
|
||||
$oEmail->SetReferences($sReference);
|
||||
$oEmail->SetMessageId($sMessageId);
|
||||
// Note: N°4849 We pass the "References" identifier instead of the "Message-ID" on purpose as we want notifications emails to group around the triggering iTop object, not just the users' replies to the notification
|
||||
$oEmail->SetInReplyTo($sReference);
|
||||
}
|
||||
|
||||
if (isset($aContextArgs['attachments']))
|
||||
@@ -483,26 +527,64 @@ class ActionEmail extends ActionNotification
|
||||
{
|
||||
case EMAIL_SEND_OK:
|
||||
return "Sent";
|
||||
|
||||
|
||||
case EMAIL_SEND_PENDING:
|
||||
return "Pending";
|
||||
|
||||
|
||||
case EMAIL_SEND_ERROR:
|
||||
return "Errors: ".implode(', ', $aErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_array($this->m_aMailErrors) && count($this->m_aMailErrors) > 0)
|
||||
{
|
||||
} else {
|
||||
if (is_array($this->m_aMailErrors) && count($this->m_aMailErrors) > 0) {
|
||||
$sError = implode(', ', $this->m_aMailErrors);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$sError = 'Unknown reason';
|
||||
}
|
||||
|
||||
return 'Notification was not sent: '.$sError;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DBObject $oObject
|
||||
* @param string $sHeaderName {@see \ActionEmail::ENUM_HEADER_NAME_REFERENCES}, {@see \ActionEmail::ENUM_HEADER_NAME_MESSAGE_ID}
|
||||
*
|
||||
* @return string The formatted identifier for $sHeaderName based on $oObject
|
||||
* @throws \Exception
|
||||
* @since 3.0.1 N°4849
|
||||
*/
|
||||
protected function GenerateIdentifierForHeaders(DBObject $oObject, string $sHeaderName): string
|
||||
{
|
||||
$sObjClass = get_class($oObject);
|
||||
$sObjId = $oObject->GetKey();
|
||||
$sAppName = utils::Sanitize(ITOP_APPLICATION_SHORT, '', utils::ENUM_SANITIZATION_FILTER_VARIABLE_NAME);
|
||||
|
||||
switch ($sHeaderName) {
|
||||
case static::ENUM_HEADER_NAME_MESSAGE_ID:
|
||||
case static::ENUM_HEADER_NAME_REFERENCES:
|
||||
// Prefix
|
||||
$sPrefix = sprintf('%s_%s_%d', $sAppName, $sObjClass, $sObjId);
|
||||
if ($sHeaderName === static::ENUM_HEADER_NAME_MESSAGE_ID) {
|
||||
$sPrefix .= sprintf('_%f', microtime(true /* get as float*/));
|
||||
}
|
||||
// Suffix
|
||||
$sSuffix = sprintf('@%s.openitop.org', MetaModel::GetEnvironmentId());
|
||||
// Identifier
|
||||
$sIdentifier = $sPrefix.$sSuffix;
|
||||
if ($sHeaderName === static::ENUM_HEADER_NAME_REFERENCES) {
|
||||
$sIdentifier = "<$sIdentifier>";
|
||||
}
|
||||
|
||||
return $sIdentifier;
|
||||
}
|
||||
|
||||
// Requested header name invalid
|
||||
$sErrorMessage = sprintf('%s: Could not generate identifier for header "%s", only %s are supported', static::class, $sHeaderName, implode(' / ', [static::ENUM_HEADER_NAME_MESSAGE_ID, static::ENUM_HEADER_NAME_REFERENCES]));
|
||||
IssueLog::Error($sErrorMessage, LogChannels::NOTIFICATIONS, [
|
||||
'Object' => $sObjClass.'::'.$sObjId.' ('.$oObject->GetRawName().')',
|
||||
'Action' => get_class($this).'::'.$this->GetKey().' ('.$this->GetRawName().')',
|
||||
]);
|
||||
throw new Exception($sErrorMessage);
|
||||
}
|
||||
}
|
||||
|
||||
42
core/apc-service.class.inc.php
Normal file
42
core/apc-service.class.inc.php
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Class ApcService
|
||||
* @since 2.7.6 N°4125
|
||||
*/
|
||||
class ApcService {
|
||||
public function __construct() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $function_name
|
||||
* @return bool
|
||||
* @see function_exists()
|
||||
*/
|
||||
public function function_exists($function_name) {
|
||||
return function_exists($function_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|array $key
|
||||
* @return mixed
|
||||
* @see apc_fetch()
|
||||
*/
|
||||
function apc_fetch($key)
|
||||
{
|
||||
return apc_fetch($key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|string $key
|
||||
* @param $var
|
||||
* @param int $ttl
|
||||
* @return array|bool
|
||||
* @see apc_store()
|
||||
*/
|
||||
function apc_store($key, $var = NULL, $ttl = 0)
|
||||
{
|
||||
return apc_store($key, $var, $ttl);
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -5717,7 +5717,7 @@ class AttributeMetaEnum extends AttributeEnum
|
||||
$aLocalizedValues = array();
|
||||
foreach($aRawValues as $sKey => $sValue)
|
||||
{
|
||||
$aLocalizedValues[$sKey] = Str::pure2html($this->GetValueLabel($sKey));
|
||||
$aLocalizedValues[$sKey] = $this->GetValueLabel($sKey);
|
||||
}
|
||||
|
||||
return $aLocalizedValues;
|
||||
|
||||
@@ -1077,7 +1077,7 @@ class CMDBChangeOpSetAttributeLinksTune extends CMDBChangeOpSetAttributeLinks
|
||||
{
|
||||
$oField = new FieldExpression('objclass', $oSearch->GetClassAlias());
|
||||
$sListExpr = '('.implode(', ', CMDBSource::Quote($aLinkClasses)).')';
|
||||
$sOQLCondition = $oField->Render()." IN $sListExpr";
|
||||
$sOQLCondition = $oField->RenderExpression()." IN $sListExpr";
|
||||
$oNewCondition = Expression::FromOQL($sOQLCondition);
|
||||
$oSearch->AddConditionExpression($oNewCondition);
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ abstract class CMDBObject extends DBObject
|
||||
*
|
||||
* @param string $sId ID of the user doing the change, null if not done by a user (eg. background task)
|
||||
*
|
||||
* @since 3.0.0
|
||||
* @since 3.0.0 N°2847 following the addition of CMDBChange.user_id
|
||||
*/
|
||||
public static function SetTrackUserId($sId)
|
||||
{
|
||||
|
||||
@@ -350,6 +350,12 @@ class CMDBSource
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws \MySQLException
|
||||
*
|
||||
* @uses \CMDBSource::QueryToCol() so needs a connection opened !
|
||||
*/
|
||||
public static function GetDBVersion()
|
||||
{
|
||||
$aVersions = self::QueryToCol('SELECT Version() as version', 'version');
|
||||
@@ -367,8 +373,10 @@ class CMDBSource
|
||||
/**
|
||||
* Get the DB vendor between MySQL and its main forks
|
||||
* @return string
|
||||
*
|
||||
* @uses \CMDBSource::GetServerVariable() so needs a connection opened !
|
||||
*/
|
||||
static public function GetDBVendor()
|
||||
public static function GetDBVendor()
|
||||
{
|
||||
$sDBVendor = static::ENUM_DB_VENDOR_MYSQL;
|
||||
|
||||
@@ -672,13 +680,13 @@ class CMDBSource
|
||||
private static function StartTransaction()
|
||||
{
|
||||
$aStackTrace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT , 3);
|
||||
$sCaller = 'From '.$aStackTrace[1]['file'].'('.$aStackTrace[1]['line'].'): '.$aStackTrace[2]['class'].'->'.$aStackTrace[2]['function'].'()';
|
||||
|
||||
$bHasExistingTransactions = self::IsInsideTransaction();
|
||||
if (!$bHasExistingTransactions) {
|
||||
IssueLog::Trace("START TRANSACTION $sCaller", LogChannels::CMDB_SOURCE);
|
||||
IssueLog::Trace("START TRANSACTION was sent to the DB", LogChannels::CMDB_SOURCE, ['stacktrace' => $aStackTrace]);
|
||||
self::DBQuery('START TRANSACTION');
|
||||
} else {
|
||||
IssueLog::Trace("Ignore nested (".self::$m_iTransactionLevel.") START TRANSACTION $sCaller", LogChannels::CMDB_SOURCE);
|
||||
IssueLog::Trace("START TRANSACTION ignored as a transaction is already opened", LogChannels::CMDB_SOURCE, ['stacktrace' => $aStackTrace]);
|
||||
}
|
||||
|
||||
self::AddTransactionLevel();
|
||||
|
||||
@@ -22,7 +22,15 @@
|
||||
|
||||
define('ITOP_APPLICATION', 'iTop');
|
||||
define('ITOP_APPLICATION_SHORT', 'iTop');
|
||||
define('ITOP_VERSION', '3.0.0-dev');
|
||||
|
||||
/**
|
||||
* Constant containing the application version
|
||||
* Warning: this might be different from iTop core version!
|
||||
*
|
||||
* @see ITOP_CORE_VERSION to get iTop core version
|
||||
*/
|
||||
define('ITOP_VERSION', '3.0.1-dev');
|
||||
|
||||
define('ITOP_VERSION_NAME', 'Fullmoon');
|
||||
define('ITOP_REVISION', 'svn');
|
||||
define('ITOP_BUILD_DATE', '$WCNOW$');
|
||||
@@ -488,6 +496,14 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
],
|
||||
'cron_task_max_execution_time' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Background tasks will use this value (integer) multiplicated by its periodicity (in seconds) as max duration per cron execution. 0 is unlimited time',
|
||||
'default' => 0,
|
||||
'value' => 0,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'cron_sleep' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Duration (seconds) before cron.php checks again if something must be done',
|
||||
@@ -608,6 +624,13 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
/**
|
||||
* The timezone is automatically set using this parameter in \utils::InitTimeZone
|
||||
* This method is called almost everywhere, cause it's called in \MetaModel::LoadConfig and exec.php... but you might
|
||||
* need to get it yourself !
|
||||
*
|
||||
* @used-by utils::InitTimeZone()
|
||||
*/
|
||||
'timezone' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Timezone (reference: http://php.net/manual/en/timezones.php). If empty, it will be left unchanged and MUST be explicitly configured in PHP',
|
||||
@@ -851,13 +874,23 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'impact_analysis_lazy_loading' => [
|
||||
'type' => 'bool',
|
||||
'description' => 'In the impact analysis view: display the analysis or filter before display',
|
||||
'default' => false,
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'url_validation_pattern' => [
|
||||
'type' => 'string',
|
||||
'description' => 'Regular expression to validate/detect the format of an URL (URL attributes and Wiki formatting for Text attributes)',
|
||||
'default' => '(https?|ftp)\://([a-zA-Z0-9+!*(),;?&=\$_.-]+(\:[a-zA-Z0-9+!*(),;?&=\$_.-]+)?@)?([a-zA-Z0-9-.]{3,})(\:[0-9]{2,5})?(/([a-zA-Z0-9%+\$_-]\.?)+)*/?(\?[a-zA-Z+&\$_.-][a-zA-Z0-9;:[\]@&%=+/\$_.-]*)?(#[a-zA-Z_.-][a-zA-Z0-9+\$_.-]*)?',
|
||||
// SHEME.......... USER....................... PASSWORD.......................... HOST/IP........... PORT.......... PATH........................ GET............................................ ANCHOR............................
|
||||
'default' => /** @lang RegExp */
|
||||
'(https?|ftp)\://([a-zA-Z0-9+!*(),;?&=\$_.-]+(\:[a-zA-Z0-9+!*(),;?&=\$_.-]+)?@)?([a-zA-Z0-9-.]{3,})(\:[0-9]{2,5})?(/([a-zA-Z0-9:%+\$_-]\.?)+)*/?(\?[a-zA-Z+&\$_.-][a-zA-Z0-9;:[\]@&%=+/\$_.-]*)?(#[a-zA-Z_.-][a-zA-Z0-9+\$_.-]*)?',
|
||||
// SCHEME....... USER....................... PASSWORD.......................... HOST/IP........... PORT.......... PATH......................... GET............................................ ANCHOR..........................
|
||||
// Example: http://User:passWord@127.0.0.1:8888/patH/Page.php?arrayArgument[2]=something:blah20#myAnchor
|
||||
// Origin of this regexp: http://www.php.net/manual/fr/function.preg-match.php#93824
|
||||
// RegExp source: http://www.php.net/manual/fr/function.preg-match.php#93824
|
||||
// Update with N°4515
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => true,
|
||||
@@ -1175,7 +1208,7 @@ class Config
|
||||
],
|
||||
'compatibility.include_deprecated_js_files' => [
|
||||
'type' => 'bool',
|
||||
'description' => 'Include the deprecated JS files to ease usage of not migrated extensions',
|
||||
'description' => 'Include the deprecated JS files (in iTop previous version) to ease usage of not migrated extensions',
|
||||
'default' => false,
|
||||
'value' => false,
|
||||
'source_of_value' => '',
|
||||
@@ -1191,7 +1224,7 @@ class Config
|
||||
],
|
||||
'compatibility.include_deprecated_css_files' => [
|
||||
'type' => 'bool',
|
||||
'description' => 'Include the deprecated CSS files to ease usage of not migrated extensions',
|
||||
'description' => 'Include the deprecated CSS files (in iTop previous version) to ease usage of not migrated extensions',
|
||||
'default' => false,
|
||||
'value' => false,
|
||||
'source_of_value' => '',
|
||||
@@ -1600,6 +1633,16 @@ class Config
|
||||
return $this->m_aSettings[$sPropCode]['value'];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed
|
||||
*
|
||||
* @since 3.0.1 N°4515
|
||||
*/
|
||||
public function GetDefault(string $sPropCode)
|
||||
{
|
||||
return $this->m_aSettings[$sPropCode]['default'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the $sPropCode parameter has a custom value or the default one.
|
||||
*
|
||||
|
||||
@@ -220,16 +220,15 @@ class CSVBulkExport extends TabularBulkExport
|
||||
|
||||
$sFormatInput = '<input type="text" size="15" name="date_format" id="csv_custom_date_time_format" title="" value="'.htmlentities($sDateTimeFormat, ENT_QUOTES, 'UTF-8').'"/>';
|
||||
$oRadioCustom = InputUIBlockFactory::MakeForInputWithLabel(Dict::Format('Core:BulkExport:DateTimeFormatCustom_Format', $sFormatInput), "csv_date_format_radio", "custom", "csv_date_time_format_custom", "radio");
|
||||
$oRadioCustom->SetDescription(Dict::S('UI:CSVImport:CustomDateTimeFormatTooltip'));
|
||||
$oRadioCustom->GetInput()->SetIsChecked($sDateTimeFormat !== (string)AttributeDateTime::GetFormat());
|
||||
$oRadioCustom->SetBeforeInput(false);
|
||||
$oRadioCustom->GetInput()->AddCSSClass('ibo-input-checkbox');
|
||||
$oFieldSetDate->AddSubBlock($oRadioCustom);
|
||||
|
||||
$sJSTooltip = json_encode('<div class="date_format_tooltip">'.Dict::S('UI:CSVImport:CustomDateTimeFormatTooltip').'</div>');
|
||||
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$('#csv_custom_date_time_format').tooltip({content: function() { return $sJSTooltip; } });
|
||||
$('#form_part_csv_options').on('preview_updated', function() { FormatDatesInPreview('csv', 'csv'); });
|
||||
$('#csv_date_time_format_default').on('click', function() { FormatDatesInPreview('csv', 'csv'); });
|
||||
$('#csv_date_time_format_custom').on('click', function() { FormatDatesInPreview('csv', 'csv'); });
|
||||
|
||||
@@ -2934,6 +2934,9 @@ abstract class DBObject implements iDisplay
|
||||
utils::EnrichRaisedException($oTrigger, $e);
|
||||
}
|
||||
}
|
||||
|
||||
// - TriggerOnObjectMention
|
||||
$this->ActivateOnMentionTriggers(true);
|
||||
|
||||
return $this->m_iKey;
|
||||
}
|
||||
@@ -3197,50 +3200,7 @@ abstract class DBObject implements iDisplay
|
||||
// Activate any existing trigger
|
||||
$sClass = get_class($this);
|
||||
// - TriggerOnObjectMention
|
||||
// 1 - Check if any caselog updated
|
||||
$aUpdatedLogAttCodes = array();
|
||||
foreach($aChanges as $sAttCode => $value)
|
||||
{
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
if($oAttDef instanceof AttributeCaseLog)
|
||||
{
|
||||
$aUpdatedLogAttCodes[] = $sAttCode;
|
||||
}
|
||||
}
|
||||
// 2 - Find mentioned objects
|
||||
$aMentionedObjects = array();
|
||||
foreach ($aUpdatedLogAttCodes as $sAttCode) {
|
||||
/** @var \ormCaseLog $oUpdatedCaseLog */
|
||||
$oUpdatedCaseLog = $this->Get($sAttCode);
|
||||
$aMentionedObjects = array_merge_recursive($aMentionedObjects, utils::GetMentionedObjectsFromText($oUpdatedCaseLog->GetModifiedEntry()));
|
||||
}
|
||||
// 3 - Trigger for those objects
|
||||
// TODO: This should be refactored and moved into the caselogs loop, otherwise, we won't be able to know which case log triggered the action.
|
||||
foreach ($aMentionedObjects as $sMentionedClass => $aMentionedIds) {
|
||||
foreach ($aMentionedIds as $sMentionedId) {
|
||||
/** @var \DBObject $oMentionedObject */
|
||||
$oMentionedObject = MetaModel::GetObject($sMentionedClass, $sMentionedId);
|
||||
$aTriggerArgs = $this->ToArgs('this') + array('mentioned->object()' => $oMentionedObject);
|
||||
|
||||
$aParams = array('class_list' => MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL));
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnObjectMention AS t WHERE t.target_class IN (:class_list)"), array(), $aParams);
|
||||
while ($oTrigger = $oSet->Fetch())
|
||||
{
|
||||
/** @var \TriggerOnObjectMention $oTrigger */
|
||||
try {
|
||||
// Ensure to handle only mentioned object in the trigger's scope
|
||||
if ($oTrigger->IsMentionedObjectInScope($oMentionedObject) === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$oTrigger->DoActivate($aTriggerArgs);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
utils::EnrichRaisedException($oTrigger, $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$this->ActivateOnMentionTriggers(false);
|
||||
|
||||
$bHasANewExternalKeyValue = false;
|
||||
$aHierarchicalKeys = array();
|
||||
@@ -3453,6 +3413,74 @@ abstract class DBObject implements iDisplay
|
||||
return $this->m_iKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Activate TriggerOnObjectMention triggers for the current object
|
||||
*
|
||||
* @param bool $bNewlyCreatedObject
|
||||
*
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
* @since 3.0.1 N°4741
|
||||
*/
|
||||
private function ActivateOnMentionTriggers(bool $bNewlyCreatedObject): void
|
||||
{
|
||||
$sClass = get_class($this);
|
||||
$aChanges = $bNewlyCreatedObject ? $this->m_aOrigValues : $this->ListChanges();
|
||||
|
||||
// 1 - Check if any caselog updated
|
||||
$aUpdatedLogAttCodes = [];
|
||||
foreach ($aChanges as $sAttCode => $value) {
|
||||
$oAttDef = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
if ($oAttDef instanceof AttributeCaseLog) {
|
||||
// Skip empty log on creation
|
||||
if ($bNewlyCreatedObject && $value->GetModifiedEntry() === '') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$aUpdatedLogAttCodes[] = $sAttCode;
|
||||
}
|
||||
}
|
||||
|
||||
// 2 - Find mentioned objects
|
||||
$aMentionedObjects = [];
|
||||
foreach ($aUpdatedLogAttCodes as $sAttCode) {
|
||||
/** @var \ormCaseLog $oUpdatedCaseLog */
|
||||
$oUpdatedCaseLog = $this->Get($sAttCode);
|
||||
$aMentionedObjects = array_merge_recursive($aMentionedObjects, utils::GetMentionedObjectsFromText($oUpdatedCaseLog->GetModifiedEntry()));
|
||||
}
|
||||
|
||||
// 3 - Trigger for those objects
|
||||
// TODO: This should be refactored and moved into the caselogs loop, otherwise, we won't be able to know which case log triggered the action.
|
||||
foreach ($aMentionedObjects as $sMentionedClass => $aMentionedIds) {
|
||||
foreach ($aMentionedIds as $sMentionedId) {
|
||||
/** @var \DBObject $oMentionedObject */
|
||||
$oMentionedObject = MetaModel::GetObject($sMentionedClass, $sMentionedId);
|
||||
$aTriggerArgs = $this->ToArgs('this') + ['mentioned->object()' => $oMentionedObject];
|
||||
|
||||
$aParams = ['class_list' => MetaModel::EnumParentClasses($sClass, ENUM_PARENT_CLASSES_ALL)];
|
||||
$oSet = new DBObjectSet(DBObjectSearch::FromOQL("SELECT TriggerOnObjectMention AS t WHERE t.target_class IN (:class_list)"), [], $aParams);
|
||||
while ($oTrigger = $oSet->Fetch())
|
||||
{
|
||||
/** @var \TriggerOnObjectMention $oTrigger */
|
||||
try {
|
||||
// Ensure to handle only mentioned object in the trigger's scope
|
||||
if ($oTrigger->IsMentionedObjectInScope($oMentionedObject) === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$oTrigger->DoActivate($aTriggerArgs);
|
||||
}
|
||||
catch (Exception $e) {
|
||||
utils::EnrichRaisedException($oTrigger, $e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* Save updated fields previous values for {@see DBObject::DBUpdate()} callbacks
|
||||
@@ -5378,7 +5406,7 @@ abstract class DBObject implements iDisplay
|
||||
}
|
||||
$oLnk->Set($sRoleAttCode, $sRoleValue);
|
||||
}
|
||||
$oLinkSet->AddObject($oLnk);
|
||||
$oLinkSet->AddItem($oLnk);
|
||||
$this->Set($sTargetListAttCode, $oLinkSet);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -416,6 +416,10 @@ class DBObjectSearch extends DBSearch
|
||||
* @param string $sFilterCode
|
||||
* @param mixed $value
|
||||
* @param string $sOpCode operator to use : 'IN', 'NOT IN', 'Contains',' Begins with', 'Finishes with', ...
|
||||
* If no operator is specified then :
|
||||
* * for id field we will use "="
|
||||
* * for other fields we will call the corresponding {@link AttributeDefinition::GetSmartConditionExpression} method impl
|
||||
* to generate the expression
|
||||
* @param bool $bParseSearchString
|
||||
*
|
||||
* @throws \CoreException
|
||||
@@ -465,14 +469,14 @@ class DBObjectSearch extends DBSearch
|
||||
if (!is_array($value)) $value = array($value);
|
||||
if (count($value) === 0) throw new Exception('AddCondition '.$sOpCode.': Value cannot be an empty array.');
|
||||
$sListExpr = '('.implode(', ', CMDBSource::Quote($value)).')';
|
||||
$sOQLCondition = $oField->Render()." IN $sListExpr";
|
||||
$sOQLCondition = $oField->RenderExpression()." IN $sListExpr";
|
||||
break;
|
||||
|
||||
case 'NOTIN':
|
||||
if (!is_array($value)) $value = array($value);
|
||||
if (count($value) === 0) throw new Exception('AddCondition '.$sOpCode.': Value cannot be an empty array.');
|
||||
$sListExpr = '('.implode(', ', CMDBSource::Quote($value)).')';
|
||||
$sOQLCondition = $oField->Render()." NOT IN $sListExpr";
|
||||
$sOQLCondition = $oField->RenderExpression()." NOT IN $sListExpr";
|
||||
break;
|
||||
|
||||
case 'Contains':
|
||||
@@ -1232,7 +1236,7 @@ class DBObjectSearch extends DBSearch
|
||||
elseif (MetaModel::IsParentClass($oRightFilter->GetFirstJoinedClass(), $oLeftFilter->GetClass()))
|
||||
{
|
||||
// Specialize $oRightFilter
|
||||
$oRightFilter->ChangeClass($oLeftFilter->GetClass());
|
||||
$oRightFilter->ChangeClass($oLeftFilter->GetFirstJoinedClass());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1368,7 +1372,7 @@ class DBObjectSearch extends DBSearch
|
||||
public function GetQueryParams($bExcludeMagicParams = true)
|
||||
{
|
||||
$aParams = array();
|
||||
$this->m_oSearchCondition->Render($aParams, true);
|
||||
$this->m_oSearchCondition->RenderExpression(false, $aParams, true);
|
||||
|
||||
if ($bExcludeMagicParams)
|
||||
{
|
||||
@@ -1457,7 +1461,7 @@ class DBObjectSearch extends DBSearch
|
||||
|
||||
$sRes .= ' ' . $this->GetFirstJoinedClass() . ' AS `' . $this->GetFirstJoinedClassAlias() . '`';
|
||||
$sRes .= $this->ToOQL_Joins();
|
||||
$sRes .= " WHERE ".$this->m_oSearchCondition->Render($aParams, $bRetrofitParams);
|
||||
$sRes .= " WHERE ".$this->m_oSearchCondition->RenderExpression(false, $aParams, $bRetrofitParams);
|
||||
|
||||
if ($bWithAllowAllFlag && $this->m_bAllowAllData)
|
||||
{
|
||||
|
||||
@@ -416,7 +416,11 @@ class DBUnionSearch extends DBSearch
|
||||
$aSearches = array();
|
||||
foreach ($this->aSearches as $oSearch)
|
||||
{
|
||||
$aSearches[] = $oSearch->Filter($sClassAlias, $oFilter);
|
||||
if (!$oSearch->IsAllDataAllowed()) {
|
||||
$aSearches[] = $oSearch->Filter($sClassAlias, $oFilter);
|
||||
} else {
|
||||
$aSearches[] = $oSearch;
|
||||
}
|
||||
}
|
||||
return new DBUnionSearch($aSearches);
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ class Dict
|
||||
protected static $m_aLanguages = array(); // array( code => array( 'description' => '...', 'localized_description' => '...') ...)
|
||||
protected static $m_aData = array();
|
||||
protected static $m_sApplicationPrefix = null;
|
||||
/** @var \ApcService $m_oApcService */
|
||||
protected static $m_oApcService = null;
|
||||
|
||||
/**
|
||||
* @param $sLanguageCode
|
||||
@@ -116,15 +118,17 @@ class Dict
|
||||
{
|
||||
// Attempt to find the string in the user language
|
||||
//
|
||||
self::InitLangIfNeeded(self::GetUserLanguage());
|
||||
$sLangCode = self::GetUserLanguage();
|
||||
self::InitLangIfNeeded($sLangCode);
|
||||
|
||||
if (!array_key_exists(self::GetUserLanguage(), self::$m_aData))
|
||||
if (!array_key_exists($sLangCode, self::$m_aData))
|
||||
{
|
||||
IssueLog::Warning("Cannot find $sLangCode in dictionnaries. default labels displayed");
|
||||
// It may happen, when something happens before the dictionaries get loaded
|
||||
return $sStringCode;
|
||||
}
|
||||
$aCurrentDictionary = self::$m_aData[self::GetUserLanguage()];
|
||||
if (array_key_exists($sStringCode, $aCurrentDictionary))
|
||||
$aCurrentDictionary = self::$m_aData[$sLangCode];
|
||||
if (is_array($aCurrentDictionary) && array_key_exists($sStringCode, $aCurrentDictionary))
|
||||
{
|
||||
return $aCurrentDictionary[$sStringCode];
|
||||
}
|
||||
@@ -135,7 +139,7 @@ class Dict
|
||||
self::InitLangIfNeeded(self::$m_sDefaultLanguage);
|
||||
|
||||
$aDefaultDictionary = self::$m_aData[self::$m_sDefaultLanguage];
|
||||
if (array_key_exists($sStringCode, $aDefaultDictionary))
|
||||
if (is_array($aDefaultDictionary) && array_key_exists($sStringCode, $aDefaultDictionary))
|
||||
{
|
||||
return $aDefaultDictionary[$sStringCode];
|
||||
}
|
||||
@@ -144,7 +148,7 @@ class Dict
|
||||
self::InitLangIfNeeded('EN US');
|
||||
|
||||
$aDefaultDictionary = self::$m_aData['EN US'];
|
||||
if (array_key_exists($sStringCode, $aDefaultDictionary))
|
||||
if (is_array($aDefaultDictionary) && array_key_exists($sStringCode, $aDefaultDictionary))
|
||||
{
|
||||
return $aDefaultDictionary[$sStringCode];
|
||||
}
|
||||
@@ -203,7 +207,26 @@ class Dict
|
||||
{
|
||||
self::$m_aLanguages = $aLanguagesList;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @since 2.7.6 N°4125
|
||||
* @return \ApcService
|
||||
*/
|
||||
public static function GetApcService() {
|
||||
if (self::$m_oApcService === null){
|
||||
self::$m_oApcService = new ApcService();
|
||||
}
|
||||
return self::$m_oApcService;
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 2.7.6 N°4125
|
||||
* @param \ApcService $m_oApcService
|
||||
*/
|
||||
public static function SetApcService($oApcService) {
|
||||
self::$m_oApcService = $oApcService;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load a language from the language dictionary, if not already loaded
|
||||
* @param string $sLangCode Language code
|
||||
@@ -212,20 +235,23 @@ class Dict
|
||||
public static function InitLangIfNeeded($sLangCode)
|
||||
{
|
||||
if (array_key_exists($sLangCode, self::$m_aData)) return true;
|
||||
|
||||
|
||||
$bResult = false;
|
||||
|
||||
if (function_exists('apc_fetch') && (self::$m_sApplicationPrefix !== null))
|
||||
|
||||
if (self::GetApcService()->function_exists('apc_fetch')
|
||||
&& (self::$m_sApplicationPrefix !== null))
|
||||
{
|
||||
// Note: For versions of APC older than 3.0.17, fetch() accepts only one parameter
|
||||
//
|
||||
self::$m_aData[$sLangCode] = apc_fetch(self::$m_sApplicationPrefix.'-dict-'.$sLangCode);
|
||||
if (self::$m_aData[$sLangCode] === false)
|
||||
{
|
||||
self::$m_aData[$sLangCode] = self::GetApcService()->apc_fetch(self::$m_sApplicationPrefix.'-dict-'.$sLangCode);
|
||||
if (self::$m_aData[$sLangCode] === false) {
|
||||
unset(self::$m_aData[$sLangCode]);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else if (! is_array(self::$m_aData[$sLangCode])) {
|
||||
// N°4125: we dont fix dictionnary corrupted cache (on iTop side).
|
||||
// but we log an error in a dedicated channel to let itop administrator be aware of a potential APCu issue to fix.
|
||||
IssueLog::Error("APCu corrupted data (with $sLangCode dictionnary). APCu configuration and running version should be troubleshooted...", LogChannels::APC);
|
||||
$bResult = true;
|
||||
} else {
|
||||
$bResult = true;
|
||||
}
|
||||
}
|
||||
@@ -234,9 +260,10 @@ class Dict
|
||||
$sDictFile = APPROOT.'env-'.utils::GetCurrentEnvironment().'/dictionaries/'.str_replace(' ', '-', strtolower($sLangCode)).'.dict.php';
|
||||
require_once($sDictFile);
|
||||
|
||||
if (function_exists('apc_store') && (self::$m_sApplicationPrefix !== null))
|
||||
if (self::GetApcService()->function_exists('apc_store')
|
||||
&& (self::$m_sApplicationPrefix !== null))
|
||||
{
|
||||
apc_store(self::$m_sApplicationPrefix.'-dict-'.$sLangCode, self::$m_aData[$sLangCode]);
|
||||
self::GetApcService()->apc_store(self::$m_sApplicationPrefix.'-dict-'.$sLangCode, self::$m_aData[$sLangCode]);
|
||||
}
|
||||
$bResult = true;
|
||||
}
|
||||
@@ -275,13 +302,12 @@ class Dict
|
||||
*
|
||||
* @param $sSourceCode
|
||||
* @param $sDestCode
|
||||
* @since 3.0.1 Not clone sSourceCode entry if sDestCode entry already exist
|
||||
*/
|
||||
public static function CloneString($sSourceCode, $sDestCode)
|
||||
{
|
||||
foreach(self::$m_aLanguages as $sLanguageCode => $foo)
|
||||
{
|
||||
if (isset(self::$m_aData[$sLanguageCode][$sSourceCode]))
|
||||
{
|
||||
foreach(self::$m_aLanguages as $sLanguageCode => $foo) {
|
||||
if (isset(self::$m_aData[$sLanguageCode][$sSourceCode]) && !isset(self::$m_aData[$sLanguageCode][$sDestCode] )) {
|
||||
self::$m_aData[$sLanguageCode][$sDestCode] = self::$m_aData[$sLanguageCode][$sSourceCode];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ class DisplayableNode extends GraphNode
|
||||
{
|
||||
public $x;
|
||||
public $y;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new node inside a graph
|
||||
* @param SimpleGraph $oGraph
|
||||
@@ -51,27 +51,27 @@ class DisplayableNode extends GraphNode
|
||||
{
|
||||
return $this->GetProperty('icon_url', '');
|
||||
}
|
||||
|
||||
|
||||
public function GetLabel()
|
||||
{
|
||||
return $this->GetProperty('label', $this->sId);
|
||||
}
|
||||
|
||||
|
||||
public function GetWidth()
|
||||
{
|
||||
return max(32, 5*strlen($this->GetProperty('label'))); // approximation of the text's bounding box
|
||||
}
|
||||
|
||||
|
||||
public function GetHeight()
|
||||
{
|
||||
return 32;
|
||||
}
|
||||
|
||||
|
||||
public function Distance2(DisplayableNode $oNode)
|
||||
{
|
||||
$dx = $this->x - $oNode->x;
|
||||
$dy = $this->y - $oNode->y;
|
||||
|
||||
|
||||
$d2 = $dx*$dx + $dy*$dy - $this->GetHeight()*$this->GetHeight();
|
||||
if ($d2 < 40)
|
||||
{
|
||||
@@ -79,12 +79,12 @@ class DisplayableNode extends GraphNode
|
||||
}
|
||||
return $d2;
|
||||
}
|
||||
|
||||
|
||||
public function Distance(DisplayableNode $oNode)
|
||||
{
|
||||
return sqrt($this->Distance2($oNode));
|
||||
}
|
||||
|
||||
|
||||
public function GetForRaphael($aContextDefs)
|
||||
{
|
||||
$aNode = array();
|
||||
@@ -100,7 +100,7 @@ class DisplayableNode extends GraphNode
|
||||
$aNode['label'] = $this->GetLabel();
|
||||
$aNode['id'] = $this->GetId();
|
||||
$fOpacity = ($this->GetProperty('is_reached') ? 1 : 0.4);
|
||||
$aNode['icon_attr'] = array('opacity' => $fOpacity);
|
||||
$aNode['icon_attr'] = array('opacity' => $fOpacity);
|
||||
$aNode['text_attr'] = array('opacity' => $fOpacity);
|
||||
$aNode['tooltip'] = $this->GetTooltip($aContextDefs);
|
||||
$aNode['context_icons'] = array();
|
||||
@@ -114,7 +114,7 @@ class DisplayableNode extends GraphNode
|
||||
}
|
||||
return $aNode;
|
||||
}
|
||||
|
||||
|
||||
public function RenderAsPDF(iTopPDF $oPdf, DisplayableGraph $oGraph, $fScale, $aContextDefs)
|
||||
{
|
||||
$Alpha = 1.0;
|
||||
@@ -170,7 +170,7 @@ class DisplayableNode extends GraphNode
|
||||
$oPdf->SetTextColor(0, 0, 0);
|
||||
$oPdf->Text($this->x*$fScale - $width/2, ($this->y + 18)*$fScale, $this->GetProperty('label'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a "whitened" version of the icon (retaining the transparency) to be used a background for masking the underlying lines
|
||||
* @param string $sIconFile The path to the file containing the icon
|
||||
@@ -179,35 +179,35 @@ class DisplayableNode extends GraphNode
|
||||
protected function CreateWhiteIcon(DisplayableGraph $oGraph, $sIconFile)
|
||||
{
|
||||
$aInfo = getimagesize($sIconFile);
|
||||
|
||||
|
||||
$im = null;
|
||||
switch($aInfo['mime'])
|
||||
{
|
||||
case 'image/png':
|
||||
if (function_exists('imagecreatefrompng'))
|
||||
{
|
||||
$im = imagecreatefrompng($sIconFile);
|
||||
}
|
||||
break;
|
||||
|
||||
if (function_exists('imagecreatefrompng'))
|
||||
{
|
||||
$im = imagecreatefrompng($sIconFile);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'image/gif':
|
||||
if (function_exists('imagecreatefromgif'))
|
||||
{
|
||||
$im = imagecreatefromgif($sIconFile);
|
||||
}
|
||||
break;
|
||||
|
||||
if (function_exists('imagecreatefromgif'))
|
||||
{
|
||||
$im = imagecreatefromgif($sIconFile);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'image/jpeg':
|
||||
case 'image/jpg':
|
||||
if (function_exists('imagecreatefromjpeg'))
|
||||
{
|
||||
$im = imagecreatefromjpeg($sIconFile);
|
||||
}
|
||||
break;
|
||||
|
||||
if (function_exists('imagecreatefromjpeg'))
|
||||
{
|
||||
$im = imagecreatefromjpeg($sIconFile);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return null;
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
if($im && imagefilter($im, IMG_FILTER_COLORIZE, 255, 255, 255))
|
||||
{
|
||||
@@ -222,17 +222,17 @@ class DisplayableNode extends GraphNode
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function GetObjectCount()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
public function GetObjectClass()
|
||||
{
|
||||
return is_object($this->GetProperty('object', null)) ? get_class($this->GetProperty('object', null)) : null;
|
||||
}
|
||||
|
||||
|
||||
protected function AddToStats($oNode, &$aNodesPerClass)
|
||||
{
|
||||
$sClass = $oNode->GetObjectClass();
|
||||
@@ -256,9 +256,9 @@ class DisplayableNode extends GraphNode
|
||||
{
|
||||
$aNodesPerClass[$sClass][$sKey]['nodes'][$oNode->GetId()] = $oNode;
|
||||
$aNodesPerClass[$sClass][$sKey]['count'] += $oNode->GetObjectCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves the list of neighbour nodes, in the given direction: 'up' or 'down'
|
||||
* @param bool $bDirectionDown
|
||||
@@ -279,11 +279,11 @@ class DisplayableNode extends GraphNode
|
||||
foreach($this->GetIncomingEdges() as $oEdge)
|
||||
{
|
||||
$aNextNodes[] = $oEdge->GetSourceNode();
|
||||
}
|
||||
}
|
||||
}
|
||||
return $aNextNodes;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Replaces the next neighbour node (in the given direction: 'up' or 'down') by the supplied group node
|
||||
* preserving the connectivity of the graph
|
||||
@@ -351,7 +351,7 @@ class DisplayableNode extends GraphNode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ($oGraph->GetNode($oNextNode->GetId()))
|
||||
{
|
||||
$oGraph->_RemoveNode($oNextNode);
|
||||
@@ -367,9 +367,9 @@ class DisplayableNode extends GraphNode
|
||||
{
|
||||
$oNewNode->AddObject($oNextNode->GetProperty('object'));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Group together (as a special kind of nodes) all the similar neighbours of the current node
|
||||
* @param DisplayableGraph $oGraph
|
||||
@@ -381,7 +381,7 @@ class DisplayableNode extends GraphNode
|
||||
{
|
||||
if ($this->GetProperty('grouped') === true) return;
|
||||
$this->SetProperty('grouped', true);
|
||||
|
||||
|
||||
$aNodesPerClass = array();
|
||||
foreach($this->GetNextNodes($bDirectionDown) as $oNode)
|
||||
{
|
||||
@@ -412,7 +412,7 @@ class DisplayableNode extends GraphNode
|
||||
$oNewNode->SetProperty('is_reached', ($sStatus == 'reached'));
|
||||
$oNewNode->SetProperty('count', $aGroupProps['count']);
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
if ($bDirectionDown)
|
||||
@@ -427,8 +427,8 @@ class DisplayableNode extends GraphNode
|
||||
catch(Exception $e)
|
||||
{
|
||||
// Ignore this redundant egde
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
foreach($aGroupProps['nodes'] as $oNextNode)
|
||||
{
|
||||
$this->ReplaceNextNodeBy($oGraph, $oNextNode, $oNewNode, $bDirectionDown);
|
||||
@@ -445,7 +445,7 @@ class DisplayableNode extends GraphNode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function GetTooltip($aContextDefs)
|
||||
{
|
||||
$sHtml = '';
|
||||
@@ -474,9 +474,9 @@ class DisplayableNode extends GraphNode
|
||||
$sHtml .= '<tr><td>'.$oAttDef->GetLabel().': </td><td>'.$oCurrObj->GetAsHtml($sAttCode).'</td></tr>';
|
||||
}
|
||||
$sHtml .= '</tbody></table>';
|
||||
return $sHtml;
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the description of the node in "dot" language
|
||||
* Used to generate the positions in the graph, but we'd better use fake label
|
||||
@@ -508,7 +508,7 @@ class DisplayableRedundancyNode extends DisplayableNode
|
||||
{
|
||||
return 24;
|
||||
}
|
||||
|
||||
|
||||
public function GetForRaphael($aContextDefs)
|
||||
{
|
||||
$aNode = array();
|
||||
@@ -519,7 +519,7 @@ class DisplayableRedundancyNode extends DisplayableNode
|
||||
$aNode['x'] = $this->x;
|
||||
$aNode['y']= $this->y;
|
||||
$aNode['label'] = $this->GetLabel();
|
||||
$aNode['id'] = $this->GetId();
|
||||
$aNode['id'] = $this->GetId();
|
||||
$fDiscOpacity = ($this->GetProperty('is_reached') ? 1 : 0.2);
|
||||
$sColor = ($this->GetProperty('is_reached_count') > $this->GetProperty('threshold')) ? '#c33' : '#999';
|
||||
$aNode['disc_attr'] = array('stroke-width' => 2, 'stroke' => '#000', 'fill' => $sColor, 'opacity' => $fDiscOpacity);
|
||||
@@ -550,35 +550,35 @@ class DisplayableRedundancyNode extends DisplayableNode
|
||||
$height = $oPdf->GetStringHeight(1000, $sLabel);
|
||||
$xPos = (float)$this->x*$fScale - $width/2;
|
||||
$yPos = (float)$this->y*$fScale - $height/2;
|
||||
|
||||
|
||||
$oPdf->SetXY(($this->x - 16)*$fScale, ($this->y - 16)*$fScale);
|
||||
|
||||
|
||||
$oPdf->Cell(32*$fScale, 32*$fScale, $sLabel, 0, 0, 'C', 0, '', 0, false, 'T', 'C');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @see DisplayableNode::GroupSimilarNeighbours()
|
||||
*/
|
||||
public function GroupSimilarNeighbours(DisplayableGraph $oGraph, $iThresholdCount, $bDirectionUp = false, $bDirectionDown = true)
|
||||
{
|
||||
parent::GroupSimilarNeighbours($oGraph, $iThresholdCount, $bDirectionUp, $bDirectionDown);
|
||||
|
||||
|
||||
if ($bDirectionUp)
|
||||
{
|
||||
$aNodesPerClass = array();
|
||||
foreach($this->GetIncomingEdges() as $oEdge)
|
||||
{
|
||||
$oNode = $oEdge->GetSourceNode();
|
||||
|
||||
|
||||
if (($oNode->GetObjectClass() !== null) && (!$oNode->GetProperty('is_reached')))
|
||||
{
|
||||
{
|
||||
$this->AddToStats($oNode, $aNodesPerClass);
|
||||
}
|
||||
else
|
||||
{
|
||||
//$oNode->GroupSimilarNeighbours($oGraph, $iThresholdCount, $bDirectionUp, $bDirectionDown);
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach($aNodesPerClass as $sClass => $aDefs)
|
||||
{
|
||||
foreach($aDefs as $sStatus => $aGroupProps)
|
||||
@@ -591,8 +591,8 @@ class DisplayableRedundancyNode extends DisplayableNode
|
||||
$oNewNode->SetProperty('is_reached', ($sStatus == 'is_reached'));
|
||||
$oNewNode->SetProperty('class', $sClass);
|
||||
$oNewNode->SetProperty('count', count($aGroupProps['nodes']));
|
||||
|
||||
|
||||
|
||||
|
||||
$sNewId = $this->GetId().'::'.$sClass.'/'.(($sStatus == 'reached') ? '_reached': '');
|
||||
$oNewNode = $oGraph->GetNode($sNewId);
|
||||
if ($oNewNode == null)
|
||||
@@ -604,7 +604,7 @@ class DisplayableRedundancyNode extends DisplayableNode
|
||||
$oNewNode->SetProperty('is_reached', ($sStatus == 'reached'));
|
||||
$oNewNode->SetProperty('count', $aGroupProps['count']);
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
$oOutgoingEdge = new DisplayableEdge($oGraph, '-'.$this->GetId().'-'.$oNewNode->GetId().'/'.$sStatus, $oNewNode, $this);
|
||||
@@ -613,7 +613,7 @@ class DisplayableRedundancyNode extends DisplayableNode
|
||||
{
|
||||
// Ignore this redundant egde
|
||||
}
|
||||
|
||||
|
||||
foreach($aGroupProps['nodes'] as $oNextNode)
|
||||
{
|
||||
$this->ReplaceNextNodeBy($oGraph, $oNextNode, $oNewNode, !$bDirectionUp);
|
||||
@@ -631,7 +631,7 @@ class DisplayableRedundancyNode extends DisplayableNode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function GetTooltip($aContextDefs)
|
||||
{
|
||||
$sHtml = '';
|
||||
@@ -640,9 +640,9 @@ class DisplayableRedundancyNode extends DisplayableNode
|
||||
$sHtml .= "<tr><td>".Dict::Format('UI:RelationTooltip:ImpactedItems_N_of_M' , $this->GetProperty('is_reached_count'), $this->GetProperty('min_up') + $this->GetProperty('threshold'))."</td></tr>";
|
||||
$sHtml .= "<tr><td>".Dict::Format('UI:RelationTooltip:CriticalThreshold_N_of_M' , $this->GetProperty('threshold'), $this->GetProperty('min_up') + $this->GetProperty('threshold'))."</td></tr>";
|
||||
$sHtml .= '</tbody></table>';
|
||||
return $sHtml;
|
||||
return $sHtml;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function GetObjectCount()
|
||||
{
|
||||
@@ -666,7 +666,7 @@ class DisplayableEdge extends GraphEdge
|
||||
}
|
||||
$xStart = $oSourceNode->x * $fScale;
|
||||
$yStart = $oSourceNode->y * $fScale;
|
||||
|
||||
|
||||
$oSinkNode = $this->GetSinkNode();
|
||||
if (($oSinkNode->x == null) || ($oSinkNode->y == null))
|
||||
{
|
||||
@@ -674,9 +674,9 @@ class DisplayableEdge extends GraphEdge
|
||||
}
|
||||
$xEnd = $oSinkNode->x * $fScale;
|
||||
$yEnd = $oSinkNode->y * $fScale;
|
||||
|
||||
|
||||
$bReached = ($this->GetSourceNode()->GetProperty('is_reached') && $this->GetSinkNode()->GetProperty('is_reached'));
|
||||
|
||||
|
||||
$oPdf->setAlpha(1);
|
||||
if ($bReached)
|
||||
{
|
||||
@@ -688,8 +688,8 @@ class DisplayableEdge extends GraphEdge
|
||||
}
|
||||
$oPdf->SetLineStyle(array('width' => 2*$fScale, 'cap' => 'round', 'join' => 'miter', 'dash' => 0, 'color' => $aColor));
|
||||
$oPdf->Line($xStart, $yStart, $xEnd, $yEnd);
|
||||
|
||||
|
||||
|
||||
|
||||
$vx = $xEnd - $xStart;
|
||||
$vy = $yEnd - $yStart;
|
||||
$l = sqrt($vx*$vx + $vy*$vy);
|
||||
@@ -699,24 +699,24 @@ class DisplayableEdge extends GraphEdge
|
||||
$uy = $vx;
|
||||
$lPos = max($l/2, $l - 40*$fScale);
|
||||
$iArrowSize = 5*$fScale;
|
||||
|
||||
|
||||
$x = $xStart + $lPos * $vx;
|
||||
$y = $yStart + $lPos * $vy;
|
||||
$oPdf->Line($x, $y, $x + $iArrowSize * ($ux-$vx), $y + $iArrowSize * ($uy-$vy));
|
||||
$oPdf->Line($x, $y, $x - $iArrowSize * ($ux+$vx), $y - $iArrowSize * ($uy+$vy));
|
||||
$oPdf->Line($x, $y, $x - $iArrowSize * ($ux+$vx), $y - $iArrowSize * ($uy+$vy));
|
||||
}
|
||||
}
|
||||
|
||||
class DisplayableGroupNode extends DisplayableNode
|
||||
{
|
||||
protected $aObjects;
|
||||
|
||||
|
||||
public function __construct(SimpleGraph $oGraph, $sId, $x = 0, $y = 0)
|
||||
{
|
||||
parent::__construct($oGraph, $sId, $x, $y);
|
||||
$this->aObjects = array();
|
||||
}
|
||||
|
||||
|
||||
public function AddObject(DBObject $oObj = null)
|
||||
{
|
||||
if (is_object($oObj))
|
||||
@@ -729,12 +729,12 @@ class DisplayableGroupNode extends DisplayableNode
|
||||
$this->aObjects[$oObj->GetKey()] = $oObj;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function GetObjects()
|
||||
{
|
||||
return $this->aObjects;
|
||||
}
|
||||
|
||||
|
||||
public function GetWidth()
|
||||
{
|
||||
return 50;
|
||||
@@ -760,7 +760,7 @@ class DisplayableGroupNode extends DisplayableNode
|
||||
$aNode['tooltip'] = $this->GetTooltip($aContextDefs);
|
||||
return $aNode;
|
||||
}
|
||||
|
||||
|
||||
public function RenderAsPDF(iTopPDF $oPdf, DisplayableGraph $oGraph, $fScale, $aContextDefs)
|
||||
{
|
||||
$bReached = $this->GetProperty('is_reached');
|
||||
@@ -790,7 +790,7 @@ class DisplayableGroupNode extends DisplayableNode
|
||||
$oPdf->SetTextColor(0, 0, 0);
|
||||
$oPdf->Text($this->x * $fScale - $width / 2, ($this->y + 25) * $fScale, $this->GetProperty('label'));
|
||||
}
|
||||
|
||||
|
||||
public function GetTooltip($aContextDefs)
|
||||
{
|
||||
$iGroupIdx = $this->GetProperty('group_index');
|
||||
@@ -823,7 +823,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
protected $aTempImages;
|
||||
protected $aSourceObjects;
|
||||
protected $aSinkObjects;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
@@ -831,14 +831,14 @@ class DisplayableGraph extends SimpleGraph
|
||||
$this->aSourceObjects = array();
|
||||
$this->aSinkObjects = array();
|
||||
}
|
||||
|
||||
|
||||
public function GetTempImageName()
|
||||
{
|
||||
$sNewTempName = tempnam(APPROOT.'data', 'img-');
|
||||
$this->aTempImages[] = $sNewTempName;
|
||||
return $sNewTempName;
|
||||
}
|
||||
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
foreach($this->aTempImages as $sTempFile)
|
||||
@@ -918,7 +918,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
$oSinkNode = $oNewGraph->GetNode($oEdge->GetSinkNode()->GetId());
|
||||
$oNewEdge = new DisplayableEdge($oNewGraph, $oEdge->GetId(), $oSourceNode, $oSinkNode);
|
||||
}
|
||||
|
||||
|
||||
// Remove duplicate edges between two nodes
|
||||
$oEdgesIter = new RelationTypeIterator($oNewGraph, 'Edge');
|
||||
$aEdgeKeys = array();
|
||||
@@ -946,7 +946,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$oNodesIter = new RelationTypeIterator($oNewGraph, 'Node');
|
||||
foreach($oNodesIter as $oNode)
|
||||
{
|
||||
@@ -981,7 +981,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Remove duplicate edges between two nodes
|
||||
$oEdgesIter = new RelationTypeIterator($oNewGraph, 'Edge');
|
||||
$aEdgeKeys = array();
|
||||
@@ -1010,10 +1010,10 @@ class DisplayableGraph extends SimpleGraph
|
||||
}
|
||||
}
|
||||
set_time_limit(intval($iPreviousTimeLimit));
|
||||
|
||||
|
||||
return $oNewGraph;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initializes the positions by rendering using Graphviz in xdot format
|
||||
* and parsing the output.
|
||||
@@ -1026,7 +1026,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
{
|
||||
throw new Exception($sDot);
|
||||
}
|
||||
|
||||
|
||||
$aChunks = explode(";", $sDot);
|
||||
foreach($aChunks as $sChunk)
|
||||
{
|
||||
@@ -1035,7 +1035,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
$sId = $aMatches[1];
|
||||
$xPos = $aMatches[2];
|
||||
$yPos = $aMatches[3];
|
||||
|
||||
|
||||
$oNode = $this->GetNode($sId);
|
||||
if ($oNode !== null)
|
||||
{
|
||||
@@ -1049,7 +1049,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function GetBoundingBox()
|
||||
{
|
||||
$xMin = null;
|
||||
@@ -1074,10 +1074,10 @@ class DisplayableGraph extends SimpleGraph
|
||||
$yMax = max($yMax, $oNode->y + $oNode->GetHeight() / 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return array('xmin' => $xMin, 'xmax' => $xMax, 'ymin' => $yMin, 'ymax' => $yMax);
|
||||
}
|
||||
|
||||
|
||||
function Translate($dx, $dy)
|
||||
{
|
||||
$oIterator = new RelationTypeIterator($this, 'Node');
|
||||
@@ -1085,9 +1085,9 @@ class DisplayableGraph extends SimpleGraph
|
||||
{
|
||||
$oNode->x += $dx;
|
||||
$oNode->y += $dy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function UpdatePositions($aPositions)
|
||||
{
|
||||
foreach($aPositions as $sNodeId => $aPos)
|
||||
@@ -1107,7 +1107,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
function GetAsJSON($sContextKey)
|
||||
{
|
||||
$aContextDefs = static::GetContextDefinitions($sContextKey, false);
|
||||
|
||||
|
||||
$aData = array('nodes' => array(), 'edges' => array(), 'groups' => array(), 'lists' => array());
|
||||
$iGroupIdx = 0;
|
||||
$oIterator = new RelationTypeIterator($this, 'Node');
|
||||
@@ -1131,7 +1131,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
$aData['groups'][$iGroupIdx] = array('class' => $sClass, 'keys' => $aKeys);
|
||||
$oNode->SetProperty('group_index', $iGroupIdx);
|
||||
$iGroupIdx++;
|
||||
|
||||
|
||||
if ($oNode->GetProperty('is_reached'))
|
||||
{
|
||||
// Also add the objects from this group into the 'list' tab
|
||||
@@ -1139,11 +1139,11 @@ class DisplayableGraph extends SimpleGraph
|
||||
{
|
||||
$aData['lists'][$sClass] = $aKeys;
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
$aData['lists'][$sClass] = array_merge($aData['lists'][$sClass], $aKeys);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
if (($oNode instanceof DisplayableNode) && $oNode->GetProperty('is_reached') && is_object($oNode->GetProperty('object')))
|
||||
@@ -1157,9 +1157,9 @@ class DisplayableGraph extends SimpleGraph
|
||||
}
|
||||
$aData['nodes'][] = $oNode->GetForRaphael($aContextDefs);
|
||||
}
|
||||
|
||||
|
||||
uksort($aData['lists'], array(get_class($this), 'SortOnClassLabel')); // sort on the localized names of the classes to provide a consistent and stable order
|
||||
|
||||
|
||||
$oIterator = new RelationTypeIterator($this, 'Edge');
|
||||
foreach($oIterator as $sId => $oEdge)
|
||||
{
|
||||
@@ -1171,7 +1171,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
$aEdge['attr'] = array('opacity' => $fOpacity, 'stroke' => '#000');
|
||||
$aData['edges'][] = $aEdge;
|
||||
}
|
||||
|
||||
|
||||
return json_encode($aData);
|
||||
}
|
||||
|
||||
@@ -1200,12 +1200,12 @@ class DisplayableGraph extends SimpleGraph
|
||||
{
|
||||
$aContextDefs = static::GetContextDefinitions($sContextKey, false); // No need to develop the parameters
|
||||
$oPdf = $oPage->get_tcpdf();
|
||||
|
||||
|
||||
$aBB = $this->GetBoundingBox();
|
||||
$this->Translate(-$aBB['xmin'], -$aBB['ymin']);
|
||||
|
||||
|
||||
$aMargins = $oPdf->getMargins();
|
||||
|
||||
|
||||
if ($xMin == -1)
|
||||
{
|
||||
$xMin = $aMargins['left'];
|
||||
@@ -1222,7 +1222,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
{
|
||||
$yMax = $oPdf->getPageHeight() - $aMargins['bottom'];
|
||||
}
|
||||
|
||||
|
||||
$fBreakMargin = $oPdf->getBreakMargin();
|
||||
$oPdf->SetAutoPageBreak(false);
|
||||
$aRemainingArea = $this->RenderKey($oPdf, $sComments, $xMin, $yMin, $xMax, $yMax, $aContextDefs);
|
||||
@@ -1230,19 +1230,19 @@ class DisplayableGraph extends SimpleGraph
|
||||
$xMax = $aRemainingArea['xmax'];
|
||||
$yMin = $aRemainingArea['ymin'];
|
||||
$yMax = $aRemainingArea['ymax'];
|
||||
|
||||
|
||||
//$oPdf->Rect($xMin, $yMin, $xMax - $xMin, $yMax - $yMin, 'D', array(), array(225, 50, 50));
|
||||
|
||||
|
||||
$fPageW = $xMax - $xMin;
|
||||
$fPageH = $yMax - $yMin;
|
||||
|
||||
$w = $aBB['xmax'] - $aBB['xmin'];
|
||||
|
||||
$w = $aBB['xmax'] - $aBB['xmin'];
|
||||
$h = $aBB['ymax'] - $aBB['ymin'] + 10; // Extra space for the labels which may appear "below" the icons
|
||||
|
||||
|
||||
$fScale = min($fPageW / $w, $fPageH / $h);
|
||||
$dx = ($fPageW - $fScale * $w) / 2;
|
||||
$dy = ($fPageH - $fScale * $h) / 2;
|
||||
|
||||
|
||||
$this->Translate(($xMin + $dx)/$fScale, ($yMin + $dy)/$fScale);
|
||||
|
||||
$oIterator = new RelationTypeIterator($this, 'Edge');
|
||||
@@ -1264,7 +1264,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
$oPdf->SetAlpha(1);
|
||||
$oPdf->SetTextColor(0, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Renders (in PDF) the key (legend) of the graphics vertically to the left of the specified zone (xmin,ymin, xmax,ymax),
|
||||
* and the comment (if any) at the bottom of the page. Returns the position of remaining area.
|
||||
@@ -1332,7 +1332,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
$yPos += $fIconSize + 2 * $fPadding;
|
||||
}
|
||||
$oPdf->Rect($xMin, $yMin, $fMaxWidth + $fIconSize + 3*$fPadding, $yMax - $yMin, 'D');
|
||||
|
||||
|
||||
if ($sComments != '')
|
||||
{
|
||||
// Draw the comment text (surrounded by a rectangle)
|
||||
@@ -1347,10 +1347,10 @@ class DisplayableGraph extends SimpleGraph
|
||||
$oPdf->Rect($xPos, $yPos, $w + 2*$fPadding, $h + 2*$fPadding, 'D');
|
||||
$yMax = $yPos - $fPadding;
|
||||
}
|
||||
|
||||
|
||||
return array('xmin' => $xMin + $fMaxWidth + $fIconSize + 4*$fPadding, 'xmax' => $xMax, 'ymin' => $yMin, 'ymax' => $yMax);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the context definitions from the parameters / configuration. The format of the "key" string is:
|
||||
* <module>/relation_context/<class>/<relation>/<direction>
|
||||
@@ -1372,7 +1372,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
else
|
||||
{
|
||||
$sLeafClass = $aLevels[2];
|
||||
|
||||
|
||||
if (!MetaModel::IsValidClass($sLeafClass))
|
||||
{
|
||||
IssueLog::Warning("GetContextDefinitions: invalid 'sLeafClass' = '$sLeafClass'. A valid class name is expected in 3rd position inside '$sContextKey' !");
|
||||
@@ -1387,7 +1387,7 @@ class DisplayableGraph extends SimpleGraph
|
||||
$aContextDefs = array_merge($aContextDefs, $aRelationContext[$sClass][$aLevels[3]][$aLevels[4]]['items']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Check if the queries are valid
|
||||
foreach($aContextDefs as $sKey => $sDefs)
|
||||
{
|
||||
@@ -1421,172 +1421,108 @@ class DisplayableGraph extends SimpleGraph
|
||||
* @param int $iObjKey
|
||||
* @param string $sContextKey
|
||||
* @param array $aContextParams
|
||||
* @param bool $bLazyLoading since 2.7.7 3.0.1
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @throws \DictExceptionMissingString
|
||||
*/
|
||||
function Display(WebPage $oP, $aResults, $sRelation, ApplicationContext $oAppContext, $aExcludedObjects, $sObjClass, $iObjKey, $sContextKey, $aContextParams = array())
|
||||
{
|
||||
$aContextDefs = static::GetContextDefinitions($sContextKey, true, $aContextParams);
|
||||
$aExcludedByClass = array();
|
||||
foreach($aExcludedObjects as $oObj)
|
||||
{
|
||||
if (!array_key_exists(get_class($oObj), $aExcludedByClass))
|
||||
{
|
||||
$aExcludedByClass[get_class($oObj)] = array();
|
||||
}
|
||||
$aExcludedByClass[get_class($oObj)][] = $oObj->GetKey();
|
||||
}
|
||||
$sSftShort = Dict::S('UI:ElementsDisplayed');
|
||||
$sSearchToggle = Dict::S('UI:Search:Toggle');
|
||||
$oP->add("<div class=\"not-printable\">\n");
|
||||
$oUiSearchBlock = new Panel($sSftShort, [],Panel::ENUM_COLOR_SCHEME_CYAN, 'ds_flash');
|
||||
$oUiSearchBlock->SetCSSClasses(["ibo-search-form-panel", "display_block"]);
|
||||
$oUiSearchBlock->SetIsCollapsible(true);
|
||||
$oUiHtmlBlock = new Combodo\iTop\Application\UI\Base\Component\Html\Html(
|
||||
<<<EOF
|
||||
<div id="ds_flash" class="search_box ibo-display-graph--search-box">
|
||||
<div id="dh_flash_criterion_outer" class="sf_criterion_area"><div class="sf_criterion_row">
|
||||
EOF
|
||||
);
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$("#dh_flash > .sf_title").on('click', function() {
|
||||
$("#dh_flash").toggleClass('closed');
|
||||
});
|
||||
$('#ReloadMovieBtn').button().button('disable');
|
||||
EOF
|
||||
);
|
||||
$aSortedElements = array();
|
||||
foreach($aResults as $sClassIdx => $aObjects)
|
||||
{
|
||||
foreach($aObjects as $oCurrObj)
|
||||
{
|
||||
$sSubClass = get_class($oCurrObj);
|
||||
$aSortedElements[$sSubClass] = MetaModel::GetName($sSubClass);
|
||||
}
|
||||
}
|
||||
|
||||
asort($aSortedElements);
|
||||
$idx = 0;
|
||||
foreach($aSortedElements as $sSubClass => $sClassName)
|
||||
{
|
||||
$oUiHtmlBlock->AddHtml("<div><input type=\"checkbox\" id=\"exclude_$idx\" name=\"excluded[]\" value=\"$sSubClass\" checked onChange=\"$('#ReloadMovieBtn').button('enable')\"><label for=\"exclude_$idx\">");
|
||||
$oUiMedallionBlock= new MedallionIcon(MetaModel::GetClassIcon($sSubClass, false));
|
||||
$oUiMedallionBlock->SetDescription($sClassName);
|
||||
$oUiHtmlBlock->AddHtml(BlockRenderer::RenderBlockTemplates($oUiMedallionBlock));
|
||||
$oUiHtmlBlock->AddHtml("</label></div>");
|
||||
$idx++;
|
||||
}
|
||||
$oUiHtmlBlock->AddHtml("</div>");
|
||||
$oUiHtmlBlock->AddHtml("<button type=\"button\" id=\"ReloadMovieBtn\" class=\"ibo-button ibo-is-neutral ibo-is-regular\" onClick=\"DoReload()\">".Dict::S('UI:Button:Refresh')."</button></div></form>");
|
||||
$oUiHtmlBlock->AddHtml("</div>\n");
|
||||
$oUiHtmlBlock->AddHtml("</div>\n"); // class="not-printable"
|
||||
function Display(WebPage $oP, $aResults, $sRelation, ApplicationContext $oAppContext, $aExcludedObjects, $sObjClass, $iObjKey, $sContextKey, $aContextParams = array(), bool $bLazyLoading = false)
|
||||
{
|
||||
list($aExcludedByClass, $aAdditionalContexts) = $this->DisplayFiltering($sContextKey, $aContextParams, $aExcludedObjects, $oP, $aResults, $bLazyLoading);
|
||||
|
||||
$oUiSearchBlock->AddSubBlock($oUiHtmlBlock);
|
||||
$oP->AddUiBlock($oUiSearchBlock);
|
||||
$aAdditionalContexts = array();
|
||||
foreach($aContextDefs as $sKey => $aDefinition)
|
||||
{
|
||||
$aAdditionalContexts[] = array('key' => $sKey, 'label' => Dict::S($aDefinition['dict']), 'oql' => $aDefinition['oql'], 'default' => (array_key_exists('default', $aDefinition) && ($aDefinition['default'] == 'yes')));
|
||||
}
|
||||
|
||||
$sDirection = utils::ReadParam('d', 'horizontal');
|
||||
$iGroupingThreshold = utils::ReadParam('g', 5);
|
||||
|
||||
WebResourcesHelper::EnableSimpleGraphInWebPage($oP);
|
||||
try
|
||||
{
|
||||
try {
|
||||
$this->InitFromGraphviz();
|
||||
$sExportAsPdfURL = '';
|
||||
$sExportAsPdfURL = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=relation_pdf&relation='.$sRelation.'&direction='.($this->bDirectionDown ? 'down' : 'up');
|
||||
$oAppcontext = new ApplicationContext();
|
||||
$sContext = $oAppContext->GetForLink();
|
||||
$sDrillDownURL = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=details&class=%1$s&id=%2$s&'.$sContext;
|
||||
$sExportAsDocumentURL = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=relation_attachment&relation='.$sRelation.'&direction='.($this->bDirectionDown ? 'down' : 'up');
|
||||
$sLoadFromURL = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=relation_json&relation='.$sRelation.'&direction='.($this->bDirectionDown ? 'down' : 'up');
|
||||
$sAttachmentExportTitle = '';
|
||||
if (($sObjClass != null) && ($iObjKey != null))
|
||||
{
|
||||
if (($sObjClass != null) && ($iObjKey != null)) {
|
||||
$oTargetObj = MetaModel::GetObject($sObjClass, $iObjKey, false);
|
||||
if ($oTargetObj)
|
||||
{
|
||||
if ($oTargetObj) {
|
||||
$sAttachmentExportTitle = Dict::Format('UI:Relation:AttachmentExportOptions_Name', $oTargetObj->GetName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$sId = 'graph';
|
||||
$sStyle = '';
|
||||
if ($oP->IsPrintableVersion())
|
||||
{
|
||||
if ($oP->IsPrintableVersion()) {
|
||||
// Optimize for printing on A4/Letter vertically
|
||||
$sStyle = 'margin-left:auto; margin-right:auto;';
|
||||
$oP->add_ready_script("$('.simple-graph').width(18/2.54*96).resizable({ stop: function() { $(window).trigger('resized'); }});"); // Default width about 18 cm, since most browsers assume 96 dpi
|
||||
}
|
||||
$oP->add('<div id="'.$sId.'" class="simple-graph" style="'.$sStyle.'"></div>');
|
||||
$aParams = array(
|
||||
'source_url' => $sLoadFromURL,
|
||||
'sources' => ($this->bDirectionDown ? $this->aSourceObjects : $this->aSinkObjects),
|
||||
'excluded' => $aExcludedByClass,
|
||||
'grouping_threshold' => $iGroupingThreshold,
|
||||
'export_as_pdf' => array('url' => $sExportAsPdfURL, 'label' => Dict::S('UI:Relation:ExportAsPDF')),
|
||||
'source_url' => $sLoadFromURL,
|
||||
'sources' => ($this->bDirectionDown ? $this->aSourceObjects : $this->aSinkObjects),
|
||||
'excluded' => $aExcludedByClass,
|
||||
'grouping_threshold' => $iGroupingThreshold,
|
||||
'export_as_pdf' => array('url' => $sExportAsPdfURL, 'label' => Dict::S('UI:Relation:ExportAsPDF')),
|
||||
'export_as_attachment' => array('url' => $sExportAsDocumentURL, 'label' => Dict::S('UI:Relation:ExportAsAttachment'), 'obj_class' => $sObjClass, 'obj_key' => $iObjKey),
|
||||
'drill_down' => array('url' => $sDrillDownURL, 'label' => Dict::S('UI:Relation:DrillDown')),
|
||||
'labels' => array(
|
||||
'export_pdf_title' => Dict::S('UI:Relation:PDFExportOptions'),
|
||||
'drill_down' => array('url' => $sDrillDownURL, 'label' => Dict::S('UI:Relation:DrillDown')),
|
||||
'labels' => array(
|
||||
'export_pdf_title' => Dict::S('UI:Relation:PDFExportOptions'),
|
||||
'export_as_attachment_title' => $sAttachmentExportTitle,
|
||||
'export' => Dict::S('UI:Button:Export'),
|
||||
'cancel' => Dict::S('UI:Button:Cancel'),
|
||||
'title' => Dict::S('UI:RelationOption:Title'),
|
||||
'untitled' => Dict::S('UI:RelationOption:Untitled'),
|
||||
'include_list' => Dict::S('UI:RelationOption:IncludeList'),
|
||||
'comments' => Dict::S('UI:RelationOption:Comments'),
|
||||
'grouping_threshold' => Dict::S('UI:RelationOption:GroupingThreshold'),
|
||||
'refresh' => Dict::S('UI:Button:Refresh'),
|
||||
'check_all' => Dict::S('UI:SearchValue:CheckAll'),
|
||||
'uncheck_all' => Dict::S('UI:SearchValue:UncheckAll'),
|
||||
'none_selected' => Dict::S('UI:Relation:NoneSelected'),
|
||||
'nb_selected' => Dict::S('UI:SearchValue:NbSelected'),
|
||||
'additional_context_info' => Dict::S('UI:Relation:AdditionalContextInfo'),
|
||||
'zoom' => Dict::S('UI:Relation:Zoom'),
|
||||
'loading' => Dict::S('UI:Loading'),
|
||||
'export' => Dict::S('UI:Button:Export'),
|
||||
'cancel' => Dict::S('UI:Button:Cancel'),
|
||||
'title' => Dict::S('UI:RelationOption:Title'),
|
||||
'untitled' => Dict::S('UI:RelationOption:Untitled'),
|
||||
'include_list' => Dict::S('UI:RelationOption:IncludeList'),
|
||||
'comments' => Dict::S('UI:RelationOption:Comments'),
|
||||
'grouping_threshold' => Dict::S('UI:RelationOption:GroupingThreshold'),
|
||||
'refresh' => Dict::S('UI:Button:Refresh'),
|
||||
'check_all' => Dict::S('UI:SearchValue:CheckAll'),
|
||||
'uncheck_all' => Dict::S('UI:SearchValue:UncheckAll'),
|
||||
'none_selected' => Dict::S('UI:Relation:NoneSelected'),
|
||||
'nb_selected' => Dict::S('UI:SearchValue:NbSelected'),
|
||||
'additional_context_info' => Dict::S('UI:Relation:AdditionalContextInfo'),
|
||||
'zoom' => Dict::S('UI:Relation:Zoom'),
|
||||
'loading' => Dict::S('UI:Loading'),
|
||||
),
|
||||
'page_format' => array(
|
||||
'label' => Dict::S('UI:Relation:PDFExportPageFormat'),
|
||||
'page_format' => array(
|
||||
'label' => Dict::S('UI:Relation:PDFExportPageFormat'),
|
||||
'values' => array(
|
||||
'A3' => Dict::S('UI:PageFormat_A3'),
|
||||
'A4' => Dict::S('UI:PageFormat_A4'),
|
||||
'A3' => Dict::S('UI:PageFormat_A3'),
|
||||
'A4' => Dict::S('UI:PageFormat_A4'),
|
||||
'Letter' => Dict::S('UI:PageFormat_Letter'),
|
||||
),
|
||||
),
|
||||
'page_orientation' => array(
|
||||
'label' => Dict::S('UI:Relation:PDFExportPageOrientation'),
|
||||
'page_orientation' => array(
|
||||
'label' => Dict::S('UI:Relation:PDFExportPageOrientation'),
|
||||
'values' => array(
|
||||
'P' => Dict::S('UI:PageOrientation_Portrait'),
|
||||
'L' => Dict::S('UI:PageOrientation_Landscape'),
|
||||
),
|
||||
),
|
||||
'additional_contexts' => $aAdditionalContexts,
|
||||
'context_key' => $sContextKey,
|
||||
'additional_contexts' => $aAdditionalContexts,
|
||||
'context_key' => $sContextKey,
|
||||
);
|
||||
if (!extension_loaded('gd'))
|
||||
{
|
||||
if (!extension_loaded('gd')) {
|
||||
// PDF export requires GD
|
||||
unset($aParams['export_as_pdf']);
|
||||
}
|
||||
if (!extension_loaded('gd') || is_null($sObjClass) || is_null($iObjKey))
|
||||
{
|
||||
if (!extension_loaded('gd') || is_null($sObjClass) || is_null($iObjKey)) {
|
||||
// Export as Attachment requires GD (for building the PDF) AND a valid objclass/objkey couple
|
||||
unset($aParams['export_as_attachment']);
|
||||
}
|
||||
$oP->add_ready_script("$('#$sId').simple_graph(".json_encode($aParams).");");
|
||||
if ($oP->IsPrintableVersion() || !$bLazyLoading) {
|
||||
$oP->add_ready_script(" $('#$sId').simple_graph(".json_encode($aParams).");");
|
||||
} else {
|
||||
$oP->add_script("function Load(){var aExcluded = []; $('input[name^=excluded]').each( function() {if (!$(this).prop('checked')) { aExcluded.push($(this).val()); }} ); var params= $.extend(".json_encode($aParams).", {excluded_classes: aExcluded}); $('#$sId').simple_graph(params);}");
|
||||
$oP->add_ready_script("$('#impacted_objects_lists').html('".utils::TextToHtml(Dict::S('Relation:impacts/NoFilteredData'))."');$('#impacted_groups').html('".utils::TextToHtml(Dict::S('Relation:impacts/NoFilteredData'))."');");
|
||||
|
||||
}
|
||||
}
|
||||
catch(Exception $e)
|
||||
{
|
||||
$oP->add('<div>'.$e->getMessage().'</div>');
|
||||
}
|
||||
$oP->add_script(
|
||||
<<<EOF
|
||||
<<<EOF
|
||||
|
||||
function DoReload()
|
||||
{
|
||||
@@ -1611,5 +1547,96 @@ EOF
|
||||
EOF
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param string $sContextKey
|
||||
* @param array $aContextParams
|
||||
* @param array $aExcludedObjects
|
||||
* @param \WebPage $oP
|
||||
* @param array $aResults
|
||||
* @param bool $bLazyLoading
|
||||
*
|
||||
* @return array
|
||||
* @throws \CoreException
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \ReflectionException
|
||||
* @throws \Twig\Error\LoaderError
|
||||
* @throws \Twig\Error\RuntimeError
|
||||
* @throws \Twig\Error\SyntaxError
|
||||
*/
|
||||
public function DisplayFiltering(string $sContextKey, array $aContextParams, array $aExcludedObjects, WebPage $oP, array $aResults, bool $bLazyLoading = false): array
|
||||
{
|
||||
$aContextDefs = static::GetContextDefinitions($sContextKey, true, $aContextParams);
|
||||
$aExcludedByClass = array();
|
||||
foreach ($aExcludedObjects as $oObj) {
|
||||
if (!array_key_exists(get_class($oObj), $aExcludedByClass)) {
|
||||
$aExcludedByClass[get_class($oObj)] = array();
|
||||
}
|
||||
$aExcludedByClass[get_class($oObj)][] = $oObj->GetKey();
|
||||
}
|
||||
$sSftShort = Dict::S('UI:ElementsDisplayed');
|
||||
$oP->add("<div class=\"not-printable\">\n");
|
||||
$oUiSearchBlock = new Panel($sSftShort, [], Panel::ENUM_COLOR_SCHEME_CYAN, 'dh_flash');
|
||||
$oUiSearchBlock->SetCSSClasses(["ibo-search-form-panel", "display_block"]);
|
||||
$oUiSearchBlock->SetIsCollapsible(true);
|
||||
$oUiHtmlBlock = new Combodo\iTop\Application\UI\Base\Component\Html\Html(
|
||||
<<<EOF
|
||||
|
||||
<div id="ds_flash" class="search_box ibo-display-graph--search-box">
|
||||
<div id="dh_flash_criterion_outer" class="sf_criterion_area"><div class="sf_criterion_row">
|
||||
EOF
|
||||
);
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$("#dh_flash > .sf_title").on("click", function() {
|
||||
$("#dh_flash").toggleClass("closed");
|
||||
});
|
||||
$("#ReloadMovieBtn").button().button("disable");
|
||||
EOF
|
||||
);
|
||||
if ($bLazyLoading) {
|
||||
$oP->add_ready_script("$('#ReloadMovieBtn').button('enable');");
|
||||
} else {
|
||||
$oP->add_ready_script("$('#dh_flash').addClass('closed');");
|
||||
}
|
||||
$aSortedElements = array();
|
||||
foreach ($aResults as $sClassIdx => $aObjects) {
|
||||
foreach ($aObjects as $oCurrObj) {
|
||||
$sSubClass = get_class($oCurrObj);
|
||||
$aSortedElements[$sSubClass] = MetaModel::GetName($sSubClass);
|
||||
}
|
||||
}
|
||||
|
||||
asort($aSortedElements);
|
||||
$idx = 0;
|
||||
foreach ($aSortedElements as $sSubClass => $sClassName) {
|
||||
$oUiHtmlBlock->AddHtml("<div><input type=\"checkbox\" id=\"exclude_$idx\" name=\"excluded[]\" value=\"$sSubClass\" checked onChange=\"$('#ReloadMovieBtn').button('enable')\"><label for=\"exclude_$idx\">");
|
||||
$oUiMedallionBlock = new MedallionIcon(MetaModel::GetClassIcon($sSubClass, false));
|
||||
$oUiMedallionBlock->SetDescription($sClassName);
|
||||
$oUiHtmlBlock->AddHtml(BlockRenderer::RenderBlockTemplates($oUiMedallionBlock));
|
||||
$oUiHtmlBlock->AddHtml("</label></div>");
|
||||
$idx++;
|
||||
}
|
||||
$oUiHtmlBlock->AddHtml("</div>");
|
||||
if ($bLazyLoading) {
|
||||
$sOnCLick = "Load(); $('#ReloadMovieBtn').attr('onclick','DoReload()');$('#ReloadMovieBtn').html('".Dict::S('UI:Button:Refresh')."');";
|
||||
$oUiHtmlBlock->AddHtml("<button type=\"button\" id=\"ReloadMovieBtn\" class=\"ibo-button ibo-is-neutral ibo-is-regular\" onClick=\"$sOnCLick\">".Dict::S('Relation:impacts/LoadData')."</button></div></form>");
|
||||
} else {
|
||||
$sOnCLick = "DoReload()";
|
||||
$oUiHtmlBlock->AddHtml("<button type=\"button\" id=\"ReloadMovieBtn\" class=\"ibo-button ibo-is-neutral ibo-is-regular\" onClick=\"$sOnCLick\">".Dict::S('UI:Button:Refresh')."</button></div></form>");
|
||||
}
|
||||
$oUiHtmlBlock->AddHtml("</div>\n");
|
||||
$oUiHtmlBlock->AddHtml("</div>\n"); // class="not-printable"
|
||||
|
||||
$oUiSearchBlock->AddSubBlock($oUiHtmlBlock);
|
||||
$oP->AddUiBlock($oUiSearchBlock);
|
||||
|
||||
$aAdditionalContexts = array();
|
||||
foreach ($aContextDefs as $sKey => $aDefinition) {
|
||||
$aAdditionalContexts[] = array('key' => $sKey, 'label' => Dict::S($aDefinition['dict']), 'oql' => $aDefinition['oql'], 'default' => (array_key_exists('default', $aDefinition) && ($aDefinition['default'] == 'yes')));
|
||||
}
|
||||
|
||||
return array($aExcludedByClass, $aAdditionalContexts);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -325,20 +325,33 @@ class EMail
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
||||
public function SetReferences($sReferences)
|
||||
{
|
||||
$this->AddToHeader('References', $sReferences);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the "In-Reply-To" header to allow emails to group as a conversation in modern mail clients (GMail, Outlook 2016+, ...)
|
||||
*
|
||||
* @link https://en.wikipedia.org/wiki/Email#Header_fields
|
||||
*
|
||||
* @param string $sMessageId
|
||||
*
|
||||
* @since 3.0.1 N°4849
|
||||
*/
|
||||
public function SetInReplyTo(string $sMessageId)
|
||||
{
|
||||
$this->AddToHeader('In-Reply-To', $sMessageId);
|
||||
}
|
||||
|
||||
public function SetBody($sBody, $sMimeType = 'text/html', $sCustomStyles = null)
|
||||
{
|
||||
if (($sMimeType === 'text/html') && ($sCustomStyles !== null))
|
||||
{
|
||||
if (($sMimeType === 'text/html') && ($sCustomStyles !== null)) {
|
||||
$oDomDocument = CssInliner::fromHtml($sBody)->inlineCss($sCustomStyles)->getDomDocument();
|
||||
HtmlPruner::fromDomDocument($oDomDocument)->removeElementsWithDisplayNone();
|
||||
$sBody = CssToAttributeConverter::fromDomDocument($oDomDocument)->convertCssToVisualAttributes()->render(); // Adds html/body tags if not already present
|
||||
|
||||
@@ -111,16 +111,15 @@ class ExcelBulkExport extends TabularBulkExport
|
||||
|
||||
$sFormatInput = '<input type="text" size="15" name="date_format" id="excel_custom_date_time_format" title="" value="'.htmlentities($sDateTimeFormat, ENT_QUOTES, 'UTF-8').'"/>';
|
||||
$oRadioCustom = InputUIBlockFactory::MakeForInputWithLabel(Dict::Format('Core:BulkExport:DateTimeFormatCustom_Format', $sFormatInput), "excel_date_format_radio", "custom", "excel_date_time_format_custom", "radio");
|
||||
$oRadioCustom->SetDescription(Dict::S('UI:CSVImport:CustomDateTimeFormatTooltip'));
|
||||
$oRadioCustom->GetInput()->SetIsChecked($sDateTimeFormat !== (string)AttributeDateTime::GetFormat());
|
||||
$oRadioCustom->SetBeforeInput(false);
|
||||
$oRadioCustom->GetInput()->AddCSSClass('ibo-input-checkbox');
|
||||
$oFieldSetDate->AddSubBlock($oRadioCustom);
|
||||
|
||||
|
||||
$sJSTooltip = json_encode('<div class="date_format_tooltip">'.Dict::S('UI:CSVImport:CustomDateTimeFormatTooltip').'</div>');
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$('#excel_custom_date_time_format').tooltip({content: function() { return $sJSTooltip; } });
|
||||
$('#form_part_xlsx_options').on('preview_updated', function() { FormatDatesInPreview('excel', 'xlsx'); });
|
||||
$('#excel_date_time_format_default').on('click', function() { FormatDatesInPreview('excel', 'xlsx'); });
|
||||
$('#excel_date_time_format_custom').on('click', function() { FormatDatesInPreview('excel', 'xlsx'); });
|
||||
|
||||
@@ -362,13 +362,8 @@ class InlineImage extends DBObject
|
||||
{
|
||||
$sJS =
|
||||
<<<JS
|
||||
$('img[data-img-id]').each(function() {
|
||||
if ($(this).width() > {$iMaxWidth})
|
||||
{
|
||||
$(this).css({'max-width': '{$iMaxWidth}px', width: '', height: '', 'max-height': ''});
|
||||
}
|
||||
$(this).addClass('inline-image').attr('href', $(this).attr('src'));
|
||||
}).magnificPopup({type: 'image', closeOnContentClick: true });
|
||||
CombodoInlineImage.SetMaxWidth('{$iMaxWidth}');
|
||||
CombodoInlineImage.FixImagesWidth();
|
||||
JS
|
||||
;
|
||||
}
|
||||
|
||||
@@ -542,13 +542,32 @@ class FileLog
|
||||
*/
|
||||
class LogChannels
|
||||
{
|
||||
public const CLI = 'CLI';
|
||||
public const APC = 'apc';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.0.1 N°4849
|
||||
*/
|
||||
public const NOTIFICATIONS = 'notifications';
|
||||
|
||||
public const CLI = 'CLI';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
* @since 2.7.7 N°4558 use this new channel when logging DB transactions
|
||||
* @since 3.0.0 logs info in CMDBSource (see commit a117906f)
|
||||
*/
|
||||
public const CMDB_SOURCE = 'cmdbsource';
|
||||
|
||||
public const CONSOLE = 'console';
|
||||
public const DEADLOCK = 'DeadLock';
|
||||
public const INLINE_IMAGE = 'InlineImage';
|
||||
public const PORTAL = 'portal';
|
||||
public const CMDB_SOURCE = 'cmdbsource';
|
||||
|
||||
public const CORE = 'core';
|
||||
|
||||
public const DEADLOCK = 'DeadLock';
|
||||
|
||||
public const INLINE_IMAGE = 'InlineImage';
|
||||
|
||||
public const PORTAL = 'portal';
|
||||
}
|
||||
|
||||
|
||||
@@ -1136,7 +1155,12 @@ class DeprecatedCallsLog extends LogAPI
|
||||
*/
|
||||
public static function NotifyDeprecatedFile(?string $sAdditionalMessage = null): void
|
||||
{
|
||||
if (!static::IsLogLevelEnabled(self::LEVEL_WARNING, self::ENUM_CHANNEL_FILE)) {
|
||||
try {
|
||||
if (!static::IsLogLevelEnabled(self::LEVEL_WARNING, self::ENUM_CHANNEL_FILE)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (ConfigException $e) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -655,7 +655,7 @@ abstract class MetaModel
|
||||
* @param string $sRuleId
|
||||
*
|
||||
* @throws \CoreException
|
||||
* @since 2.6.1 N°1918 (sous les pavés, la plage) initialize in 'root_class' property the class that has the first
|
||||
* @since 2.6.1 N°1968 (sous les pavés, la plage) initialize in 'root_class' property the class that has the first
|
||||
* definition of the rule in the hierarchy
|
||||
*/
|
||||
private static function SetUniquenessRuleRootClass($sRootClass, $sRuleId)
|
||||
@@ -3001,7 +3001,32 @@ abstract class MetaModel
|
||||
|
||||
// Build the list of available extensions
|
||||
//
|
||||
$aInterfaces = array('iApplicationUIExtension', 'iPreferencesExtension', 'iApplicationObjectExtension', 'iLoginFSMExtension', 'iLoginUIExtension', 'iLogoutExtension', 'iQueryModifier', 'iOnClassInitialization', 'iPopupMenuExtension', 'iPageUIExtension', 'iPageUIBlockExtension', 'iPortalUIExtension', 'ModuleHandlerApiInterface', 'iNewsroomProvider', 'iModuleExtension');
|
||||
$aInterfaces = [
|
||||
'iApplicationUIExtension',
|
||||
'iPreferencesExtension',
|
||||
'iApplicationObjectExtension',
|
||||
'iLoginFSMExtension',
|
||||
'iLoginUIExtension',
|
||||
'iLogoutExtension',
|
||||
'iQueryModifier',
|
||||
'iOnClassInitialization',
|
||||
'iPopupMenuExtension',
|
||||
'iPageUIExtension',
|
||||
'iPageUIBlockExtension',
|
||||
'iBackofficeLinkedScriptsExtension',
|
||||
'iBackofficeEarlyScriptExtension',
|
||||
'iBackofficeScriptExtension',
|
||||
'iBackofficeInitScriptExtension',
|
||||
'iBackofficeReadyScriptExtension',
|
||||
'iBackofficeLinkedStylesheetsExtension',
|
||||
'iBackofficeStyleExtension',
|
||||
'iBackofficeDictEntriesExtension',
|
||||
'iBackofficeDictEntriesPrefixesExtension',
|
||||
'iPortalUIExtension',
|
||||
'ModuleHandlerApiInterface',
|
||||
'iNewsroomProvider',
|
||||
'iModuleExtension',
|
||||
];
|
||||
foreach($aInterfaces as $sInterface)
|
||||
{
|
||||
self::$m_aExtensionClassNames[$sInterface] = array();
|
||||
@@ -5985,7 +6010,7 @@ abstract class MetaModel
|
||||
|
||||
// Reporting views (must be created after any other table)
|
||||
//
|
||||
foreach(self::GetClasses('bizmodel') as $sClass)
|
||||
foreach(self::GetClasses() as $sClass)
|
||||
{
|
||||
$sView = self::DBGetView($sClass);
|
||||
if (CMDBSource::IsTable($sView))
|
||||
|
||||
@@ -33,6 +33,17 @@ define('CASELOG_SEPARATOR', "\n".'========== %1$s : %2$s (%3$d) ============'."\
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
class ormCaseLog {
|
||||
/**
|
||||
* @var string "plain text" format for the log
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public const ENUM_FORMAT_TEXT = 'text';
|
||||
/**
|
||||
* @var string "HTML" format for the log
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public const ENUM_FORMAT_HTML = 'html';
|
||||
|
||||
protected $m_sLog;
|
||||
protected $m_aIndex;
|
||||
protected $m_bModified;
|
||||
@@ -53,7 +64,7 @@ class ormCaseLog {
|
||||
{
|
||||
if ($bConvertToPlainText)
|
||||
{
|
||||
// Rebuild the log, but filtering any HTML markup for the all 'html' entries in the log
|
||||
// Rebuild the log, but filtering any HTML markup for the all {@see static::ENUM_FORMAT_HTML} entries in the log
|
||||
return $this->GetAsPlainText();
|
||||
}
|
||||
else
|
||||
@@ -136,14 +147,14 @@ class ormCaseLog {
|
||||
$sDate = '';
|
||||
}
|
||||
}
|
||||
$sFormat = array_key_exists('format', $this->m_aIndex[$index]) ? $this->m_aIndex[$index]['format'] : 'text';
|
||||
$sFormat = array_key_exists('format', $this->m_aIndex[$index]) ? $this->m_aIndex[$index]['format'] : static::ENUM_FORMAT_TEXT;
|
||||
switch($sFormat)
|
||||
{
|
||||
case 'text':
|
||||
case static::ENUM_FORMAT_TEXT:
|
||||
$sHtmlEntry = utils::TextToHtml($sTextEntry);
|
||||
break;
|
||||
|
||||
case 'html':
|
||||
case static::ENUM_FORMAT_HTML:
|
||||
$sHtmlEntry = $sTextEntry;
|
||||
$sTextEntry = utils::HtmlToText($sHtmlEntry);
|
||||
break;
|
||||
@@ -175,7 +186,8 @@ class ormCaseLog {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a "plain text" version of the log (equivalent to $this->m_sLog) where all the HTML markup from the 'html' entries have been removed
|
||||
* Returns a "plain text" version of the log (equivalent to $this->m_sLog) where all the HTML markup from the {@see static::ENUM_FORMAT_HTML} entries have been removed
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function GetAsPlainText()
|
||||
@@ -237,7 +249,7 @@ class ormCaseLog {
|
||||
$iPos += $aIndex[$index]['separator_length'];
|
||||
$sTextEntry = substr($this->m_sLog, $iPos, $aIndex[$index]['text_length']);
|
||||
$sCSSClass = 'caselog_entry_html';
|
||||
if (!array_key_exists('format', $aIndex[$index]) || ($aIndex[$index]['format'] == 'text'))
|
||||
if (!array_key_exists('format', $aIndex[$index]) || ($aIndex[$index]['format'] == static::ENUM_FORMAT_TEXT))
|
||||
{
|
||||
$sCSSClass = 'caselog_entry';
|
||||
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", htmlentities($sTextEntry, ENT_QUOTES, 'UTF-8'));
|
||||
@@ -320,7 +332,7 @@ class ormCaseLog {
|
||||
$iPos += $aIndex[$index]['separator_length'];
|
||||
$sTextEntry = substr($this->m_sLog, $iPos, $aIndex[$index]['text_length']);
|
||||
$sCSSClass = 'case_log_simple_html_entry_html';
|
||||
if (!array_key_exists('format', $aIndex[$index]) || ($aIndex[$index]['format'] == 'text'))
|
||||
if (!array_key_exists('format', $aIndex[$index]) || ($aIndex[$index]['format'] == static::ENUM_FORMAT_TEXT))
|
||||
{
|
||||
$sCSSClass = 'case_log_simple_html_entry';
|
||||
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", htmlentities($sTextEntry, ENT_QUOTES, 'UTF-8'));
|
||||
@@ -425,7 +437,7 @@ class ormCaseLog {
|
||||
}
|
||||
$iPos += $aIndex[$index]['separator_length'];
|
||||
$sTextEntry = substr($this->m_sLog, $iPos, $aIndex[$index]['text_length']);
|
||||
if (!array_key_exists('format', $aIndex[$index]) || ($aIndex[$index]['format'] == 'text'))
|
||||
if (!array_key_exists('format', $aIndex[$index]) || ($aIndex[$index]['format'] == static::ENUM_FORMAT_TEXT))
|
||||
{
|
||||
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", htmlentities($sTextEntry, ENT_QUOTES, 'UTF-8'));
|
||||
if (!is_null($aTransfoHandler))
|
||||
@@ -590,7 +602,7 @@ class ormCaseLog {
|
||||
'date' => time(),
|
||||
'text_length' => $iTextlength,
|
||||
'separator_length' => $iSepLength,
|
||||
'format' => 'html',
|
||||
'format' => static::ENUM_FORMAT_HTML,
|
||||
);
|
||||
$this->m_bModified = true;
|
||||
}
|
||||
@@ -644,11 +656,11 @@ class ormCaseLog {
|
||||
else
|
||||
{
|
||||
// The default is HTML
|
||||
$sFormat = 'html';
|
||||
$sFormat = static::ENUM_FORMAT_HTML;
|
||||
}
|
||||
|
||||
$sText = isset($oJson->message) ? $oJson->message : '';
|
||||
if ($sFormat == 'html')
|
||||
if ($sFormat == static::ENUM_FORMAT_HTML)
|
||||
{
|
||||
$sText = HTMLSanitizer::Sanitize($sText);
|
||||
}
|
||||
@@ -671,7 +683,7 @@ class ormCaseLog {
|
||||
$this->m_bModified = true;
|
||||
}
|
||||
|
||||
public function GetModifiedEntry($sFormat = 'text')
|
||||
public function GetModifiedEntry($sFormat = self::ENUM_FORMAT_TEXT)
|
||||
{
|
||||
$sModifiedEntry = '';
|
||||
if ($this->m_bModified)
|
||||
@@ -686,15 +698,15 @@ class ormCaseLog {
|
||||
* @param string The expected output format text|html
|
||||
* @return string
|
||||
*/
|
||||
public function GetLatestEntry($sFormat = 'text')
|
||||
public function GetLatestEntry($sFormat = self::ENUM_FORMAT_TEXT)
|
||||
{
|
||||
$sRes = '';
|
||||
$aLastEntry = end($this->m_aIndex);
|
||||
$sRaw = substr($this->m_sLog, $aLastEntry['separator_length'], $aLastEntry['text_length']);
|
||||
switch($sFormat)
|
||||
{
|
||||
case 'text':
|
||||
if ($aLastEntry['format'] == 'text')
|
||||
case static::ENUM_FORMAT_TEXT:
|
||||
if ($aLastEntry['format'] == static::ENUM_FORMAT_TEXT)
|
||||
{
|
||||
$sRes = $sRaw;
|
||||
}
|
||||
@@ -704,8 +716,8 @@ class ormCaseLog {
|
||||
}
|
||||
break;
|
||||
|
||||
case 'html':
|
||||
if ($aLastEntry['format'] == 'text')
|
||||
case static::ENUM_FORMAT_HTML:
|
||||
if ($aLastEntry['format'] == static::ENUM_FORMAT_TEXT)
|
||||
{
|
||||
$sRes = utils::TextToHtml($sRaw);
|
||||
}
|
||||
|
||||
@@ -719,70 +719,68 @@ class ormLinkSet implements iDBObjectSetIterator, Iterator, SeekableIterator
|
||||
{
|
||||
unset($this->aRemoved[$sLinkKey]);
|
||||
}
|
||||
$bIsDuplicate = true;
|
||||
break;
|
||||
$bIsDuplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if ($bIsDuplicate)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if ($bIsDuplicate) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!array_key_exists($oLink->GetKey(), $aExistingLinks))
|
||||
{
|
||||
} else {
|
||||
if (!array_key_exists($oLink->GetKey(), $aExistingLinks)) {
|
||||
$oLink->DBClone();
|
||||
}
|
||||
}
|
||||
$oLink->DBWrite();
|
||||
|
||||
$this->aPreserved[$oLink->GetKey()] = $oLink;
|
||||
$this->aOriginalObjects[$oLink->GetKey()] = $oLink;
|
||||
}
|
||||
foreach ($this->aRemoved as $iLinkId)
|
||||
{
|
||||
if (array_key_exists($iLinkId, $aExistingLinks))
|
||||
{
|
||||
$this->aAdded = [];
|
||||
|
||||
foreach ($this->aRemoved as $iLinkId) {
|
||||
if (array_key_exists($iLinkId, $aExistingLinks)) {
|
||||
$oLink = $aExistingLinks[$iLinkId];
|
||||
if ($oAttDef->IsIndirect())
|
||||
{
|
||||
if ($oAttDef->IsIndirect()) {
|
||||
$oLink->DBDelete();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$oExtKeyToRemote = MetaModel::GetAttributeDef($this->sClass, $sExtKeyToMe);
|
||||
if ($oExtKeyToRemote->IsNullAllowed())
|
||||
{
|
||||
if ($oLink->Get($sExtKeyToMe) == $oHostObject->GetKey())
|
||||
{
|
||||
if ($oExtKeyToRemote->IsNullAllowed()) {
|
||||
if ($oLink->Get($sExtKeyToMe) == $oHostObject->GetKey()) {
|
||||
// Detach the link object from this
|
||||
$oLink->Set($sExtKeyToMe, 0);
|
||||
$oLink->DBUpdate();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$oLink->DBDelete();
|
||||
}
|
||||
}
|
||||
unset($this->aPreserved[$oLink->GetKey()], $this->aOriginalObjects[$oLink->GetKey()]);
|
||||
}
|
||||
}
|
||||
$this->aRemoved = [];
|
||||
|
||||
// Note: process modifications at the end: if a link to remove has also been listed as modified, then it will be gracefully ignored
|
||||
foreach ($this->aModified as $iLinkId => $oLink)
|
||||
{
|
||||
if (array_key_exists($oLink->GetKey(), $aExistingLinks))
|
||||
{
|
||||
foreach ($this->aModified as $iLinkId => $oLink) {
|
||||
if (array_key_exists($oLink->GetKey(), $aExistingLinks)) {
|
||||
$oLink->DBUpdate();
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
$oLink->DBClone();
|
||||
}
|
||||
$this->aPreserved[$oLink->GetKey()] = $oLink;
|
||||
$this->aOriginalObjects[$oLink->GetKey()] = $oLink;
|
||||
}
|
||||
$this->aModified = [];
|
||||
|
||||
// End of the critical section
|
||||
//
|
||||
$oMtx->Unlock();
|
||||
|
||||
// we updated the instance (original/preserved/added/modified/removed arrays) all along the way
|
||||
$this->bHasDelta = false;
|
||||
$this->oOriginalSet->GetFilter()->SetInternalParams(['id', $oHostObject->GetKey()]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -31,13 +31,13 @@ class iTopOwnershipToken extends DBObject
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
'category' => 'application',
|
||||
'key_type' => 'autoincrement',
|
||||
'name_attcode' => array('obj_class', 'obj_key'),
|
||||
'state_attcode' => '',
|
||||
'reconc_keys' => array(''),
|
||||
'db_table' => 'priv_ownership_token',
|
||||
'db_key_field' => 'id',
|
||||
'category' => '',
|
||||
'key_type' => 'autoincrement',
|
||||
'name_attcode' => array('obj_class', 'obj_key'),
|
||||
'state_attcode' => '',
|
||||
'reconc_keys' => array(''),
|
||||
'db_table' => 'priv_ownership_token',
|
||||
'db_key_field' => 'id',
|
||||
'db_finalclass_field' => '',
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
|
||||
@@ -95,15 +95,14 @@ class PDFBulkExport extends HTMLBulkExport
|
||||
|
||||
$sFormatInput = '<input type="text" size="15" name="date_format" id="pdf_custom_date_time_format" title="" value="'.htmlentities($sDateTimeFormat, ENT_QUOTES, 'UTF-8').'"/>';
|
||||
$oRadioCustom = InputUIBlockFactory::MakeForInputWithLabel(Dict::Format('Core:BulkExport:DateTimeFormatCustom_Format', $sFormatInput), "pdf_date_format_radio", "custom", "pdf_date_time_format_custom", "radio");
|
||||
$oRadioCustom->SetDescription(Dict::S('UI:CSVImport:CustomDateTimeFormatTooltip'));
|
||||
$oRadioCustom->GetInput()->SetIsChecked($sDateTimeFormat !== (string)AttributeDateTime::GetFormat());
|
||||
$oRadioCustom->SetBeforeInput(false);
|
||||
$oRadioCustom->GetInput()->AddCSSClass('ibo-input-checkbox');
|
||||
$oFieldSetDate->AddSubBlock($oRadioCustom);
|
||||
|
||||
$sJSTooltip = json_encode('<div id="date_format_tooltip">'.Dict::S('UI:CSVImport:CustomDateTimeFormatTooltip').'</div>');
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$('#pdf_custom_date_time_format').tooltip({content: function() { return $sJSTooltip; } });
|
||||
$('#form_part_pdf_options').on('preview_updated', function() { FormatDatesInPreview('pdf', 'html'); });
|
||||
$('#pdf_date_time_format_default').on('click', function() { FormatDatesInPreview('pdf', 'html'); });
|
||||
$('#pdf_date_time_format_custom').on('click', function() { FormatDatesInPreview('pdf', 'html'); });
|
||||
|
||||
@@ -84,15 +84,14 @@ class SpreadsheetBulkExport extends TabularBulkExport
|
||||
|
||||
$sFormatInput = '<input type="text" size="15" name="date_format" id="spreadsheet_custom_date_time_format" title="" value="'.htmlentities($sDateTimeFormat, ENT_QUOTES, 'UTF-8').'"/>';
|
||||
$oRadioCustom = InputUIBlockFactory::MakeForInputWithLabel(Dict::Format('Core:BulkExport:DateTimeFormatCustom_Format', $sFormatInput), "spreadsheet_date_format_radio", "custom", "spreadsheet_date_time_format_custom", "radio");
|
||||
$oRadioCustom->SetDescription(Dict::S('UI:CSVImport:CustomDateTimeFormatTooltip'));
|
||||
$oRadioCustom->GetInput()->SetIsChecked($sDateTimeFormat !== (string)AttributeDateTime::GetFormat());
|
||||
$oRadioCustom->GetInput()->AddCSSClass('ibo-input-checkbox');
|
||||
$oRadioCustom->SetBeforeInput(false);
|
||||
$oFieldSetDate->AddSubBlock($oRadioCustom);
|
||||
|
||||
$sJSTooltip = json_encode('<div class="date_format_tooltip">'.Dict::S('UI:CSVImport:CustomDateTimeFormatTooltip').'</div>');
|
||||
$oP->add_ready_script(
|
||||
<<<EOF
|
||||
$('#spreadsheet_custom_date_time_format').tooltip({content: function() { return $sJSTooltip; } });
|
||||
$('#form_part_spreadsheet_options').on('preview_updated', function() { FormatDatesInPreview('spreadsheet', 'spreadsheet'); });
|
||||
$('#spreadsheet_date_time_format_default').on('click', function() { FormatDatesInPreview('spreadsheet', 'spreadsheet'); });
|
||||
$('#spreadsheet_date_time_format_custom').on('click', function() { FormatDatesInPreview('spreadsheet', 'spreadsheet'); });
|
||||
|
||||
@@ -494,7 +494,17 @@ class SQLObjectQuery extends SQLQuery
|
||||
}
|
||||
}
|
||||
|
||||
private function PrepareSingleTable(SQLObjectQuery $oRootQuery, &$aFrom, $sCallerAlias = '', $aJoinData)
|
||||
/**
|
||||
* @param \SQLObjectQuery $oRootQuery
|
||||
* @param $aFrom
|
||||
* @param $sCallerAlias
|
||||
* @param $aJoinData
|
||||
*
|
||||
* @return string
|
||||
*
|
||||
* @since 2.7.7 3.0.1 3.1.0 N°3129 Remove default value for $sCallerAlias for PHP 8.0 compat (Private method with only 2 calls in the class, both providing the optional parameter)
|
||||
*/
|
||||
private function PrepareSingleTable(SQLObjectQuery $oRootQuery, &$aFrom, $sCallerAlias, $aJoinData)
|
||||
{
|
||||
$aTranslationTable[$this->m_sTable]['*'] = $this->m_sTableAlias;
|
||||
$sJoinCond = '';
|
||||
@@ -613,6 +623,7 @@ class SQLObjectQuery extends SQLQuery
|
||||
$aTempFrom = array(); // temporary subset of 'from' specs, to be grouped in the final query
|
||||
foreach ($this->m_aJoinSelects as $aJoinData)
|
||||
{
|
||||
/** @var \SQLObjectQuery $oRightSelect */
|
||||
$oRightSelect = $aJoinData["select"];
|
||||
|
||||
$oRightSelect->PrepareSingleTable($oRootQuery, $aTempFrom, $this->m_sTableAlias, $aJoinData);
|
||||
|
||||
@@ -42,4 +42,24 @@
|
||||
// N°2847 - Recolor svg illustrations with iTop's primary color
|
||||
.ibo-svg-illustration--container > svg *[fill="#6c63ff"]{
|
||||
fill: $ibo-svg-illustration--fill;
|
||||
}
|
||||
|
||||
// N°4481 - Restore HTML tables style identical between edition and visualization
|
||||
// This is a hack to compensate missing variables in the bulma lib, PR has been made here: https://github.com/jgthms/bulma/pull/3455
|
||||
// The following can't be reset to it's original value (from the browser stylesheet), so we have to hardcode it even though it might change in future browser versions...
|
||||
.ibo-is-html-content table {
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
tbody {
|
||||
tr {
|
||||
&:last-child {
|
||||
td,
|
||||
th {
|
||||
border-bottom-width: 1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,9 @@
|
||||
overflow-x: auto;
|
||||
|
||||
th {
|
||||
position: relative;
|
||||
padding: 5px;
|
||||
padding-right: $ibo-spacing-600;
|
||||
border-width: 1px 1px 0;
|
||||
border-style: groove groove none;
|
||||
background: $ibo-color-white-200;
|
||||
@@ -30,6 +32,14 @@
|
||||
.ibo-preview-header {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.ibo-table-preview--remove-column {
|
||||
position: absolute;
|
||||
top: $ibo-spacing-300;
|
||||
right: $ibo-spacing-300;
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
font-size: 8px;
|
||||
}
|
||||
|
||||
#form_part_interactive_fields_xlsx, #form_part_interactive_fields_csv, #form_part_interactive_fields_pdf {
|
||||
margin-top: $ibo-spacing-600;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
@import "display-block/all";
|
||||
@import "field/all";
|
||||
@import "fieldset/all";
|
||||
@import "form/all";
|
||||
@import "input/all";
|
||||
@import "panel/all";
|
||||
@import "pill/all";
|
||||
|
||||
@@ -4,4 +4,5 @@
|
||||
*/
|
||||
|
||||
@import "collapsible-section-with-blocks";
|
||||
@import "collapsible-section-within-caselog-list";
|
||||
@import "collapsible-section-within-caselog-list";
|
||||
@import "collapsible-section-within-alert";
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2022 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/* SCSS variables */
|
||||
$ibo-collapsible-section-within-alert--body--padding: $ibo-spacing-300 !default;
|
||||
$ibo-collapsible-section-within-alert--body--text-color: $ibo-color-grey-900 !default;
|
||||
|
||||
.ibo-alert--body {
|
||||
.ibo-collapsible-section {
|
||||
.ibo-collapsible-section--header .ibo-collapsible-section--title,
|
||||
.ibo-collapsible-section--body {
|
||||
@extend %ibo-font-size-150;
|
||||
}
|
||||
|
||||
.ibo-collapsible-section--body {
|
||||
color: $ibo-collapsible-section-within-alert--body--text-color;
|
||||
padding: $ibo-collapsible-section-within-alert--body--padding;
|
||||
}
|
||||
}
|
||||
> * + .ibo-collapsible-section {
|
||||
margin-top: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,4 +3,5 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@import "field-with-field";
|
||||
@import "field-with-field";
|
||||
@import "field-with-fieldset";
|
||||
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
$ibo-field--spacing-top--with-fieldset: $ibo-spacing-700 !default;
|
||||
|
||||
.ibo-fieldset + .ibo-field {
|
||||
margin-top: $ibo-field--spacing-top--with-fieldset;
|
||||
}
|
||||
@@ -3,5 +3,6 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@import "fieldset-with-field";
|
||||
@import "fieldset-with-fieldset";
|
||||
@import "fieldset-with-multicolumn";
|
||||
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
$ibo-fieldset--spacing-top--with-field: $ibo-spacing-700 !default;
|
||||
|
||||
.ibo-field + .ibo-fieldset:not(.ibo-column) {
|
||||
margin-top: $ibo-fieldset--spacing-top--with-field;
|
||||
}
|
||||
@@ -3,8 +3,8 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
$ibo-fieldset--spacing-left--with-fieldset: $ibo-spacing-800 !default;
|
||||
$ibo-fieldset--spacing-top--with-fieldset: $ibo-spacing-800 !default;
|
||||
|
||||
.ibo-fieldset + .ibo-fieldset:not(.ibo-column) {
|
||||
margin-top: $ibo-fieldset--spacing-left--with-fieldset;
|
||||
margin-top: $ibo-fieldset--spacing-top--with-fieldset;
|
||||
}
|
||||
@@ -3,9 +3,9 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
$ibo-fieldset--spacing-left--with-multicolumn: $ibo-spacing-800 !default;
|
||||
$ibo-fieldset--spacing-top--with-multicolumn: $ibo-spacing-800 !default;
|
||||
|
||||
|
||||
.ibo-multi-column + .ibo-fieldset {
|
||||
margin-top: $ibo-fieldset--spacing-left--with-multicolumn;
|
||||
margin-top: $ibo-fieldset--spacing-top--with-multicolumn;
|
||||
}
|
||||
|
||||
6
css/backoffice/blocks-integrations/form/_all.scss
Normal file
6
css/backoffice/blocks-integrations/form/_all.scss
Normal file
@@ -0,0 +1,6 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@import "form-with-form";
|
||||
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
$ibo-form--sibling-spacing: $ibo-spacing-600 !default;
|
||||
|
||||
.ibo-form + .ibo-form {
|
||||
margin-top: $ibo-form--sibling-spacing;
|
||||
}
|
||||
@@ -11,4 +11,18 @@ $ibo-input--spacing-left--with-label: $ibo-spacing-300 !default;
|
||||
select + label, label + select, label > select,
|
||||
input + label, label + input, label > input {
|
||||
margin-left: $ibo-input--spacing-left--with-label;
|
||||
}
|
||||
|
||||
.ibo-input-with-label--label {
|
||||
&.ibo-has-description {
|
||||
&::after {
|
||||
content: $ibo-field--label--description--content;
|
||||
padding-left: $ibo-field--label--description--padding-left;
|
||||
vertical-align: top;
|
||||
|
||||
cursor: pointer;
|
||||
color: $ibo-field--label--description--color;
|
||||
@extend %ibo-font-ral-bol-50;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -479,6 +479,22 @@ $ibo-button-colors: (
|
||||
&.ibo-action-button {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.ibo-button--loading-icon {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&.ibo-is-loading {
|
||||
.ibo-button--icon{
|
||||
display: none;
|
||||
}
|
||||
.ibo-button--loading-icon {
|
||||
display: inline-block;
|
||||
&+ .ibo-button--label{
|
||||
margin-left: $ibo-button--label--margin-left;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ibo-button--label {
|
||||
|
||||
@@ -120,4 +120,9 @@ $ibo-fieldsorter--selected--background-color: $ibo-color-blue-200 !default;
|
||||
background-color: $ibo-datatable--row--background-color--is-selected;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.ibo-datatable--selected-count, .ibo-datatable--result-count{
|
||||
padding-right: 0.2em;
|
||||
padding-left: 0.1em;
|
||||
}
|
||||
@@ -58,14 +58,17 @@ $ibo-field--enable-bulk--checkbox--margin-left: $ibo-spacing-300 !default;
|
||||
[data-attribute-type="AttributeQueryAttCodeSet"],
|
||||
.ibo-input-file-select--container
|
||||
) {
|
||||
/* We need the rule to apply for the class and all its descendants, hence the "& *" */
|
||||
/* We need the rule to apply for the class and all its descendants (but only in read-only), hence the "& *" */
|
||||
.ibo-field--value {
|
||||
word-break: break-word;
|
||||
white-space: inherit; /* Here we don't put break-spaces as it would put ".ibo-field-small .ibo-field-value" on a new line due to the spaces/indentation of the HTML templates. For now we rather have this rule than diminish the templates readability/maintenability */
|
||||
& * {
|
||||
& *:not(input, select, textarea) {
|
||||
word-break: break-word;
|
||||
white-space: inherit;
|
||||
}
|
||||
& pre {
|
||||
white-space: break-spaces;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,8 @@ $ibo-search-form-panel--body--padding-top: 18px !default;
|
||||
$ibo-search-form-panel--body--padding-bottom: 10px !default;
|
||||
$ibo-search-form-panel--body--padding-x: 14px !default;
|
||||
|
||||
$ibo-search-form-panel--highlight--border-radius: $ibo-panel--body--border-radius $ibo-panel--body--border-radius 0 0 !default;
|
||||
|
||||
$ibo-search-form-panel--criteria--margin-bottom: 5px !default;
|
||||
$ibo-search-form-panel--criteria--color: $ibo-color-grey-900 !default;
|
||||
$ibo-search-form-panel--criteria--background-color: $ibo-color-white-200 !default;
|
||||
@@ -24,6 +26,9 @@ $ibo-search-form-panel--items--hover--color: $ibo-color-grey-200 !default;
|
||||
|
||||
$ibo-search-form-panel--multiple-choice--hover--color: $ibo-color-grey-200 !default;
|
||||
|
||||
$ibo-search-form-panel--hint--margin-left: $ibo-spacing-300 !default;
|
||||
$ibo-search-form-panel--hint--color: $ibo-color-grey-800 !default;
|
||||
|
||||
$ibo-search-form-panel--misc-button--background-color: $ibo-search-form-panel--more-criteria--background-color !default;
|
||||
$ibo-search-form-panel--misc-button--icon--color: $ibo-search-form-panel--more-criteria--icon--color !default;
|
||||
|
||||
@@ -68,11 +73,6 @@ $ibo-search-results-area--datatable-scrollhead--border--is-sticking: $ibo-search
|
||||
display: none;
|
||||
}
|
||||
|
||||
.sft_hint,
|
||||
.sfobs_hint,
|
||||
.sft_toggler {
|
||||
margin-top: 4px;
|
||||
}
|
||||
|
||||
.sft_toggler {
|
||||
transform: rotateX(180deg);
|
||||
@@ -345,6 +345,7 @@ $ibo-search-results-area--datatable-scrollhead--border--is-sticking: $ibo-search
|
||||
/* Form group (operators) is displayed only when the criteria is toggled to opened state */
|
||||
display: none;
|
||||
max-width: 450px;
|
||||
width: max-content;
|
||||
max-height: 520px;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
@@ -374,7 +375,7 @@ $ibo-search-results-area--datatable-scrollhead--border--is-sticking: $ibo-search
|
||||
}
|
||||
|
||||
.sfc_op_name {
|
||||
width: 90px;
|
||||
width: 96px;
|
||||
}
|
||||
|
||||
.sfc_op_content {
|
||||
@@ -846,6 +847,12 @@ $ibo-search-results-area--datatable-scrollhead--border--is-sticking: $ibo-search
|
||||
}
|
||||
}
|
||||
|
||||
.sft_hint,
|
||||
.sfobs_hint,
|
||||
.sft_toggler {
|
||||
margin-left: $ibo-search-form-panel--hint--margin-left;
|
||||
color: $ibo-search-form-panel--hint--color;
|
||||
}
|
||||
|
||||
.sf_results_placeholder {
|
||||
@extend %ibo-font-size-150;
|
||||
@@ -868,6 +875,10 @@ $ibo-search-results-area--datatable-scrollhead--border--is-sticking: $ibo-search
|
||||
.ibo-panel--body {
|
||||
padding: $ibo-search-form-panel--body--padding-top $ibo-search-form-panel--body--padding-x $ibo-search-form-panel--body--padding-bottom;
|
||||
overflow: initial;
|
||||
|
||||
&::before {
|
||||
border-radius: $ibo-search-form-panel--highlight--border-radius;
|
||||
}
|
||||
}
|
||||
}
|
||||
.ibo-criterion-area{
|
||||
|
||||
@@ -8,6 +8,8 @@ $ibo-title--padding-y: $ibo-spacing-400 !default;
|
||||
$ibo-title--padding-x: $ibo-spacing-0 !default;
|
||||
|
||||
$ibo-title--icon--size: 90px !default;
|
||||
$ibo-title--icon--size-2: 80px !default;
|
||||
$ibo-title--icon--size-3: 70px !default;
|
||||
|
||||
$ibo-title--icon-background--size--must-contain: contain !default;
|
||||
$ibo-title--icon-background--size--must-cover: cover !default;
|
||||
@@ -29,6 +31,18 @@ $ibo-title--icon-background--size--must-zoomout: 66.67% !default;
|
||||
min-height: $ibo-title--icon--size;
|
||||
overflow: hidden;
|
||||
}
|
||||
.ibo-title--icon > .ibo-title--icon-level-2{
|
||||
width: $ibo-title--icon--size-2;
|
||||
height: $ibo-title--icon--size-2;
|
||||
min-width: $ibo-title--icon--size-2;
|
||||
min-height: $ibo-title--icon--size-2;
|
||||
}
|
||||
.ibo-title--icon > .ibo-title--icon-level-3{
|
||||
width: $ibo-title--icon--size-3;
|
||||
height: $ibo-title--icon--size-3;
|
||||
min-width: $ibo-title--icon--size-3;
|
||||
min-height: $ibo-title--icon--size-3;
|
||||
}
|
||||
|
||||
.ibo-title--icon-background {
|
||||
width: 100%;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
$ibo-input-image--image-view--min-height: 96px !default;
|
||||
$ibo-input-image--image-view--background-color: $ibo-color-grey-200 !default;
|
||||
$ibo-input-image--image-view--border-radius: $ibo-border-radius-500 !default;
|
||||
|
||||
@@ -18,6 +19,7 @@ $ibo-input-image--edit-buttons--elements-spacing: $ibo-input-image--edit-buttons
|
||||
.ibo-input-image--image-view {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
min-height: $ibo-input-image--image-view--min-height;
|
||||
background-color: $ibo-input-image--image-view--background-color;
|
||||
border-radius: $ibo-input-image--image-view--border-radius;
|
||||
@extend %ibo-fully-centered-content;
|
||||
|
||||
@@ -13,13 +13,16 @@ $ibo-input-select-icon--menu--icon--max-width: 45px !default;
|
||||
$ibo-input-select-icon--menu--icon--margin-right: 10px !default;
|
||||
|
||||
.ibo-input-select-icon{
|
||||
display: inline-block;
|
||||
display: inline-flex;
|
||||
text-align: left;
|
||||
>img{
|
||||
max-height: 100%;
|
||||
max-width: 100%;
|
||||
padding-right: $ibo-input-select-icon--icon--padding-right;
|
||||
}
|
||||
>span{
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.ibo-input-select-icon--menu {
|
||||
|
||||
@@ -61,8 +61,11 @@ $ibo-input-select--autocomplete-item-image--border: 1px solid $ibo-color-grey-60
|
||||
|
||||
input {
|
||||
border-width: 0px;
|
||||
border-color: white;
|
||||
color: inherit;
|
||||
border-color: $ibo-color-white-100;
|
||||
padding-left: $ibo-input-select--padding-x;
|
||||
|
||||
@extend %ibo-font-ral-nor-150;
|
||||
}
|
||||
|
||||
> [data-value] {
|
||||
@@ -101,6 +104,13 @@ $ibo-input-select--autocomplete-item-image--border: 1px solid $ibo-color-grey-60
|
||||
> input {
|
||||
background-color: unset;
|
||||
border: unset;
|
||||
&:focus{
|
||||
outline: none !important; /* Overwrite browsers default focus outline */
|
||||
}
|
||||
}
|
||||
|
||||
&.input-active{
|
||||
border: 1px solid $ibo-input--focus--border-color;
|
||||
}
|
||||
}
|
||||
.ibo-input-select-wrapper{
|
||||
|
||||
@@ -22,7 +22,6 @@ $ibo-input--placeholder--color: $ibo-color-grey-600 !default;
|
||||
$ibo-input--disabled--background-color: $ibo-color-grey-300 !default;
|
||||
$ibo-input--placeholder--color: $ibo-color-grey-700 !default;
|
||||
|
||||
$ibo-input-wrapper--is-error--background-color: $ibo-color-red-200 !default;
|
||||
$ibo-input-wrapper--is-error--border-color: $ibo-color-red-600 !default;
|
||||
$ibo-field-validation: $ibo-color-red-700 !default;
|
||||
|
||||
@@ -38,6 +37,8 @@ $ibo-input--margin-x: $ibo-spacing-200 !default;
|
||||
border: 1px solid $ibo-input--border-color;
|
||||
border-radius: $ibo-input--border-radius;
|
||||
|
||||
@extend %ibo-font-ral-nor-150;
|
||||
|
||||
&:focus{
|
||||
border: 1px solid $ibo-input--focus--border-color;
|
||||
}
|
||||
@@ -55,7 +56,6 @@ textarea.ibo-input{
|
||||
.ibo-input-wrapper.is-error, .ibo-input-field-wrapper.is-error {
|
||||
.ibo-input, .ibo-input-vanilla, .cke, textarea {
|
||||
border: 1px solid $ibo-input-wrapper--is-error--border-color;
|
||||
background-color: $ibo-input-wrapper--is-error--background-color;
|
||||
}
|
||||
.ibo-input-vanilla input{
|
||||
border: 0;
|
||||
|
||||
@@ -14,7 +14,7 @@ $ibo-navigation-menu--body--background-color: $ibo-color-blue-grey-900 !default;
|
||||
$ibo-navigation-menu--body--text-color: $ibo-color-grey-300 !default;
|
||||
|
||||
$ibo-navigation-menu--top-part--height: 120px !default;
|
||||
$ibo-navigation-menu--top-part--padding-y: $ibo-navigation-menu--body--padding-y !default;
|
||||
$ibo-navigation-menu--top-part--padding-y: $ibo-spacing-400 !default;
|
||||
$ibo-navigation-menu--top-part--padding-x: $ibo-navigation-menu--body--padding-x !default;
|
||||
$ibo-navigation-menu--top-part--elements-spacing: 20px !default;
|
||||
|
||||
@@ -70,13 +70,13 @@ $ibo-navigation-menu--square-company-logo--width: 38px !default;
|
||||
$ibo-navigation-menu--square-company-logo--height: 38px !default;
|
||||
$ibo-navigation-menu--square-company-logo--margin-top: $ibo-spacing-0 !default;
|
||||
$ibo-navigation-menu--square-company-logo--margin-x: -5px !default;
|
||||
$ibo-navigation-menu--square-company-logo--margin-bottom: $ibo-navigation-menu--body--padding-y * 2 !default;
|
||||
$ibo-navigation-menu--square-company-logo--margin-bottom: ($ibo-navigation-menu--body--padding-y * 2) + 12px !default; /* +12px to keep burger & menu groups icons align in both expanded and collapsed mode */
|
||||
|
||||
$ibo-navigation-menu--full-company-logo--width: $ibo-navigation-menu--body--width-expanded !default;
|
||||
$ibo-navigation-menu--full-company-logo--height: 70px !default;
|
||||
$ibo-navigation-menu--full-company-logo--margin-top: $ibo-spacing-0 !default;
|
||||
$ibo-navigation-menu--full-company-logo--margin-right: $ibo-spacing-0 !default;
|
||||
$ibo-navigation-menu--full-company-logo--margin-bottom: $ibo-spacing-0 !default;
|
||||
$ibo-navigation-menu--full-company-logo--margin-bottom: $ibo-spacing-400 !default;
|
||||
$ibo-navigation-menu--full-company-logo--margin-left: -$ibo-navigation-menu--body--padding-y !default;
|
||||
$ibo-navigation-menu--full-company-logo--image--margin-x: auto !default;
|
||||
$ibo-navigation-menu--full-company-logo--image--margin-y: $ibo-spacing-0 !default;
|
||||
|
||||
@@ -41,6 +41,12 @@ $ibo-activity-panel--tab-title-decoration--border-radius: $ibo-border-radius-300
|
||||
|
||||
$ibo-activity-panel--tab-title-draft-indicator--margin-x: $ibo-activity-panel--tab-title-decoration--margin-right !default;
|
||||
|
||||
$ibo-activity-panel--tab-title-messages-count--margin-left: $ibo-activity-panel--tab-title-draft-indicator--margin-x !default;
|
||||
$ibo-activity-panel--tab-title-messages-count--background-color: $ibo-color-grey-200 !default;
|
||||
$ibo-activity-panel--tab-title-messages-count--padding-x: $ibo-spacing-200 !default;
|
||||
$ibo-activity-panel--tab-title-messages-count--padding-y: $ibo-spacing-0 !default;
|
||||
$ibo-activity-panel--tab-title-messages-count--border-radius: $ibo-border-radius-300 !default;
|
||||
|
||||
$ibo-activity-panel--tab-title-text--max-width: 100px !default;
|
||||
|
||||
/* - Tab toolbar */
|
||||
@@ -180,6 +186,9 @@ $ibo-activity-panel--open-icon--margin-left: 0.75rem !default;
|
||||
.ibo-activity-panel--tab-title{
|
||||
background-color: $ibo-activity-panel--tab-title--is-active--background-color;
|
||||
}
|
||||
.ibo-activity-panel--tab-title-messages-count{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
&.ibo-is-draft{
|
||||
.ibo-activity-panel--tab-title-draft-indicator{
|
||||
@@ -213,6 +222,17 @@ $ibo-activity-panel--open-icon--margin-left: 0.75rem !default;
|
||||
border-radius: $ibo-activity-panel--tab-title-decoration--border-radius;
|
||||
@extend %ibo-depression-100;
|
||||
}
|
||||
.ibo-activity-panel--tab-title-messages-count{
|
||||
display: inline-block;
|
||||
margin-left: $ibo-activity-panel--tab-title-messages-count--margin-left;
|
||||
background-color: $ibo-activity-panel--tab-title-messages-count--background-color;
|
||||
padding: $ibo-activity-panel--tab-title-messages-count--padding-y $ibo-activity-panel--tab-title-messages-count--padding-x;
|
||||
border-radius: $ibo-activity-panel--tab-title-messages-count--border-radius;
|
||||
|
||||
&[data-messages-count="0"]{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
.ibo-activity-panel--tab-title-draft-indicator{
|
||||
display: none;
|
||||
margin-left: $ibo-activity-panel--tab-title-draft-indicator--margin-x;
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
*/
|
||||
|
||||
/* SCSS variables */
|
||||
$ibo-tab-container--hidden-tabs-on-init--display: none !default;
|
||||
|
||||
$ibo-tab-container--tabs-list--height: 36px !default;
|
||||
$ibo-tab-container--tabs-list--padding-x: $ibo-spacing-600 !default;
|
||||
$ibo-tab-container--tabs-list--background-color: $ibo-color-grey-100 !default;
|
||||
@@ -53,6 +55,12 @@ $ibo-tab-container--tab-container--min-height: auto !default;
|
||||
$ibo-tab-container--tab-container--last--min-height: 60vh !default;
|
||||
|
||||
/* Rules */
|
||||
.ibo-tab-container:not(.ibo-is-scrollable):not([data-status="loaded"]) {
|
||||
.ibo-tab-container--tab-container:not(:first-child) {
|
||||
display: $ibo-tab-container--hidden-tabs-on-init--display;
|
||||
}
|
||||
}
|
||||
|
||||
.ibo-tab-container--tabs-list {
|
||||
position: relative;
|
||||
@extend %ibo-full-height-content;
|
||||
|
||||
20
css/backoffice/pages/_about.scss
Normal file
20
css/backoffice/pages/_about.scss
Normal file
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
$ibo-about-box--top-part--children--padding-y: $ibo-spacing-500 !default;
|
||||
$ibo-about-box--top-part--children--padding-x: $ibo-spacing-400 !default;
|
||||
$ibo-about-box--top-part--children--margin-y: auto !default;
|
||||
$ibo-about-box--top-part--children--margin-x: auto !default;
|
||||
$ibo-about-box--top-part--children--width: 50% !default;
|
||||
|
||||
.ibo-about-box--top-part{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-content: center;
|
||||
> div{
|
||||
padding: $ibo-about-box--top-part--children--padding-y $ibo-about-box--top-part--children--padding-x;
|
||||
margin: $ibo-about-box--top-part--children--margin-y $ibo-about-box--top-part--children--margin-x;
|
||||
width: $ibo-about-box--top-part--children--width;
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@import "about";
|
||||
@import "base";
|
||||
@import "preferences";
|
||||
@import "attachments";
|
||||
@@ -12,4 +13,5 @@
|
||||
@import "datamodel-viewer";
|
||||
@import "csv-import";
|
||||
@import "global-search";
|
||||
@import "run-query";
|
||||
@import "welcome-popup";
|
||||
@@ -12,7 +12,7 @@ $ibo-datamodel-viewer--origin-cell--diameter: 8px !default;
|
||||
$ibo-datamodel-viewer--origin-cell--border-radius: $ibo-border-radius-full !default;
|
||||
|
||||
$ibo-datamodel-viewer--classes-list--height: 100% !default;
|
||||
$ibo-datamodel-viewer--classes-list--max-width: 350px !default;
|
||||
$ibo-datamodel-viewer--classes-list--width: 350px !default;
|
||||
$ibo-datamodel-viewer--classes-list--padding-left: $ibo-spacing-600 !default;
|
||||
|
||||
$ibo-datamodel-viewer--lifecycle--code--color: $ibo-color-grey-700 !default;
|
||||
@@ -63,7 +63,7 @@ $ibo-datamodel-viewer--lifecycle-image--margin-bottom: $ibo-spacing-500 !default
|
||||
.ibo-datamodel-viewer--classes-list{
|
||||
position: relative;
|
||||
height: $ibo-datamodel-viewer--classes-list--height;
|
||||
max-width: $ibo-datamodel-viewer--classes-list--max-width;
|
||||
width: $ibo-datamodel-viewer--classes-list--width;
|
||||
padding-left: $ibo-datamodel-viewer--classes-list--padding-left;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
10
css/backoffice/pages/_run-query.scss
Normal file
10
css/backoffice/pages/_run-query.scss
Normal file
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
$ibo-run-query--highlight--background-color: $ibo-color-primary-300 !default;
|
||||
|
||||
.ibo-run-query--highlight{
|
||||
background-color: $ibo-run-query--highlight--background-color;
|
||||
}
|
||||
@@ -134,6 +134,9 @@ body.ibo-has-fullscreen-descendant {
|
||||
@extend %ibo-font-code-150;
|
||||
}
|
||||
|
||||
.ibo-add-margin-top-250{
|
||||
margin-top: $ibo-spacing-400;
|
||||
}
|
||||
/*
|
||||
* A single class to handle WYSIWYG generated content, where only HTML tags are available
|
||||
* See https://bulma.io/documentation/elements/content/
|
||||
@@ -147,9 +150,18 @@ body.ibo-has-fullscreen-descendant {
|
||||
max-width: max-content;
|
||||
}
|
||||
|
||||
/* For table to render like in CKEditor, works with bulma lib. overload see:
|
||||
* - ../../vendors/_bulma-variables-overload.scss)
|
||||
* - ../../_shame.scss
|
||||
*/
|
||||
table {
|
||||
border-collapse: separate;
|
||||
border-spacing: 2px;
|
||||
}
|
||||
|
||||
/* Preserve original text color in code blocks, except for the Highlight.js blocks which have their own colors */
|
||||
& > code,
|
||||
:not(pre.hljs) code {
|
||||
code:not(.hljs) {
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,8 +17,15 @@ $body-overflow-y: auto !default;
|
||||
* customize Bulma content variables
|
||||
* See https://bulma.io/documentation/elements/content/
|
||||
*/
|
||||
$content-table-cell-border: 1px solid black;
|
||||
$content-table-cell-border-width: 1px;
|
||||
$content-table-head-cell-border-width: 1px;
|
||||
$content-table-foot-cell-border-width: 1px;
|
||||
$content-table-foot-cell-color: black;
|
||||
/* Table: Reset style as much as possible to match rich text editor preview, which is the browser's default stylesheet.
|
||||
* As there is no way to avoid bulma rules, we simply make them invalid by setting an invalid variable value, the rules will then be ignored by the browser.
|
||||
* See N°4481 for more information
|
||||
*/
|
||||
$content-table-cell-border: 'invalid on purpose';
|
||||
$content-table-cell-border-width: 'invalid on purpose';
|
||||
$content-table-cell-padding: 'invalid on purpose';
|
||||
$content-table-cell-heading-color: 'invalid on purpose';
|
||||
$content-table-head-cell-border-width: 'invalid on purpose';
|
||||
$content-table-head-cell-color: 'invalid on purpose';
|
||||
$content-table-foot-cell-border-width: 'invalid on purpose';
|
||||
$content-table-foot-cell-color: 'invalid on purpose';
|
||||
6
css/backoffice/vendors/_ckeditor.scss
vendored
6
css/backoffice/vendors/_ckeditor.scss
vendored
@@ -49,7 +49,11 @@ $ibo-vendors-ckeditor--autocomplete-item-title--text-color: #3A3A3A !default;
|
||||
padding: $ibo-vendors-highlightjs--padding !important;
|
||||
box-shadow: 0 0px 3px 2px inset rgba(0, 0, 0, 0.4);
|
||||
border-radius: $ibo-vendors-highlightjs--border-radius;
|
||||
white-space: pre-line;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.ibo-hljs-container{
|
||||
padding: 0 !important;
|
||||
}
|
||||
|
||||
/* Mentions in caselogs */
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
|
||||
// Beware the version number MUST be enclosed with quotes otherwise v2.3.0 becomes v2 0.3 .0
|
||||
$version: "v2.7.7";
|
||||
$approot-relative: "../../../../" !default; // relative to env-***/branding/themes/***/main.css
|
||||
|
||||
// Base colors
|
||||
|
||||
@@ -59,8 +59,8 @@ a:hover {
|
||||
padding-right: 20px;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
height: 54px;
|
||||
margin-top: 150px;
|
||||
height: 94px;
|
||||
margin-top: 110px;
|
||||
}
|
||||
|
||||
#login-content {
|
||||
@@ -75,9 +75,10 @@ a:hover {
|
||||
{
|
||||
#login-logo {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
#login-content {
|
||||
margin-top: 74px;
|
||||
margin-top: 94px;
|
||||
}
|
||||
h1 {
|
||||
margin-top: 0;
|
||||
@@ -86,7 +87,7 @@ a:hover {
|
||||
|
||||
#login-logo img {
|
||||
border: 0;
|
||||
max-height: 54px;
|
||||
max-height: 94px;
|
||||
}
|
||||
|
||||
#login-form {
|
||||
|
||||
@@ -14,34 +14,4 @@
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
*/
|
||||
body {
|
||||
display: block;
|
||||
}
|
||||
/* Landing page */
|
||||
#uwp-main-container {
|
||||
margin-top: 40px;
|
||||
}
|
||||
#uwp-main-container #uwp-logo, #uwp-main-container #uwp-title {
|
||||
vertical-align: middle;
|
||||
}
|
||||
#uwp-main-container #uwp-title {
|
||||
margin-left: 25px;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
}
|
||||
#uwp-main-container #uwp-description {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
#uwp-main-container .uwp-text-hint--icon {
|
||||
font-size: 12px;
|
||||
margin-left: 5px;
|
||||
color: #939191;
|
||||
}
|
||||
#uwp-main-container #uwp-bottom-buttons {
|
||||
margin-top: 25px;
|
||||
text-align: right;
|
||||
}
|
||||
#uwp-main-container #uwp-bottom-buttons .btn ~ .btn {
|
||||
margin-left: 8px;
|
||||
}
|
||||
*/body{display:block}#uwp-main-container{margin-top:40px}#uwp-main-container #uwp-logo,#uwp-main-container #uwp-title{vertical-align:middle;max-height:74px}#uwp-main-container #uwp-title{margin-left:25px;font-size:20px;font-weight:bold}#uwp-main-container #uwp-description{margin-bottom:25px}#uwp-main-container .uwp-text-hint--icon{font-size:12px;margin-left:5px;color:#939191}#uwp-main-container #uwp-bottom-buttons{margin-top:25px;text-align:right}#uwp-main-container #uwp-bottom-buttons .btn~.btn{margin-left:8px}
|
||||
@@ -29,6 +29,7 @@ body{
|
||||
#uwp-logo,
|
||||
#uwp-title{
|
||||
vertical-align: middle;
|
||||
max-height: 74px;
|
||||
}
|
||||
#uwp-title{
|
||||
margin-left: 25px;
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'authent-cas/3.0.0',
|
||||
'authent-cas/3.0.1',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -29,6 +29,8 @@ use utils;
|
||||
*/
|
||||
class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExtension, iLoginUIExtension
|
||||
{
|
||||
const LOGIN_MODE = 'cas';
|
||||
|
||||
/**
|
||||
* Return the list of supported login modes for this plugin
|
||||
*
|
||||
@@ -36,7 +38,7 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
*/
|
||||
public function ListSupportedLoginModes()
|
||||
{
|
||||
return array('cas');
|
||||
return array(static::LOGIN_MODE);
|
||||
}
|
||||
|
||||
protected function OnStart(&$iErrorCode)
|
||||
@@ -47,12 +49,12 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
|
||||
protected function OnReadCredentials(&$iErrorCode)
|
||||
{
|
||||
if (Session::Get('login_mode') == 'cas')
|
||||
if (empty(Session::Get('login_mode')) || Session::Get('login_mode') == static::LOGIN_MODE)
|
||||
{
|
||||
static::InitCASClient();
|
||||
if (phpCAS::isAuthenticated())
|
||||
{
|
||||
Session::Set('login_mode', 'cas');
|
||||
Session::Set('login_mode', static::LOGIN_MODE);
|
||||
Session::Set('auth_user', phpCAS::getUser());
|
||||
Session::Unset('login_will_redirect');
|
||||
}
|
||||
@@ -68,7 +70,7 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
$iErrorCode = LoginWebPage::EXIT_CODE_MISSINGLOGIN;
|
||||
return LoginWebPage::LOGIN_FSM_ERROR;
|
||||
}
|
||||
Session::Set('login_mode', 'cas');
|
||||
Session::Set('login_mode', static::LOGIN_MODE);
|
||||
phpCAS::forceAuthentication(); // Redirect to CAS and exit
|
||||
}
|
||||
}
|
||||
@@ -77,7 +79,7 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
|
||||
protected function OnCheckCredentials(&$iErrorCode)
|
||||
{
|
||||
if (Session::Get('login_mode') == 'cas')
|
||||
if (Session::Get('login_mode') == static::LOGIN_MODE)
|
||||
{
|
||||
if (!Session::IsSet('auth_user'))
|
||||
{
|
||||
@@ -94,7 +96,7 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
|
||||
protected function OnCredentialsOK(&$iErrorCode)
|
||||
{
|
||||
if (Session::Get('login_mode') == 'cas')
|
||||
if (Session::Get('login_mode') == static::LOGIN_MODE)
|
||||
{
|
||||
$sAuthUser = Session::Get('auth_user');
|
||||
if (!LoginWebPage::CheckUser($sAuthUser))
|
||||
@@ -109,7 +111,7 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
|
||||
protected function OnError(&$iErrorCode)
|
||||
{
|
||||
if (Session::Get('login_mode') == 'cas')
|
||||
if (Session::Get('login_mode') == static::LOGIN_MODE)
|
||||
{
|
||||
Session::Unset('phpCAS');
|
||||
if ($iErrorCode != LoginWebPage::EXIT_CODE_MISSINGLOGIN)
|
||||
@@ -124,7 +126,7 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
|
||||
protected function OnConnected(&$iErrorCode)
|
||||
{
|
||||
if (Session::Get('login_mode') == 'cas')
|
||||
if (Session::Get('login_mode') == static::LOGIN_MODE)
|
||||
{
|
||||
Session::Set('can_logoff', true);
|
||||
return LoginWebPage::CheckLoggedUser($iErrorCode);
|
||||
@@ -205,7 +207,7 @@ class CASLoginExtension extends AbstractLoginFSMExtension implements iLogoutExte
|
||||
$oLoginContext->SetLoaderPath(APPROOT.'env-'.utils::GetCurrentEnvironment().'/authent-cas/view');
|
||||
|
||||
$aData = array(
|
||||
'sLoginMode' => 'cas',
|
||||
'sLoginMode' => static::LOGIN_MODE,
|
||||
'sLabel' => Dict::S('CAS:Login:SignIn'),
|
||||
'sTooltip' => Dict::S('CAS:Login:SignInTooltip'),
|
||||
);
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
|
||||
* @copyright Copyright (C) 2021 Combodo SARL
|
||||
* @licence http://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
*
|
||||
*/
|
||||
Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Class:UserExternal' => 'Externer Benutzer',
|
||||
'Class:UserExternal+' => 'Externe authentifizierter '.ITOP_APPLICATION_SHORT.'-Benutzer',
|
||||
'Class:UserExternal+' => 'Extern authentifizierter '.ITOP_APPLICATION_SHORT.'-Benutzer',
|
||||
));
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'authent-external/3.0.0',
|
||||
'authent-external/3.0.1',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -9,7 +9,7 @@ if (function_exists('ldap_connect'))
|
||||
|
||||
SetupWebPage::AddModule(
|
||||
__FILE__, // Path to the current file, all other file names are relative to the directory containing this file
|
||||
'authent-ldap/3.0.0',
|
||||
'authent-ldap/3.0.1',
|
||||
array(
|
||||
// Identification
|
||||
//
|
||||
|
||||
@@ -49,10 +49,13 @@ Dict::Add('CS CZ', 'Czech', 'Čeština', array(
|
||||
'Class:UserLocal/Attribute:expiration/Value:never_expire+' => '~~',
|
||||
'Class:UserLocal/Attribute:expiration/Value:force_expire' => 'Expired~~',
|
||||
'Class:UserLocal/Attribute:expiration/Value:force_expire+' => '~~',
|
||||
'Class:UserLocal/Attribute:expiration/Value:otp_expire' => 'One-time Password~~',
|
||||
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~',
|
||||
'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewal~~',
|
||||
'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed~~',
|
||||
|
||||
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.~~',
|
||||
|
||||
'UserLocal:password:expiration' => 'The fields below require an extension~~'
|
||||
'UserLocal:password:expiration' => 'The fields below require an extension~~',
|
||||
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Setting password expiration to "One-time password" is not allowed for your own User~~',
|
||||
));
|
||||
|
||||
@@ -34,10 +34,13 @@ Dict::Add('DA DA', 'Danish', 'Dansk', array(
|
||||
'Class:UserLocal/Attribute:expiration/Value:never_expire+' => '~~',
|
||||
'Class:UserLocal/Attribute:expiration/Value:force_expire' => 'Expired~~',
|
||||
'Class:UserLocal/Attribute:expiration/Value:force_expire+' => '~~',
|
||||
'Class:UserLocal/Attribute:expiration/Value:otp_expire' => 'One-time Password~~',
|
||||
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~',
|
||||
'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewal~~',
|
||||
'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed~~',
|
||||
|
||||
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.~~',
|
||||
|
||||
'UserLocal:password:expiration' => 'The fields below require an extension~~'
|
||||
'UserLocal:password:expiration' => 'The fields below require an extension~~',
|
||||
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Setting password expiration to "One-time password" is not allowed for your own User~~',
|
||||
));
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
|
||||
* @copyright Copyright (C) 2021 Combodo SARL
|
||||
* @licence http://opensource.org/licenses/AGPL-3.0
|
||||
*
|
||||
*
|
||||
*/
|
||||
Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
'Class:UserLocal' => ITOP_APPLICATION_SHORT.'-Benutzer',
|
||||
@@ -43,5 +43,6 @@ Dict::Add('DE DE', 'German', 'Deutsch', array(
|
||||
|
||||
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Das Passwort entspricht nicht dem in den Konfigurationsregeln hinterlegten RegEx-Ausdruck',
|
||||
|
||||
'UserLocal:password:expiration' => 'Die folgenden Felder benötigen eine '.ITOP_APPLICATION_SHORT.' Erweiterung'
|
||||
'UserLocal:password:expiration' => 'Die folgenden Felder benötigen eine '.ITOP_APPLICATION_SHORT.' Erweiterung',
|
||||
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Das setzen des Passwortablaufs auf "Einmalpasswort" ist für den eigenen Benutzer nicht erlaubt.',
|
||||
));
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
/**
|
||||
/**
|
||||
* Spanish Localized data
|
||||
*
|
||||
* @copyright Copyright (C) 2010-2021 Combodo SARL
|
||||
@@ -48,10 +48,13 @@ Dict::Add('ES CR', 'Spanish', 'Español, Castellano', array(
|
||||
'Class:UserLocal/Attribute:expiration/Value:never_expire+' => '',
|
||||
'Class:UserLocal/Attribute:expiration/Value:force_expire' => 'Expirado',
|
||||
'Class:UserLocal/Attribute:expiration/Value:force_expire+' => '',
|
||||
'Class:UserLocal/Attribute:expiration/Value:otp_expire' => 'One-time Password~~',
|
||||
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~',
|
||||
'Class:UserLocal/Attribute:password_renewed_date' => 'Renovación de contraseña',
|
||||
'Class:UserLocal/Attribute:password_renewed_date+' => 'Cuando fue el último cambio de contraseña',
|
||||
|
||||
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'La contraseña debe ser de al menos 8 caracteres e incluír mayúsculas, minúsculas, números y caracteres especiales.',
|
||||
|
||||
'UserLocal:password:expiration' => 'El siguiente campo requiere una extensión'
|
||||
'UserLocal:password:expiration' => 'El siguiente campo requiere una extensión',
|
||||
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Setting password expiration to "One-time password" is not allowed for your own User~~',
|
||||
));
|
||||
|
||||
@@ -33,10 +33,13 @@ Dict::Add('HU HU', 'Hungarian', 'Magyar', array(
|
||||
'Class:UserLocal/Attribute:expiration/Value:never_expire+' => '~~',
|
||||
'Class:UserLocal/Attribute:expiration/Value:force_expire' => 'Expired~~',
|
||||
'Class:UserLocal/Attribute:expiration/Value:force_expire+' => '~~',
|
||||
'Class:UserLocal/Attribute:expiration/Value:otp_expire' => 'One-time Password~~',
|
||||
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~',
|
||||
'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewal~~',
|
||||
'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed~~',
|
||||
|
||||
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.~~',
|
||||
|
||||
'UserLocal:password:expiration' => 'The fields below require an extension~~'
|
||||
'UserLocal:password:expiration' => 'The fields below require an extension~~',
|
||||
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Setting password expiration to "One-time password" is not allowed for your own User~~',
|
||||
));
|
||||
|
||||
@@ -47,10 +47,13 @@ Dict::Add('IT IT', 'Italian', 'Italiano', array(
|
||||
'Class:UserLocal/Attribute:expiration/Value:never_expire+' => '~~',
|
||||
'Class:UserLocal/Attribute:expiration/Value:force_expire' => 'Expired~~',
|
||||
'Class:UserLocal/Attribute:expiration/Value:force_expire+' => '~~',
|
||||
'Class:UserLocal/Attribute:expiration/Value:otp_expire' => 'One-time Password~~',
|
||||
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~',
|
||||
'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewal~~',
|
||||
'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed~~',
|
||||
|
||||
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.~~',
|
||||
|
||||
'UserLocal:password:expiration' => 'The fields below require an extension~~'
|
||||
'UserLocal:password:expiration' => 'The fields below require an extension~~',
|
||||
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Setting password expiration to "One-time password" is not allowed for your own User~~',
|
||||
));
|
||||
|
||||
@@ -34,10 +34,13 @@ Dict::Add('JA JP', 'Japanese', '日本語', array(
|
||||
'Class:UserLocal/Attribute:expiration/Value:never_expire+' => '~~',
|
||||
'Class:UserLocal/Attribute:expiration/Value:force_expire' => 'Expired~~',
|
||||
'Class:UserLocal/Attribute:expiration/Value:force_expire+' => '~~',
|
||||
'Class:UserLocal/Attribute:expiration/Value:otp_expire' => 'One-time Password~~',
|
||||
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~',
|
||||
'Class:UserLocal/Attribute:password_renewed_date' => 'Password renewal~~',
|
||||
'Class:UserLocal/Attribute:password_renewed_date+' => 'When the password was last changed~~',
|
||||
|
||||
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Password must be at least 8 characters and include uppercase, lowercase, numeric and special characters.~~',
|
||||
|
||||
'UserLocal:password:expiration' => 'The fields below require an extension~~'
|
||||
'UserLocal:password:expiration' => 'The fields below require an extension~~',
|
||||
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Setting password expiration to "One-time password" is not allowed for your own User~~',
|
||||
));
|
||||
|
||||
@@ -38,10 +38,13 @@ Dict::Add('NL NL', 'Dutch', 'Nederlands', array(
|
||||
'Class:UserLocal/Attribute:expiration/Value:never_expire+' => '',
|
||||
'Class:UserLocal/Attribute:expiration/Value:force_expire' => 'Moet veranderd worden',
|
||||
'Class:UserLocal/Attribute:expiration/Value:force_expire+' => '',
|
||||
'Class:UserLocal/Attribute:expiration/Value:otp_expire' => 'One-time Password~~',
|
||||
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~',
|
||||
'Class:UserLocal/Attribute:password_renewed_date' => 'Wachtwoord laatst aangepast',
|
||||
'Class:UserLocal/Attribute:password_renewed_date+' => 'Tijdstip waarop het wachtwoord het laatst aangepast werd.',
|
||||
|
||||
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Het wachtwoord bestaat uit minstens 8 tekens en bestaat uit een mix van minstens 1 hoofdletter, kleine letter, cijfer en speciaal teken.',
|
||||
|
||||
'UserLocal:password:expiration' => 'De velden hieronder vereisen een extensie.'
|
||||
'UserLocal:password:expiration' => 'De velden hieronder vereisen een extensie.',
|
||||
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Setting password expiration to "One-time password" is not allowed for your own User~~',
|
||||
));
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
// Dictionnay conventions
|
||||
// Class:<class_name>
|
||||
// Class:<class_name>+
|
||||
@@ -30,11 +29,9 @@
|
||||
// Class:<class_name>/Attribute:<attribute_code>/Value:<value>+
|
||||
// Class:<class_name>/Stimulus:<stimulus_code>
|
||||
// Class:<class_name>/Stimulus:<stimulus_code>+
|
||||
|
||||
//
|
||||
// Class: UserLocal
|
||||
//
|
||||
|
||||
Dict::Add('PL PL', 'Polish', 'Polski', array(
|
||||
'Class:UserLocal' => 'Użytkownik '.ITOP_APPLICATION_SHORT,
|
||||
'Class:UserLocal+' => 'Użytkownik uwierzytelniony przez '.ITOP_APPLICATION_SHORT,
|
||||
@@ -49,10 +46,13 @@ Dict::Add('PL PL', 'Polish', 'Polski', array(
|
||||
'Class:UserLocal/Attribute:expiration/Value:never_expire+' => '',
|
||||
'Class:UserLocal/Attribute:expiration/Value:force_expire' => 'Wygasło',
|
||||
'Class:UserLocal/Attribute:expiration/Value:force_expire+' => '',
|
||||
'Class:UserLocal/Attribute:expiration/Value:otp_expire' => 'One-time Password~~',
|
||||
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~',
|
||||
'Class:UserLocal/Attribute:password_renewed_date' => 'Odnowienie hasła',
|
||||
'Class:UserLocal/Attribute:password_renewed_date+' => 'Kiedy ostatnio zmieniano hasło',
|
||||
|
||||
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'Hasło musi mieć co najmniej 8 znaków i zawierać duże, małe litery, cyfry i znaki specjalne.',
|
||||
|
||||
'UserLocal:password:expiration' => 'Poniższe pola wymagają rozszerzenia'
|
||||
'UserLocal:password:expiration' => 'Poniższe pola wymagają rozszerzenia',
|
||||
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Setting password expiration to "One-time password" is not allowed for your own User~~',
|
||||
));
|
||||
|
||||
@@ -33,10 +33,13 @@ Dict::Add('PT BR', 'Brazilian', 'Brazilian', array(
|
||||
'Class:UserLocal/Attribute:expiration/Value:never_expire+' => '',
|
||||
'Class:UserLocal/Attribute:expiration/Value:force_expire' => 'Expirada',
|
||||
'Class:UserLocal/Attribute:expiration/Value:force_expire+' => '',
|
||||
'Class:UserLocal/Attribute:expiration/Value:otp_expire' => 'One-time Password~~',
|
||||
'Class:UserLocal/Attribute:expiration/Value:otp_expire+' => 'Password cannot be changed by the user.~~',
|
||||
'Class:UserLocal/Attribute:password_renewed_date' => 'Renovação de senha',
|
||||
'Class:UserLocal/Attribute:password_renewed_date+' => 'Quando a senha foi trocada antiormente',
|
||||
|
||||
'Error:UserLocalPasswordValidator:UserPasswordPolicyRegex:ValidationFailed' => 'A senha deve ter no mínimo 8 caracteres e incluir letras maiúsculas, minúsculas, números e símbolos.',
|
||||
|
||||
'UserLocal:password:expiration' => 'O campo abaixo requer uma extensão'
|
||||
'UserLocal:password:expiration' => 'O campo abaixo requer uma extensão',
|
||||
'Class:UserLocal/Error:OneTimePasswordChangeIsNotAllowed' => 'Setting password expiration to "One-time password" is not allowed for your own User~~',
|
||||
));
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user