mirror of
https://github.com/Combodo/iTop.git
synced 2026-03-25 19:04:13 +01:00
Compare commits
457 Commits
feature/70
...
3.2.0-alph
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dc553ca83c | ||
|
|
14c637c7f3 | ||
|
|
3ce6c8b7cf | ||
|
|
b4cdf5cf6d | ||
|
|
77cc4672b0 | ||
|
|
331e66e594 | ||
|
|
b65e931c4c | ||
|
|
de5a9261df | ||
|
|
46b0dabb1d | ||
|
|
dfbfab7005 | ||
|
|
aa831b632c | ||
|
|
6cb3519308 | ||
|
|
cfb9fae648 | ||
|
|
f4e791734f | ||
|
|
6653ab0668 | ||
|
|
7ab258ba03 | ||
|
|
b5af30a93f | ||
|
|
dad406d208 | ||
|
|
a6d01739ba | ||
|
|
e3501447ad | ||
|
|
2294fce5da | ||
|
|
ce5c05234d | ||
|
|
bbfa601ab1 | ||
|
|
93e1f6ae03 | ||
|
|
2a9add241e | ||
|
|
c9a9ec2fed | ||
|
|
83764deedb | ||
|
|
172b1cb1ff | ||
|
|
8a4e144725 | ||
|
|
5f35effad9 | ||
|
|
e1374a0e6b | ||
|
|
ca356859a3 | ||
|
|
5efe294895 | ||
|
|
6a6dacc8ce | ||
|
|
28feddb6c9 | ||
|
|
e6fa589412 | ||
|
|
18d0b88531 | ||
|
|
3139a0b610 | ||
|
|
e0170ccc7e | ||
|
|
c24e7ef318 | ||
|
|
ffefa5495a | ||
|
|
3f773539fe | ||
|
|
a371b7f03b | ||
|
|
de97a6263f | ||
|
|
233bbebd93 | ||
|
|
f0c5264fc8 | ||
|
|
367aac3e04 | ||
|
|
3b78885f38 | ||
|
|
793f5c7cbe | ||
|
|
1d4cb6034d | ||
|
|
e6814d6860 | ||
|
|
79198f51a3 | ||
|
|
f14b4c32be | ||
|
|
6be5264fe9 | ||
|
|
6a30d6caa9 | ||
|
|
628a7319d1 | ||
|
|
bc8543d88c | ||
|
|
a51242dc36 | ||
|
|
64ba706083 | ||
|
|
ed562c9f73 | ||
|
|
85c576a986 | ||
|
|
3deb74a4d1 | ||
|
|
b9dd891aac | ||
|
|
1f2469e1e4 | ||
|
|
8fa56a6f3f | ||
|
|
22af1a8787 | ||
|
|
5e15fbec45 | ||
|
|
3a6a5ca49d | ||
|
|
3d6509e246 | ||
|
|
cd34f8b5eb | ||
|
|
8357c86361 | ||
|
|
d48b5d7d21 | ||
|
|
efe61201e5 | ||
|
|
a458d98688 | ||
|
|
a3553202d9 | ||
|
|
b10d381dda | ||
|
|
9dc7b6dc0c | ||
|
|
1be67f349f | ||
|
|
4ca92affcf | ||
|
|
3f401e4de0 | ||
|
|
9b198bc76e | ||
|
|
f7230de6d6 | ||
|
|
a4aa494e5d | ||
|
|
8647414a33 | ||
|
|
a58f0bfc0b | ||
|
|
ff1305165e | ||
|
|
d9b87064a1 | ||
|
|
a468bf8f7e | ||
|
|
65c706fdfe | ||
|
|
0853645264 | ||
|
|
e6162fe958 | ||
|
|
25f266ef66 | ||
|
|
fee07960ca | ||
|
|
5a34c76cc4 | ||
|
|
5efb1a0872 | ||
|
|
2c68f78027 | ||
|
|
7f9b60d66f | ||
|
|
816df1b551 | ||
|
|
1278c4b196 | ||
|
|
a7f3bf9a56 | ||
|
|
4eed5bdeb9 | ||
|
|
739afdb1ec | ||
|
|
75a01db959 | ||
|
|
c29bff4d91 | ||
|
|
7b999cef50 | ||
|
|
69e481dbc1 | ||
|
|
279b29a98c | ||
|
|
12b30c1531 | ||
|
|
bcfbacc625 | ||
|
|
36d6c13941 | ||
|
|
4952fc5575 | ||
|
|
7b8634e9e7 | ||
|
|
c86ebba60d | ||
|
|
db4c70cea3 | ||
|
|
e8c4c45c5c | ||
|
|
a3d5712087 | ||
|
|
5b8a3459f5 | ||
|
|
8a983ecbb7 | ||
|
|
e62473d4e9 | ||
|
|
054520cdac | ||
|
|
b38a7c8ab6 | ||
|
|
3588a50597 | ||
|
|
babdd9f163 | ||
|
|
5d8a0f8e9f | ||
|
|
52106fe48c | ||
|
|
e7a04e0e70 | ||
|
|
90458f6048 | ||
|
|
3a990f46d3 | ||
|
|
673b01585d | ||
|
|
3653a4bc90 | ||
|
|
bdfd956825 | ||
|
|
da99a250bf | ||
|
|
d57fd05552 | ||
|
|
5554241877 | ||
|
|
d9232a645d | ||
|
|
def10a9877 | ||
|
|
b29597110e | ||
|
|
c7a8d90364 | ||
|
|
86489dbbe1 | ||
|
|
6098842d9f | ||
|
|
2f30a0146e | ||
|
|
193af6c759 | ||
|
|
1de9e704fc | ||
|
|
f4b9a9a5fe | ||
|
|
561e743fc3 | ||
|
|
fa5d03fc6e | ||
|
|
7b5fa0a912 | ||
|
|
5f88391935 | ||
|
|
29300fd91e | ||
|
|
2c8b2f6c71 | ||
|
|
4cde461876 | ||
|
|
5a3bfa8043 | ||
|
|
c5544a7a1e | ||
|
|
8ffcb01c43 | ||
|
|
5c46b4ef4a | ||
|
|
912c7fa956 | ||
|
|
79cdb837b5 | ||
|
|
db2ea617d3 | ||
|
|
7499e41e40 | ||
|
|
a97935ca01 | ||
|
|
dc6ea37f23 | ||
|
|
87181669d1 | ||
|
|
efd7fb0f59 | ||
|
|
c2f72f713a | ||
|
|
700c4d0b04 | ||
|
|
43a8152de1 | ||
|
|
8c1d986a03 | ||
|
|
f3dd414a51 | ||
|
|
d1a4d333eb | ||
|
|
b934cbe89e | ||
|
|
71a0f8b87d | ||
|
|
a4edf8cb21 | ||
|
|
dbd5ba0377 | ||
|
|
5d6f293956 | ||
|
|
65e6c84477 | ||
|
|
61e04c5a73 | ||
|
|
9cc7ccb1cd | ||
|
|
a337ef3d88 | ||
|
|
27ac1fe276 | ||
|
|
986c24d777 | ||
|
|
763112c179 | ||
|
|
a5efd981d8 | ||
|
|
6450b52697 | ||
|
|
c0e4d04a1c | ||
|
|
289ca7b505 | ||
|
|
2922b22478 | ||
|
|
2af05a437e | ||
|
|
71d9536bc4 | ||
|
|
b1e1a66496 | ||
|
|
d7270c56cd | ||
|
|
7a7b7381c9 | ||
|
|
da32362ef6 | ||
|
|
5569df5950 | ||
|
|
b08b5297cf | ||
|
|
3e6e096f62 | ||
|
|
6377a738c5 | ||
|
|
a9f8dcc5e8 | ||
|
|
9470d9b9ec | ||
|
|
9750fec959 | ||
|
|
969a301cbb | ||
|
|
c325294e17 | ||
|
|
8588757da9 | ||
|
|
f894cb24c6 | ||
|
|
722765c0aa | ||
|
|
5e9b4da68c | ||
|
|
af2c6d9ab8 | ||
|
|
0176905c20 | ||
|
|
5e4f76bde9 | ||
|
|
0c3e839381 | ||
|
|
5be386d03e | ||
|
|
2ced460ec6 | ||
|
|
ae9bda8bbb | ||
|
|
9566963835 | ||
|
|
cf6e8ab22a | ||
|
|
2aa1385958 | ||
|
|
509df0939e | ||
|
|
9032dac314 | ||
|
|
a29b0a8e33 | ||
|
|
fee1897932 | ||
|
|
093a4cec75 | ||
|
|
892a7fa95f | ||
|
|
48f7ae8476 | ||
|
|
10ef277982 | ||
|
|
ebe7da7acb | ||
|
|
9fa036df7e | ||
|
|
c24c1ba73c | ||
|
|
3650cf761d | ||
|
|
34c4d753d3 | ||
|
|
4d1f8e5704 | ||
|
|
7ac283bffb | ||
|
|
c1efad7556 | ||
|
|
f78b57521a | ||
|
|
da490739be | ||
|
|
8e8d586dcc | ||
|
|
e05b4e772c | ||
|
|
02efea4e55 | ||
|
|
17bab06ff5 | ||
|
|
ab4f224a00 | ||
|
|
fe6ee083f6 | ||
|
|
655539c289 | ||
|
|
33ba754277 | ||
|
|
7948793674 | ||
|
|
8c7b33fb06 | ||
|
|
db4dfe1ba3 | ||
|
|
e00112d6e1 | ||
|
|
3404306de8 | ||
|
|
ff7e4d3db6 | ||
|
|
e371db846a | ||
|
|
5bbf3c9c35 | ||
|
|
fe4233e218 | ||
|
|
8490c2a22f | ||
|
|
e758527ca9 | ||
|
|
3e9f4df1bf | ||
|
|
f3fbce7459 | ||
|
|
ff079f7d01 | ||
|
|
d4c54b6e1c | ||
|
|
39d1ddeab8 | ||
|
|
fada9793f0 | ||
|
|
45a8e6d1c8 | ||
|
|
bf4b07a366 | ||
|
|
48de13b5cf | ||
|
|
b867faa355 | ||
|
|
1848b5f231 | ||
|
|
9fa53d43ab | ||
|
|
646e86b207 | ||
|
|
e93c9b8537 | ||
|
|
849c495093 | ||
|
|
e878938e25 | ||
|
|
7453cc184f | ||
|
|
2d5cd7042a | ||
|
|
7b01108c91 | ||
|
|
3b9ca4ad18 | ||
|
|
59129bc3ce | ||
|
|
eddc750ca8 | ||
|
|
f3abe1ff13 | ||
|
|
473cf004b6 | ||
|
|
90a5a7a9a7 | ||
|
|
5574952033 | ||
|
|
1a8de82be5 | ||
|
|
d15a0a0070 | ||
|
|
76167a3d54 | ||
|
|
46273dfc12 | ||
|
|
24f1cf8ca1 | ||
|
|
2a5337d84c | ||
|
|
fbe7f559d2 | ||
|
|
c8810708ef | ||
|
|
e8c11f38d2 | ||
|
|
1394bc221d | ||
|
|
baa05ba8d4 | ||
|
|
e7b493dafa | ||
|
|
940833a66f | ||
|
|
2b172d6e19 | ||
|
|
69677954b4 | ||
|
|
9c35cddfc0 | ||
|
|
86bf6ba0b0 | ||
|
|
82e19f6eca | ||
|
|
8f1d8b1dc2 | ||
|
|
b67057c863 | ||
|
|
0546a7b82b | ||
|
|
3d360e99da | ||
|
|
3cc3f0e4ff | ||
|
|
b6230ed486 | ||
|
|
123dfd8dd3 | ||
|
|
e9bd76f2cd | ||
|
|
47f7dfeb47 | ||
|
|
405919f204 | ||
|
|
b7f43ba22b | ||
|
|
b813a32225 | ||
|
|
b13e0c92a5 | ||
|
|
a6e5f95ff4 | ||
|
|
2e5f0b064c | ||
|
|
a9f6e86381 | ||
|
|
c6548ace61 | ||
|
|
aa81c94dad | ||
|
|
478afb88e3 | ||
|
|
7c17957ec7 | ||
|
|
ba0a585256 | ||
|
|
f41f2a063d | ||
|
|
d7e9ae1a77 | ||
|
|
dd6a138ea1 | ||
|
|
b6caa51552 | ||
|
|
8a67ceff57 | ||
|
|
095c94a917 | ||
|
|
102a4a0c75 | ||
|
|
f6fec506b1 | ||
|
|
829d82dfe3 | ||
|
|
5fdf8d7687 | ||
|
|
1ddf8b419a | ||
|
|
7d0801f74f | ||
|
|
3b9f281afd | ||
|
|
c718fcf176 | ||
|
|
bcba666483 | ||
|
|
ec465174f7 | ||
|
|
2982911df7 | ||
|
|
9f675fef02 | ||
|
|
c7cb7c0b68 | ||
|
|
68f229f91c | ||
|
|
1d106eb33a | ||
|
|
31bd763b90 | ||
|
|
5c12151c26 | ||
|
|
ceba1ad1e9 | ||
|
|
efe5f004a1 | ||
|
|
b716a3965c | ||
|
|
15fa495458 | ||
|
|
1dfb2e0a1a | ||
|
|
d775658980 | ||
|
|
2bd40bef47 | ||
|
|
961315cf34 | ||
|
|
67d43c19ec | ||
|
|
2695aeb64b | ||
|
|
95fef002a6 | ||
|
|
9777ac1a5c | ||
|
|
9e24447835 | ||
|
|
296250b20f | ||
|
|
38601bf0cf | ||
|
|
9f46aad80a | ||
|
|
ba0020fa63 | ||
|
|
1e83f2eb60 | ||
|
|
dd27a3ebb4 | ||
|
|
54439ad529 | ||
|
|
a492f7a664 | ||
|
|
85a49262e9 | ||
|
|
2c61ac4949 | ||
|
|
8f7bf00551 | ||
|
|
0483cea226 | ||
|
|
922a842e96 | ||
|
|
955d04252e | ||
|
|
95c4a93f2e | ||
|
|
e4f068a518 | ||
|
|
c020de59a7 | ||
|
|
85dac470aa | ||
|
|
3c2350961d | ||
|
|
391c78ae42 | ||
|
|
aa53de467d | ||
|
|
bc6efc99ed | ||
|
|
bb3ab76205 | ||
|
|
0b1bdfff55 | ||
|
|
77c0cdf5aa | ||
|
|
af9fb74c54 | ||
|
|
5d6c4939f6 | ||
|
|
41eb927480 | ||
|
|
5663c61e51 | ||
|
|
bec5e250a5 | ||
|
|
51d0d16a11 | ||
|
|
9fe45e9472 | ||
|
|
78133418d7 | ||
|
|
8275de8fa7 | ||
|
|
ba7c154e84 | ||
|
|
d2b0140fa4 | ||
|
|
5c4ba74237 | ||
|
|
848528567e | ||
|
|
b0634c9fbc | ||
|
|
7f4b50ca7f | ||
|
|
fabeea8dba | ||
|
|
c951a33646 | ||
|
|
e7687a0fe6 | ||
|
|
5dd5986b88 | ||
|
|
8f250e82f4 | ||
|
|
ed694b09b0 | ||
|
|
3e0ca6a70a | ||
|
|
3b08ed5f51 | ||
|
|
41dcb26283 | ||
|
|
d4879b9bd8 | ||
|
|
87856fe382 | ||
|
|
205a37a879 | ||
|
|
e830c90314 | ||
|
|
5308b49cd2 | ||
|
|
216ea34a3c | ||
|
|
0a9c5250f8 | ||
|
|
0e91c75dc2 | ||
|
|
cf996dda0b | ||
|
|
21638e6a9e | ||
|
|
272d6e9b66 | ||
|
|
87b08669d7 | ||
|
|
de86682562 | ||
|
|
25c2e34eed | ||
|
|
e92b006f70 | ||
|
|
962eb08e40 | ||
|
|
6342e0065a | ||
|
|
ac44ffcdff | ||
|
|
dfb5a4875a | ||
|
|
ddce3058be | ||
|
|
9235c395b4 | ||
|
|
e1296105f9 | ||
|
|
38cdcf4f61 | ||
|
|
5623decdb3 | ||
|
|
0f39ea8ac7 | ||
|
|
f3d3ec6ef7 | ||
|
|
fde01d5004 | ||
|
|
71d9710322 | ||
|
|
7a5ce8cd6b | ||
|
|
18deb79068 | ||
|
|
16b3e62587 | ||
|
|
6c1edadc55 | ||
|
|
8928a87b14 | ||
|
|
8eca200023 | ||
|
|
865b6d14f0 | ||
|
|
b63af9b919 | ||
|
|
4d4cdf9e60 | ||
|
|
3868d57d28 | ||
|
|
1b3a2c8470 | ||
|
|
618d8e6468 | ||
|
|
53a2a7a8e2 | ||
|
|
9a26c37ffd | ||
|
|
1e3ef6846d | ||
|
|
31225b9e23 | ||
|
|
436b6808b5 | ||
|
|
cc5e105d7f | ||
|
|
7f62bd61e3 | ||
|
|
aecc34a78b | ||
|
|
72bbc31cd9 | ||
|
|
f54d1273c9 | ||
|
|
01a955a16f | ||
|
|
ed99433448 | ||
|
|
669e6f93fa | ||
|
|
a5aac0caad | ||
|
|
31e29506fa |
Binary file not shown.
|
After Width: | Height: | Size: 4.8 MiB |
83
.github/pull_request_template.md
vendored
Normal file
83
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
<!--
|
||||
|
||||
IMPORTANT: Please follow the guidelines within this PR template before submitting it, it will greatly help us process your PR. 🙏
|
||||
|
||||
Any PRs not following the guidelines or with missing information will not be considered.
|
||||
|
||||
-->
|
||||
|
||||
## Base information
|
||||
| Question | Answer
|
||||
|---------------------------------------------------------------|--------
|
||||
| Related to a SourceForge thead / Another PR / Combodo ticket? | <!-- Put the URL -->
|
||||
| Type of change? | Bug fix / Enhancement / Translations
|
||||
|
||||
|
||||
## Symptom (bug) / Objective (enhancement)
|
||||
<!--
|
||||
If it's a bug
|
||||
- Explain the symptom in details
|
||||
- If possible put error messages, logs or screenshots (you can paste image directly in this editor).
|
||||
|
||||
If it's an enhancement
|
||||
- Describe what is blocking you, what is the objective with as much details as possible.
|
||||
- Add screenshots if it's related to UI.
|
||||
-->
|
||||
|
||||
|
||||
## Reproduction procedure (bug)
|
||||
<!--
|
||||
Remove this section only if it's NOT a bug.
|
||||
|
||||
Otherwise, explain step by step how to reproduce the issue on a standard iTop Community.
|
||||
|
||||
If it requires a custom datamodel, provide the minimal XML delta to reproduce it on a standard iTop Community.
|
||||
-->
|
||||
|
||||
1. On iTop x.y.z <!-- Put complete iTop version (eg. 3.1.0-2) -->
|
||||
2. With PHP x.y.z <!-- Put complete PHP version (eg. 8.1.24) -->
|
||||
2. First go there
|
||||
2. Then do that
|
||||
3. ...
|
||||
4. Finally, see that...
|
||||
|
||||
|
||||
## Cause (bug)
|
||||
<!--
|
||||
Remove this section only if it's NOT a bug.
|
||||
|
||||
Otherwise, explain what is the cause of the issue (where in the code and why)
|
||||
-->
|
||||
|
||||
|
||||
## Proposed solution (bug and enhancement)
|
||||
<!--
|
||||
Explain in details how you are proposing to solve this:
|
||||
- What did you do in the code and why
|
||||
- If you changed something in the UI, put before / after screenshots (you can paste image directly in this editor)
|
||||
-->
|
||||
|
||||
|
||||
## Checklist before requesting a review
|
||||
<!--
|
||||
Don't remove these lines, check them once done.
|
||||
-->
|
||||
- [ ] I have performed a self-review of my code
|
||||
- [ ] I have tested all changes I made on an iTop instance
|
||||
- [ ] I have added a unit test, otherwise I have explained why I couldn't
|
||||
- [ ] Is the PR clear and detailed enough so anyone can understand digging in the code?
|
||||
|
||||
## Checklist of things to do before PR is ready to merge
|
||||
<!--
|
||||
Things that needs to be done in the PR before it can be considered as ready to be merged
|
||||
|
||||
Examples:
|
||||
- Changes requested in the review
|
||||
- Unit test to add
|
||||
- Dictionary entries to translate
|
||||
- ...
|
||||
-->
|
||||
|
||||
- [ ] ...
|
||||
- [ ] ...
|
||||
- [ ] ...
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -47,6 +47,9 @@ tests/*/vendor/*
|
||||
!/log/index.php
|
||||
!/log/web.config
|
||||
|
||||
# NPM: `jquery-ui` package is just there for vulnerability scans, so we don't want to version its files (only `jquery-ui-dist` is used within the code base)
|
||||
/node_modules/jquery-ui/**
|
||||
|
||||
# PHPUnit: Cache file, local XML working copies
|
||||
/tests/php-unit-tests/.phpunit.result.cache
|
||||
/tests/php-unit-tests/phpunit.xml
|
||||
|
||||
@@ -4,7 +4,7 @@ $iBeginTime = time();
|
||||
chdir(__DIR__);
|
||||
|
||||
$aCommands = [
|
||||
'php composer/rmDeniedTestDir.php',
|
||||
'php composer/rmUnnecessaryFolders.php',
|
||||
'php build/commands/setupCssCompiler.php',
|
||||
// 'bash /tmp/gabuzomeu.sh',
|
||||
];
|
||||
@@ -22,13 +22,13 @@ $iElapsed = time() - $iBeginTime;
|
||||
|
||||
if (count($aFailedCommands))
|
||||
{
|
||||
fwrite(STDERR, "\nafterBuild execution failed! (in ${iElapsed}s)\n");
|
||||
fwrite(STDERR, "\nafterBuild execution failed! (in {$iElapsed}s)\n");
|
||||
fwrite(STDERR, "List of failling commands:\n - " . implode("\n - ", $aFailedCommands) . "\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
echo "\nDone (${iElapsed}s)\n";
|
||||
echo "\nDone ({$iElapsed}s)\n";
|
||||
exit(0);
|
||||
|
||||
/**
|
||||
@@ -74,7 +74,7 @@ function ExecCommand($cmd) {
|
||||
}
|
||||
else
|
||||
{
|
||||
echo "| elapsed:${iElapsed}s \n";
|
||||
echo "| elapsed:{$iElapsed}s \n";
|
||||
}
|
||||
|
||||
if (!empty($stderr))
|
||||
|
||||
@@ -1,73 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2010-2023 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with iTop. If not, see <http: *www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Composer\iTopComposer;
|
||||
|
||||
$iTopFolder = __DIR__ . "/../../" ;
|
||||
|
||||
require_once ("$iTopFolder/approot.inc.php");
|
||||
require_once (APPROOT."/setup/setuputils.class.inc.php");
|
||||
|
||||
if (php_sapi_name() !== 'cli')
|
||||
{
|
||||
throw new \Exception('This script can only run from CLI');
|
||||
}
|
||||
|
||||
clearstatcache();
|
||||
|
||||
$oiTopComposer = new iTopComposer();
|
||||
$aDeniedButStillPresent = $oiTopComposer->ListDeniedButStillPresent();
|
||||
|
||||
echo "\n";
|
||||
foreach ($aDeniedButStillPresent as $sDir)
|
||||
{
|
||||
if (false === iTopComposer::IsTestDir($sDir))
|
||||
{
|
||||
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 "OK Remove denied test dir: '$sDir'\n";
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
echo "\nFAILED to remove denied test dir: '$sDir'\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$aAllowedAndDeniedDirs = array_merge(
|
||||
$oiTopComposer->ListAllowedTestDir(),
|
||||
$oiTopComposer->ListDeniedTestDir()
|
||||
);
|
||||
$aExistingDirs = $oiTopComposer->ListAllTestDir();
|
||||
$aMissing = array_diff($aExistingDirs, $aAllowedAndDeniedDirs);
|
||||
if (false === empty($aMissing)) {
|
||||
echo "Some new tests dirs exists !\n"
|
||||
.' They must be declared either in the allowed or denied list in '.iTopComposer::class." (see N°2651).\n"
|
||||
.' List of dirs:'."\n".var_export($aMissing, true);
|
||||
}
|
||||
@@ -26,7 +26,7 @@
|
||||
* @link https://getcomposer.org/doc/03-cli.md#show
|
||||
*/
|
||||
|
||||
$iTopFolder = __DIR__."/../../";
|
||||
$iTopFolder = __DIR__."/../../../";
|
||||
|
||||
require_once("$iTopFolder/approot.inc.php");
|
||||
$sApproot = APPROOT;
|
||||
@@ -0,0 +1,56 @@
|
||||
courier.php
|
||||
courierb.php
|
||||
courierbi.php
|
||||
courieri.php
|
||||
dejavusans.ctg.z
|
||||
dejavusans.php
|
||||
dejavusans.z
|
||||
dejavusansb.ctg.z
|
||||
dejavusansb.php
|
||||
dejavusansb.z
|
||||
dejavusansbi.ctg.z
|
||||
dejavusansbi.php
|
||||
dejavusansbi.z
|
||||
dejavusanscondensed.ctg.z
|
||||
dejavusanscondensed.php
|
||||
dejavusanscondensed.z
|
||||
dejavusanscondensedb.ctg.z
|
||||
dejavusanscondensedb.php
|
||||
dejavusanscondensedb.z
|
||||
dejavusanscondensedbi.ctg.z
|
||||
dejavusanscondensedbi.php
|
||||
dejavusanscondensedbi.z
|
||||
dejavusanscondensedi.ctg.z
|
||||
dejavusanscondensedi.php
|
||||
dejavusanscondensedi.z
|
||||
dejavusansextralight.ctg.z
|
||||
dejavusansextralight.php
|
||||
dejavusansextralight.z
|
||||
dejavusansi.ctg.z
|
||||
dejavusansi.php
|
||||
dejavusansi.z
|
||||
dejavusansmono.ctg.z
|
||||
dejavusansmono.php
|
||||
dejavusansmono.z
|
||||
dejavusansmonob.ctg.z
|
||||
dejavusansmonob.php
|
||||
dejavusansmonob.z
|
||||
dejavusansmonobi.ctg.z
|
||||
dejavusansmonobi.php
|
||||
dejavusansmonobi.z
|
||||
dejavusansmonoi.ctg.z
|
||||
dejavusansmonoi.php
|
||||
dejavusansmonoi.z
|
||||
droidsansfallback.ctg.z
|
||||
droidsansfallback.php
|
||||
droidsansfallback.z
|
||||
helvetica.php
|
||||
helveticab.php
|
||||
helveticabi.php
|
||||
helveticai.php
|
||||
symbol.php
|
||||
times.php
|
||||
timesb.php
|
||||
timesbi.php
|
||||
timesi.php
|
||||
zapfdingbats.php
|
||||
101
.make/dependencies/composer/tcpdf/tcpdfUpdateFonts.php
Normal file
101
.make/dependencies/composer/tcpdf/tcpdfUpdateFonts.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
/**
|
||||
* This script will copy custom fonts in the TCPDF lib fonts directory.
|
||||
* If you need to add other files :
|
||||
* - add the corresponding files in this script directory
|
||||
* - modify this script to copy also your files
|
||||
*
|
||||
* @since 2.7.0 N°1947 add DroidSansFallback font (see also PR #49 in the links below)
|
||||
* @since 2.7.0 N°2435 TCPPDF lib forked and added in composer.json (at that time the lib was announced as deprecated and rewritten in tecnickcom/tc-lib-pdf)
|
||||
* @since 3.2.0 N°7175 switch back to TCPDF original lib (which is finally still maintained, tecnickcom/tc-lib-pdf us still under dev), script creation to keep custom DroidSansFallback font
|
||||
*
|
||||
* @link https://github.com/Combodo/iTop/pull/49 add DroidSansFallback font
|
||||
* @link https://github.com/tecnickcom/TCPDF?tab=readme-ov-file#note TCPDF is in support only mode
|
||||
*/
|
||||
|
||||
$sItopRootFolder = realpath(__DIR__ . "/../../../../");
|
||||
$sCurrentScriptFileName = basename(__FILE__);
|
||||
|
||||
|
||||
require_once ("$sItopRootFolder/lib/autoload.php");
|
||||
|
||||
|
||||
$sTcPdfRootFolder = $sItopRootFolder.'/lib/tecnickcom/tcpdf';
|
||||
if (false === file_exists($sTcPdfRootFolder)) {
|
||||
echo $sCurrentScriptFileName.": No TCPDF lib detected, exiting !\n";
|
||||
return;
|
||||
}
|
||||
$sTcPdfFontsFolder = $sTcPdfRootFolder.'/Fonts/';
|
||||
|
||||
|
||||
/**
|
||||
* 1) Cleaning up the fonts directory to keep only the ones we want in iTop
|
||||
*/
|
||||
echo $sCurrentScriptFileName.": ---1) Cleaning up the fonts files\n";
|
||||
$aTcpdfDefaultFontsToKeepInItop = file(__DIR__.'/tcpdfDefaultFontsToKeepInItop.txt', FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||
|
||||
$aTcpdfFontsDirContent = scandir($sTcPdfFontsFolder);
|
||||
foreach ($aTcpdfFontsDirContent as $sTcpdfFontResourceName) {
|
||||
if ($sTcpdfFontResourceName === '.') {
|
||||
continue;
|
||||
}
|
||||
if ($sTcpdfFontResourceName === '..') {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!in_array($sTcpdfFontResourceName, $aTcpdfDefaultFontsToKeepInItop, true)) {
|
||||
echo $sCurrentScriptFileName.": Removing $sTcpdfFontResourceName !\n";
|
||||
|
||||
$sTcpdfFontResourceFullPath = $sTcPdfFontsFolder.$sTcpdfFontResourceName;
|
||||
if (is_file($sTcpdfFontResourceFullPath)) {
|
||||
unlink($sTcpdfFontResourceFullPath);
|
||||
} elseif (is_dir($sTcpdfFontResourceFullPath)) {
|
||||
rrmdir($sTcpdfFontResourceFullPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 2) Then adding the DroidSansFallback font (useful for CJK data for example)
|
||||
*/
|
||||
echo $sCurrentScriptFileName.": ---2) Copying font files to TCPDF ($sTcPdfFontsFolder)...\n";
|
||||
$aFontFilesToCopy = glob(__DIR__.'\droidsansfallback.*');
|
||||
foreach ($aFontFilesToCopy as $sFontFileToCopy) {
|
||||
$sFontFileName = basename($sFontFileToCopy);
|
||||
echo $sCurrentScriptFileName.': copying '.$sFontFileName."\n";
|
||||
copy($sFontFileToCopy, $sTcPdfFontsFolder.$sFontFileName);
|
||||
}
|
||||
echo $sCurrentScriptFileName.": Done !\n";
|
||||
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------------------------------------*/
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Recursively delete a directory and its content
|
||||
*
|
||||
* @param $sDirToRemovePath
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function rrmdir($sDirToRemovePath):void
|
||||
{
|
||||
if (is_dir($sDirToRemovePath)) {
|
||||
$objects = scandir($sDirToRemovePath);
|
||||
foreach ($objects as $object) {
|
||||
if ($object != "." && $object != "..") {
|
||||
if (filetype($sDirToRemovePath."/".$object) == "dir") {
|
||||
rrmdir($sDirToRemovePath."/".$object);
|
||||
} else {
|
||||
unlink($sDirToRemovePath."/".$object);
|
||||
}
|
||||
}
|
||||
}
|
||||
reset($objects);
|
||||
rmdir($sDirToRemovePath);
|
||||
}
|
||||
}
|
||||
51
.make/dependencies/npm/restoreFolderBrowsingProtection.php
Normal file
51
.make/dependencies/npm/restoreFolderBrowsingProtection.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2010-2023 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with iTop. If not, see <http: *www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Ensure that the files for folder browsing protection (.htaccess, web.config) are kept after an "npm install/update" command
|
||||
*/
|
||||
|
||||
$iTopFolder = __DIR__."/../../../";
|
||||
|
||||
require_once("$iTopFolder/approot.inc.php");
|
||||
|
||||
$sDependenciesRootFolderAbsPath = APPROOT . "node_modules/";
|
||||
$aFilesToCheck = [
|
||||
".htaccess",
|
||||
"web.config",
|
||||
];
|
||||
|
||||
echo "This command aims at ensuring that folder browsing protection files (.htaccess, web.config) are present in the dependencies folder even after an install/upgrade command\n";
|
||||
echo "Checking files:\n";
|
||||
|
||||
foreach($aFilesToCheck as $sFileToCheck) {
|
||||
if (file_exists($sDependenciesRootFolderAbsPath . $sFileToCheck)) {
|
||||
echo "✔️ $sFileToCheck is present\n";
|
||||
continue;
|
||||
}
|
||||
|
||||
// If missing, copy the one from /lib as it contains the necessary allow/deny directives for third-parties
|
||||
copy(APPROOT . "lib/$sFileToCheck", $sDependenciesRootFolderAbsPath . $sFileToCheck);
|
||||
echo "✔️ $sFileToCheck was missing and has been re-created\n";
|
||||
}
|
||||
|
||||
// Ensure separation with following scripts
|
||||
echo "\n";
|
||||
95
.make/dependencies/rmUnnecessaryFolders.php
Normal file
95
.make/dependencies/rmUnnecessaryFolders.php
Normal file
@@ -0,0 +1,95 @@
|
||||
<?php
|
||||
/**
|
||||
* Copyright (C) 2010-2023 Combodo SARL
|
||||
*
|
||||
* This file is part of iTop.
|
||||
*
|
||||
* iTop is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* iTop is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with iTop. If not, see <http: *www.gnu.org/licenses/>
|
||||
*
|
||||
*/
|
||||
|
||||
$iTopFolder = __DIR__ . "/../../" ;
|
||||
|
||||
require_once ("$iTopFolder/approot.inc.php");
|
||||
require_once (APPROOT."/setup/setuputils.class.inc.php");
|
||||
|
||||
if (php_sapi_name() !== 'cli')
|
||||
{
|
||||
throw new \Exception('This script can only run from CLI');
|
||||
}
|
||||
|
||||
clearstatcache();
|
||||
|
||||
// Read params
|
||||
$key = array_search("--manager", $argv);
|
||||
if (false === $key || false === isset($argv[$key + 1]) ) {
|
||||
throw new \InvalidArgumentException("Usage: " . __FILE__ . " --manager composer|npm");
|
||||
}
|
||||
$sDependenciesHandlerCode = $argv[$key + 1];
|
||||
|
||||
switch ($sDependenciesHandlerCode) {
|
||||
case "composer":
|
||||
$sDependenciesHandlerFQCN = \Combodo\iTop\Dependencies\Composer\iTopComposer::class;
|
||||
break;
|
||||
|
||||
case "npm":
|
||||
$sDependenciesHandlerFQCN = \Combodo\iTop\Dependencies\NPM\iTopNPM::class;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new \Exception("Invalid dependencies handler code, $sDependenciesHandlerCode given, expected composer|npm");
|
||||
}
|
||||
|
||||
// Start handler
|
||||
$oDependenciesHandler = new $sDependenciesHandlerFQCN();
|
||||
$aDeniedButStillPresent = $oDependenciesHandler->ListDeniedButStillPresentFoldersAbsPaths();
|
||||
|
||||
echo "\n";
|
||||
foreach ($aDeniedButStillPresent as $sDir)
|
||||
{
|
||||
if (false === $oDependenciesHandler::IsQuestionnableFolder($sDir))
|
||||
{
|
||||
echo "ERROR found INVALID denied test dir: '$sDir'\n";
|
||||
throw new \RuntimeException("$sDir is in the denied list but doesn't comply with the rule (see IsQuestionnableFolder method)");
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
catch (\Exception $e) {
|
||||
echo "\n❌ FAILED to remove denied test dir: '$sDir'\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$aAllowedAndDeniedDirs = array_merge(
|
||||
$oDependenciesHandler->ListAllowedFoldersAbsPaths(),
|
||||
$oDependenciesHandler->ListDeniedFoldersAbsPaths()
|
||||
);
|
||||
$aExistingDirs = $oDependenciesHandler->ListAllFoldersAbsPaths();
|
||||
$aMissing = array_diff($aExistingDirs, $aAllowedAndDeniedDirs);
|
||||
if (false === empty($aMissing)) {
|
||||
echo "Some new tests dirs exists !\n"
|
||||
." They must be declared either in the allowed or denied list in {$sDependenciesHandlerFQCN}\n"
|
||||
.' List of dirs:'."\n".var_export($aMissing, true)."\n";
|
||||
}
|
||||
|
||||
// Ensure separation with following scripts
|
||||
echo "\n";
|
||||
@@ -159,6 +159,6 @@ We have one sticker per contribution type. You might get multiple stickers with
|
||||
* Beta tester: Test and give feedback on beta releases
|
||||
* Extension developer: Develop and publish an extension
|
||||
|
||||
Here is the design of each stickers for year 2022:
|
||||
Here is the design of each stickers for year 2024:
|
||||
|
||||

|
||||

|
||||
|
||||
@@ -1274,8 +1274,6 @@ abstract class AbstractPageUIExtension implements iPageUIExtension
|
||||
*/
|
||||
public function GetNorthPaneHtml(iTopWebPage $oPage)
|
||||
{
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use iPageUIBlockExtension instead');
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -1284,8 +1282,6 @@ abstract class AbstractPageUIExtension implements iPageUIExtension
|
||||
*/
|
||||
public function GetSouthPaneHtml(iTopWebPage $oPage)
|
||||
{
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use iPageUIBlockExtension instead');
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -1294,8 +1290,6 @@ abstract class AbstractPageUIExtension implements iPageUIExtension
|
||||
*/
|
||||
public function GetBannerHtml(iTopWebPage $oPage)
|
||||
{
|
||||
DeprecatedCallsLog::NotifyDeprecatedPhpMethod('use iPageUIBlockExtension instead');
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -2105,8 +2099,16 @@ class RestUtils
|
||||
elseif (is_string($key))
|
||||
{
|
||||
// OQL
|
||||
$oSearch = DBObjectSearch::FromOQL($key);
|
||||
}
|
||||
try {
|
||||
$oSearch = DBObjectSearch::FromOQL($key);
|
||||
} catch (Exception $e) {
|
||||
throw new CoreOqlException('Query failed to execute', [
|
||||
'query' => $key,
|
||||
'exception_class' => get_class($e),
|
||||
'exception_message' => $e->getMessage(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Wrong format for key");
|
||||
@@ -2279,4 +2281,19 @@ interface iKPILoggerExtension
|
||||
* @return mixed
|
||||
*/
|
||||
public function LogOperation($oKpiLogData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement this interface to add files to the backup
|
||||
*
|
||||
* @api
|
||||
* @since 3.2.0
|
||||
*/
|
||||
interface iBackupExtraFilesExtension
|
||||
{
|
||||
/**
|
||||
* @api
|
||||
* @return string[] Array of relative paths (from app root) for files and directories to be included in the backup
|
||||
*/
|
||||
public function GetExtraFilesRelPaths(): array;
|
||||
}
|
||||
|
||||
@@ -86,7 +86,7 @@ class lnkAuditCategoryToAuditDomain extends cmdbAbstractObject
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "application, grant_by_profile",
|
||||
"category" => "application,grant_by_profile",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "",
|
||||
"state_attcode" => "",
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
use Combodo\iTop\Application\Helper\CKEditorHelper;
|
||||
use Combodo\iTop\Application\Helper\FormHelper;
|
||||
use Combodo\iTop\Application\Helper\Session;
|
||||
use Combodo\iTop\Application\Helper\WebResourcesHelper;
|
||||
@@ -137,6 +138,8 @@ abstract class cmdbAbstractObject extends CMDBObject implements iDisplay
|
||||
/** @var string */
|
||||
public const ENUM_INPUT_TYPE_TAGSET = 'tagset';
|
||||
/** @var string */
|
||||
public const ENUM_INPUT_TYPE_TAGSET_LINKEDSET = 'tagset_linkedset';
|
||||
/** @var string */
|
||||
public const ENUM_INPUT_TYPE_RADIO = 'radio';
|
||||
/** @var string */
|
||||
public const ENUM_INPUT_TYPE_CHECKBOX = 'checkbox';
|
||||
@@ -2321,14 +2324,14 @@ JS
|
||||
// To change the default settings of the editor,
|
||||
// a) edit the file /js/ckeditor/config.js
|
||||
// b) or override some of the configuration settings, using the second parameter of ckeditor()
|
||||
$aConfig = utils::GetCkeditorPref();
|
||||
$aConfig = CKEditorHelper::GetCkeditorPref();
|
||||
$aConfig['placeholder'] = Dict::S('UI:CaseLogTypeYourTextHere');
|
||||
|
||||
// - Final config
|
||||
$sConfigJS = json_encode($aConfig);
|
||||
|
||||
WebResourcesHelper::EnableCKEditorToWebPage($oPage);
|
||||
$oPage->add_ready_script("$('#$iId').ckeditor(function() { /* callback code */ }, $sConfigJS);"); // Transform $iId into a CKEdit
|
||||
$oPage->add_ready_script("CombodoCKEditorHandler.CreateInstance('#$iId')");
|
||||
|
||||
$oPage->add_ready_script(
|
||||
<<<EOF
|
||||
@@ -2362,6 +2365,7 @@ EOF
|
||||
|
||||
case 'LinkedSet':
|
||||
if ($oAttDef->GetDisplayStyle() === LINKSET_DISPLAY_STYLE_PROPERTY) {
|
||||
$sInputType = self::ENUM_INPUT_TYPE_TAGSET_LINKEDSET;
|
||||
if (array_key_exists('bulk_context', $aArgs)) {
|
||||
$oTagSetBlock = LinkSetUIBlockFactory::MakeForBulkLinkSet($iId, $oAttDef, $value, $sWizardHelperJsVarName, $aArgs['bulk_context']);
|
||||
} else {
|
||||
@@ -2426,7 +2430,7 @@ HTML;
|
||||
$sInputType = self::ENUM_INPUT_TYPE_IMAGE;
|
||||
$aEventsList[] = 'validate';
|
||||
$aEventsList[] = 'change';
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/edit_image.js');
|
||||
$oPage->LinkScriptFromAppRoot('js/edit_image.js');
|
||||
$oDocument = $value; // Value is an ormDocument objectm
|
||||
$sDefaultUrl = $oAttDef->Get('default_image');
|
||||
if (is_object($oDocument) && !$oDocument->IsEmpty()) {
|
||||
@@ -2542,11 +2546,11 @@ HTML;
|
||||
$sHTMLValue .= '</div></div>';
|
||||
$sHTMLValue .= '<div>'.$sReloadSpan.'</div>'; // No validation span for this one: it does handle its own validation!
|
||||
$sHTMLValue .= "<input name=\"attr_{$sFieldPrefix}{$sAttCode}{$sNameSuffix}\" type=\"hidden\" id=\"$iId\" value=\"\"/>\n";
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/form_handler.js');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/console_form_handler.js');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/field_set.js');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/form_field.js');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/subform_field.js');
|
||||
$oPage->LinkScriptFromAppRoot('js/form_handler.js');
|
||||
$oPage->LinkScriptFromAppRoot('js/console_form_handler.js');
|
||||
$oPage->LinkScriptFromAppRoot('js/field_set.js');
|
||||
$oPage->LinkScriptFromAppRoot('js/form_field.js');
|
||||
$oPage->LinkScriptFromAppRoot('js/subform_field.js');
|
||||
$oPage->add_ready_script(
|
||||
<<<JS
|
||||
$('#{$iId}_field_set').field_set($sFieldSetOptions);
|
||||
@@ -2572,9 +2576,9 @@ JS
|
||||
case 'Set':
|
||||
case 'TagSet':
|
||||
$sInputType = self::ENUM_INPUT_TYPE_TAGSET;
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/selectize.min.js');
|
||||
$oPage->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/selectize.default.css');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.itop-set-widget.js');
|
||||
$oPage->LinkScriptFromAppRoot('js/selectize.min.js');
|
||||
$oPage->LinkStylesheetFromAppRoot('css/selectize.default.css');
|
||||
$oPage->LinkScriptFromAppRoot('js/jquery.itop-set-widget.js');
|
||||
|
||||
$oPage->add_dict_entry('Core:AttributeSet:placeholder');
|
||||
|
||||
@@ -3449,7 +3453,7 @@ EOF
|
||||
// Dummy collapsible section created in order to get JS files
|
||||
$oCollapsibleSection = new CollapsibleSection('');
|
||||
foreach ($oCollapsibleSection->GetJsFilesUrlRecursively(true) as $sJSFile) {
|
||||
$oPage->add_linked_script($sJSFile);
|
||||
$oPage->LinkScriptFromURI($sJSFile);
|
||||
}
|
||||
}
|
||||
$aAllowedValues = MetaModel::GetAllowedValues_att($sClass, $sAttCode, $aArgs);
|
||||
@@ -3589,16 +3593,26 @@ EOF
|
||||
$oPage->add_ready_script(InlineImage::EnableCKEditorImageUpload($this, $sTempId));
|
||||
} else {
|
||||
//we can directly apply the stimuli
|
||||
$sExceptionMessage = null;
|
||||
try {
|
||||
$bApplyStimulus = $this->ApplyStimulus($sStimulus); // will write the object in the DB
|
||||
if (!$bApplyStimulus) {
|
||||
throw new ApplicationException(Dict::S('UI:FailedToApplyStimuli'));
|
||||
} else {
|
||||
}
|
||||
catch (Exception $oException) {
|
||||
// Catch any exception happening during the stimulus
|
||||
$bApplyStimulus = false;
|
||||
$sExceptionMessage = ($oException instanceof CoreCannotSaveObjectException) ? $oException->getHtmlMessage() : $oException->getMessage();
|
||||
}
|
||||
finally {
|
||||
if ($sOwnershipToken !== null) {
|
||||
// Release the concurrent lock, if any
|
||||
iTopOwnershipLock::ReleaseLock($sClass, $iKey, $sOwnershipToken);
|
||||
}
|
||||
|
||||
return true;
|
||||
if (!$bApplyStimulus) {
|
||||
// Throw an application oriented exception if necessary
|
||||
throw new ApplicationException($sExceptionMessage ?? Dict::S('UI:FailedToApplyStimuli'));
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -480,7 +480,7 @@ abstract class Dashboard
|
||||
CombodoTooltip.InitTooltipFromMarkup($("#attr_auto_reload_sec"));
|
||||
$("#attr_auto_reload_sec").prop('disabled', !$('#attr_auto_reload').is(':checked'));
|
||||
|
||||
$('#attr_auto_reload').change( function(ev) {
|
||||
$('#attr_auto_reload').on('change', function(ev) {
|
||||
$("#attr_auto_reload_sec").prop('disabled', !$(this).is(':checked'));
|
||||
} );
|
||||
|
||||
@@ -563,8 +563,8 @@ JS
|
||||
}
|
||||
|
||||
if (!$bEditMode) {
|
||||
$oPage->add_linked_script('../js/dashlet.js');
|
||||
$oPage->add_linked_script('../js/dashboard.js');
|
||||
$oPage->LinkScriptFromAppRoot('js/dashlet.js');
|
||||
$oPage->LinkScriptFromAppRoot('js/dashboard.js');
|
||||
}
|
||||
|
||||
return $oDashboard;
|
||||
@@ -1118,8 +1118,8 @@ JS
|
||||
*/
|
||||
protected function RenderEditionTools(WebPage $oPage, DashboardLayoutUIBlock $oDashboard, $aExtraParams)
|
||||
{
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.iframe-transport.js');
|
||||
$oPage->add_linked_script(utils::GetAbsoluteUrlAppRoot().'js/jquery.fileupload.js');
|
||||
$oPage->LinkScriptFromAppRoot('node_modules/blueimp-file-upload/js/jquery.iframe-transport.js');
|
||||
$oPage->LinkScriptFromAppRoot('node_modules/blueimp-file-upload/js/jquery.fileupload.js');
|
||||
$sId = utils::Sanitize($this->GetId(), '', 'element_identifier');
|
||||
|
||||
$sMenuTogglerId = "ibo-dashboard-menu-toggler-{$sId}";
|
||||
@@ -1272,6 +1272,7 @@ EOF
|
||||
$sAutoReloadSec = (string) $this->iAutoReloadSec;
|
||||
$sTitle = utils::HtmlEntities($this->sTitle);
|
||||
$sFile = utils::HtmlEntities($this->GetDefinitionFile());
|
||||
$sFileForJS = json_encode($this->GetDefinitionFile());
|
||||
$sUrl = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php';
|
||||
$sReloadURL = $this->GetReloadURL();
|
||||
|
||||
@@ -1333,9 +1334,9 @@ $('#dashboard_editor .ui-layout-center').runtimedashboard({
|
||||
auto_reload: $sAutoReload,
|
||||
auto_reload_sec: $sAutoReloadSec,
|
||||
submit_to: '$sUrl',
|
||||
submit_parameters: {operation: 'save_dashboard', file: '$sFile', extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
|
||||
submit_parameters: {operation: 'save_dashboard', file: {$sFileForJS}, extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
|
||||
render_to: '$sUrl',
|
||||
render_parameters: {operation: 'render_dashboard', file: '$sFile', extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
|
||||
render_parameters: {operation: 'render_dashboard', file: {$sFileForJS}, extra_params: $sJSExtraParams, reload_url: '$sReloadURL'},
|
||||
new_dashlet_parameters: {operation: 'new_dashlet'}
|
||||
});
|
||||
|
||||
|
||||
@@ -187,7 +187,9 @@
|
||||
</menus>
|
||||
<events>
|
||||
<event id="EVENT_DB_BEFORE_WRITE" _delta="define">
|
||||
<description>An object is about to be written into the database. The object can be modified.</description>
|
||||
<name>Before create or update</name>
|
||||
<description><![CDATA[An object is about to be written into the database.
|
||||
The object can be modified.]]></description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
@@ -208,7 +210,9 @@
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_DB_CHECK_TO_WRITE" _delta="define">
|
||||
<description>Check an object before it is written into the database (no change possible). Call DBObject::AddCheckIssue() to signal an issue</description>
|
||||
<name>Check to write</name>
|
||||
<description><![CDATA[Check an object before it is written into the database (no change possible).
|
||||
Call $this->AddCheckIssue() to signal an issue.]]></description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
@@ -229,7 +233,9 @@
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_DB_AFTER_WRITE" _delta="define">
|
||||
<description>An object has been written into the database. The modifications can be propagated to other objects.</description>
|
||||
<name>After create or update</name>
|
||||
<description><![CDATA[An object has been written into the database.
|
||||
The modifications can be propagated to other objects.]]></description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
@@ -244,7 +250,7 @@
|
||||
<type>boolean</type>
|
||||
</event_datum>
|
||||
<event_datum id="changes">
|
||||
<description>For updates, the list of changes done during this operation</description>
|
||||
<description><![CDATA[For updates, the list of changes done during this operation]]></description>
|
||||
<type>array</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
@@ -254,7 +260,9 @@
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_DB_CHECK_TO_DELETE" _delta="define">
|
||||
<description>Check an object before it is deleted from the database. Call DBObject::AddDeleteIssue() to signal an issue</description>
|
||||
<name>Check to delete</name>
|
||||
<description><![CDATA[Check an object before it is deleted from the database.
|
||||
Call $this->AddDeleteIssue() to signal an issue.]]></description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
@@ -271,7 +279,8 @@
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_DB_ABOUT_TO_DELETE" _delta="define">
|
||||
<description>An object is about to be deleted from the database</description>
|
||||
<name>Before delete</name>
|
||||
<description><![CDATA[An object is about to be deleted from the database]]></description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
@@ -288,7 +297,8 @@
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_DB_AFTER_DELETE" _delta="define">
|
||||
<description>An object has been deleted into the database</description>
|
||||
<name>After delete</name>
|
||||
<description><![CDATA[An object has been deleted into the database]]></description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
@@ -304,8 +314,10 @@
|
||||
</event_datum>
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_DB_BEFORE_APPLY_STIMULUS" _delta="define">
|
||||
<description>A stimulus is about to be applied to an object</description>
|
||||
<event id="EVENT_ENUM_TRANSITIONS" _delta="define">
|
||||
<name>Enum transitions</name>
|
||||
<description><![CDATA[Manage the allowed transitions in current object state.
|
||||
The only action allowed is to deny transitions with $this->DenyTransition()]]></description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
@@ -314,89 +326,9 @@
|
||||
<description>The object where the stimulus is targeted</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="stimulus">
|
||||
<description>Current stimulus applied</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="previous_state">
|
||||
<description>Object previous state</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="new_state">
|
||||
<description>Object new state</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="save_object">
|
||||
<description>The object must be saved in the database</description>
|
||||
<type>boolean</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_DB_AFTER_APPLY_STIMULUS" _delta="define">
|
||||
<description>A stimulus has been applied to an object</description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
<event_data>
|
||||
<event_datum id="object">
|
||||
<description>The object where the stimulus is targeted</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="stimulus">
|
||||
<description>Current stimulus applied</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="previous_state">
|
||||
<description>Object previous state</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="new_state">
|
||||
<description>Object new state</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="save_object">
|
||||
<description>The object is asked to be saved in the database</description>
|
||||
<type>boolean</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_DB_APPLY_STIMULUS_FAILED" _delta="define">
|
||||
<description>A stimulus has failed</description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
<event_data>
|
||||
<event_datum id="action">
|
||||
<description>The action that failed to apply the stimulus</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="object">
|
||||
<description>The object where the stimulus is targeted</description>
|
||||
<type>DBObject</type>
|
||||
</event_datum>
|
||||
<event_datum id="stimulus">
|
||||
<description>Current stimulus applied</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="previous_state">
|
||||
<description>Object previous state</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="new_state">
|
||||
<description>Object new state</description>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="save_object">
|
||||
<description>The object must be saved in the database</description>
|
||||
<type>boolean</type>
|
||||
<event_datum id="allowed_stimuli">
|
||||
<description>The list of available stimuli in the current state</description>
|
||||
<type>array</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
@@ -405,7 +337,8 @@
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_DB_LINKS_CHANGED" _delta="define">
|
||||
<description>At least one link class was changed</description>
|
||||
<name>Links on object have changed</name>
|
||||
<description><![CDATA[At least one link class was changed]]></description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
@@ -421,7 +354,9 @@
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_DB_OBJECT_RELOAD" _delta="define">
|
||||
<description>An object has been re-loaded from the database</description>
|
||||
<name>Object reload</name>
|
||||
<internal>true</internal>
|
||||
<description><![CDATA[An object has been re-loaded from the database]]></description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
@@ -437,7 +372,8 @@
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_DB_COMPUTE_VALUES" _delta="define">
|
||||
<description>An object needs to be recomputed after changes</description>
|
||||
<name>Recompute object values</name>
|
||||
<description><![CDATA[An object needs to be recomputed after changes]]></description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
@@ -454,7 +390,8 @@
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_DB_ARCHIVE" _delta="define">
|
||||
<description>An object has been archived</description>
|
||||
<name>Object archived</name>
|
||||
<description><![CDATA[An object has been archived]]></description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
@@ -470,7 +407,8 @@
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_DB_UNARCHIVE" _delta="define">
|
||||
<description>An object has been unarchived</description>
|
||||
<name>Object unarchived</name>
|
||||
<description><![CDATA[An object has been unarchived]]></description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
@@ -486,7 +424,9 @@
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_DB_SET_ATTRIBUTES_FLAGS" _delta="define">
|
||||
<description>Set object attributes flags. Call cmdbAbstractObject::AddAttributeFlags() for all the attributes to be set for this target state.</description>
|
||||
<name>Set attributes flags</name>
|
||||
<description><![CDATA[Set object attributes flags.
|
||||
Call $this->AddAttributeFlags() for all the attributes to be set for this target state.]]></description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
@@ -497,7 +437,7 @@
|
||||
</event_datum>
|
||||
<event_datum id="target_state">
|
||||
<description>The target state in which to evaluate the flags</description>
|
||||
<type>array</type>
|
||||
<type>string</type>
|
||||
</event_datum>
|
||||
<event_datum id="debug_info">
|
||||
<description>Debug string</description>
|
||||
@@ -506,7 +446,9 @@
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_DB_SET_INITIAL_ATTRIBUTES_FLAGS" _delta="define">
|
||||
<description>Set object initial attributes flags. Call cmdbAbstractObject::AddInitialAttributeFlags() for all the initial attributes to be set initially.</description>
|
||||
<name>Set initial attributes flags</name>
|
||||
<description><![CDATA[Set object initial attributes flags.
|
||||
Call $this->AddInitialAttributeFlags() for all the initial attributes to be set initially.]]></description>
|
||||
<sources>
|
||||
<source id="cmdbAbstractObject">cmdbAbstractObject</source>
|
||||
</sources>
|
||||
@@ -522,7 +464,8 @@
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_DOWNLOAD_DOCUMENT" _delta="define">
|
||||
<description>A document has been downloaded from the GUI</description>
|
||||
<name>Document downloaded</name>
|
||||
<description><![CDATA[A document has been downloaded from the GUI]]></description>
|
||||
<sources>
|
||||
<source id="Document">Document</source>
|
||||
</sources>
|
||||
@@ -550,7 +493,9 @@
|
||||
</event_data>
|
||||
</event>
|
||||
<event id="EVENT_LOGIN" _delta="define">
|
||||
<description>Inform the listeners about the connection states</description>
|
||||
<name>Login</name>
|
||||
<internal>true</internal>
|
||||
<description><![CDATA[Inform the listeners about the connection states]]></description>
|
||||
<event_data>
|
||||
<event_datum id="code">
|
||||
<description>The login step result code (LoginWebPage::EXIT_CODE_...) </description>
|
||||
|
||||
@@ -326,6 +326,7 @@ class DataTable
|
||||
$sPagesLinks = implode('', $aPagesToDisplay);
|
||||
$sPagesList = '['.implode(',', array_keys($aPagesToDisplay)).']';
|
||||
|
||||
$sAppRootUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
$sSelectionMode = ($iNbPages == 1) ? '' : 'positive';
|
||||
$sHtml =
|
||||
<<<EOF
|
||||
@@ -333,11 +334,11 @@ class DataTable
|
||||
<div $sPagerStyle>
|
||||
<table id="pager{$this->iListId}" class="pager"><tr>
|
||||
<td>$sPages</td>
|
||||
<td><img src="../images/first.png" class="first"/></td>
|
||||
<td><img src="../images/prev.png" class="prev"/></td>
|
||||
<td><img src="{$sAppRootUrl}images/first.png" class="first"/>AAAA</td>
|
||||
<td><img src="{$sAppRootUrl}images/prev.png" class="prev"/></td>
|
||||
<td><span id="index">$sPagesLinks</span></td>
|
||||
<td><img src="../images/next.png" class="next"/></td>
|
||||
<td><img src="../images/last.png" class="last"/></td>
|
||||
<td><img src="{$sAppRootUrl}images/next.png" class="next"/></td>
|
||||
<td><img src="{$sAppRootUrl}images/last.png" class="last"/></td>
|
||||
<td>$sPageSizeCombo</td>
|
||||
<td><span id="loading"> </span><input type="hidden" name="selectionMode" value="$sSelectionMode"></input>
|
||||
</td>
|
||||
|
||||
@@ -570,7 +570,7 @@ class DisplayBlock
|
||||
} else {
|
||||
// render it as an Ajax (asynchronous) call
|
||||
$oHtml->AddCSSClass("loading");
|
||||
$oHtml->AddHtml("<p><img src=\"../images/indicator_arrows.gif\"> ".Dict::S('UI:Loading').'</p>');
|
||||
$oHtml->AddHtml("<p><img src=\"".utils::GetAbsoluteUrlAppRoot()."images/indicator_arrows.gif\"> ".Dict::S('UI:Loading').'</p>');
|
||||
$oPage->add_script('
|
||||
$.post("ajax.render.php?style='.$this->m_sStyle.'",
|
||||
{ operation: "ajax", filter: "'.$sFilter.'", extra_params: "'.$sExtraParams.'" },
|
||||
|
||||
@@ -82,7 +82,7 @@ class LoginWebPage extends NiceWebPage
|
||||
}
|
||||
|
||||
protected static $m_sLoginFailedMessage = '';
|
||||
|
||||
|
||||
public function __construct($sTitle = null)
|
||||
{
|
||||
if ($sTitle === null) {
|
||||
@@ -97,8 +97,17 @@ class LoginWebPage extends NiceWebPage
|
||||
|
||||
public function SetStyleSheet()
|
||||
{
|
||||
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/login.css');
|
||||
$this->add_linked_stylesheet(utils::GetAbsoluteUrlAppRoot().'css/font-awesome/css/all.min.css');
|
||||
$this->LinkStylesheetFromAppRoot('css/login.css');
|
||||
$this->LinkStylesheetFromAppRoot('css/font-awesome/css/all.min.css');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function GetFaviconAbsoluteUrl()
|
||||
{
|
||||
return Branding::GetLoginFavIconAbsoluteUrl();
|
||||
}
|
||||
|
||||
public static function SetLoginFailedMessage($sMessage)
|
||||
@@ -910,13 +919,13 @@ class LoginWebPage extends NiceWebPage
|
||||
$aAllProfiles = array();
|
||||
while ($oProfile = $oProfilesSet->Fetch())
|
||||
{
|
||||
$aAllProfiles[strtolower($oProfile->GetName())] = $oProfile->GetKey();
|
||||
$aAllProfiles[mb_strtolower($oProfile->GetName())] = $oProfile->GetKey();
|
||||
}
|
||||
|
||||
$aProfiles = array();
|
||||
foreach ($aRequestedProfiles as $sRequestedProfile)
|
||||
{
|
||||
$sRequestedProfile = strtolower($sRequestedProfile);
|
||||
$sRequestedProfile = mb_strtolower($sRequestedProfile);
|
||||
if (isset($aAllProfiles[$sRequestedProfile]))
|
||||
{
|
||||
$aProfiles[] = $aAllProfiles[$sRequestedProfile];
|
||||
|
||||
@@ -125,9 +125,7 @@ class ApplicationMenu
|
||||
*/
|
||||
public static function CheckMenuIdEnabled($sMenuId)
|
||||
{
|
||||
self::LoadAdditionalMenus();
|
||||
$oMenuNode = self::GetMenuNode(self::GetMenuIndexById($sMenuId));
|
||||
if (is_null($oMenuNode) || !$oMenuNode->IsEnabled())
|
||||
if (self::IsMenuIdEnabled($sMenuId) === false)
|
||||
{
|
||||
require_once(APPROOT.'/setup/setuppage.class.inc.php');
|
||||
$oP = new ErrorPage(Dict::S('UI:PageTitle:FatalError'));
|
||||
@@ -138,6 +136,19 @@ class ApplicationMenu
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sMenuId
|
||||
*
|
||||
* @return bool true if the menu exists and current user is allowed to see the menu
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static function IsMenuIdEnabled($sMenuId):bool
|
||||
{
|
||||
self::LoadAdditionalMenus();
|
||||
$oMenuNode = self::GetMenuNode(self::GetMenuIndexById($sMenuId));
|
||||
return is_null($oMenuNode) === false && $oMenuNode->IsEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* Main function to add a menu entry into the application, can be called during the definition
|
||||
* of the data model objects
|
||||
@@ -269,9 +280,11 @@ class ApplicationMenu
|
||||
$oMenuNode = static::GetMenuNode($sMenuGroupIdx);
|
||||
|
||||
if (!($oMenuNode instanceof MenuGroup)) {
|
||||
IssueLog::Error('Menu node was not displayed as a menu group as it is actually not a menu group', LogChannels::CONSOLE, [
|
||||
IssueLog::Error('Menu node without parent (root menu) must be of type menu group. Parent menu is missing or not visible to user.', LogChannels::CONSOLE, [
|
||||
'menu_node_class' => get_class($oMenuNode),
|
||||
'menu_node_id' => $oMenuNode->GetMenuID(),
|
||||
'menu_node_label' => $oMenuNode->GetLabel(),
|
||||
'current_user_id' => UserRights::GetUserId(),
|
||||
]);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -293,7 +293,7 @@ $("#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) {
|
||||
$('#attr_auto_reload').on('change', function(ev) {
|
||||
$("#attr_auto_reload_sec").prop('disabled', !$(this).is(':checked'));
|
||||
} );
|
||||
|
||||
|
||||
@@ -232,12 +232,13 @@ class DisplayTemplate
|
||||
static public function UnitTest()
|
||||
{
|
||||
require_once(APPROOT.'/application/startup.inc.php');
|
||||
|
||||
|
||||
$sAppRootUrl = utils::GetAbsoluteUrlAppRoot();
|
||||
$sTemplate = '<div class="page_header">
|
||||
<div class="actions_details"><a href="#"><span>Actions</span></a></div>
|
||||
<h1>$class$: <span class="hilite">$name$</span></h1>
|
||||
</div>
|
||||
<img src="../../images/connect_to_network.png" style="margin-top:-10px; margin-right:10px; float:right">
|
||||
<img src="'.$sAppRootUrl.'images/connect_to_network.png" style="margin-top:-10px; margin-right:10px; float:right">
|
||||
<itoptabs>
|
||||
<itoptab name="Interfaces">
|
||||
<itopblock blockclass="DisplayBlock" type="list" encoding="text/oql">SELECT Interface AS i WHERE i.device_id = $id$</itopblock>
|
||||
@@ -350,7 +351,8 @@ class ObjectDetailsTemplate extends DisplayTemplate
|
||||
if ($iFlags & OPT_ATT_SLAVE)
|
||||
{
|
||||
$iSynchroFlags = $this->m_oObj->GetSynchroReplicaFlags($sAttCode, $aReasons);
|
||||
$sSynchroIcon = " <img id=\"synchro_$iInputId\" src=\"../images/transp-lock.png\" style=\"vertical-align:middle\"/>";
|
||||
$sAppRooturl = utils::GetAbsoluteUrlAppRoot();
|
||||
$sSynchroIcon = " <img id=\"synchro_$iInputId\" src=\"{$sAppRooturl}images/transp-lock.png\" style=\"vertical-align:middle\"/>";
|
||||
$sTip = '';
|
||||
foreach($aReasons as $aRow)
|
||||
{
|
||||
|
||||
@@ -536,7 +536,7 @@ CSS;
|
||||
if (static::HasImageExtension($sImg)
|
||||
&& ! array_key_exists($sImg, $aImages))
|
||||
{
|
||||
$sFilePath = realpath($sImg);
|
||||
$sFilePath = utils::RealPath($sImg, APPROOT);
|
||||
if ($sFilePath !== false) {
|
||||
$sFilePathWithSlashes = str_replace('\\', '/', $sFilePath);
|
||||
$aImages[$sImg] = $sFilePathWithSlashes;
|
||||
@@ -544,7 +544,7 @@ CSS;
|
||||
}
|
||||
|
||||
$sCanonicalPath = static::CanonicalizePath($sTargetThemeFolderPath.'/'.$sImg);
|
||||
$sFilePath = realpath($sCanonicalPath);
|
||||
$sFilePath = utils::RealPath($sCanonicalPath, APPROOT);
|
||||
if ($sFilePath !== false) {
|
||||
$sFilePathWithSlashes = str_replace('\\', '/', $sFilePath);
|
||||
$aImages[$sImg] = $sFilePathWithSlashes;
|
||||
|
||||
@@ -161,8 +161,8 @@ class UIExtKeyWidget
|
||||
public function DisplaySelect(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, $sTitle, DBObjectset $oAllowedValues, $value, $bMandatory, $sFieldName, $sFormPrefix = '', $aArgs = array(), &$sInputType = '')
|
||||
{
|
||||
$sTitle = addslashes($sTitle);
|
||||
$oPage->add_linked_script('../js/extkeywidget.js');
|
||||
$oPage->add_linked_script('../js/forms-json-utils.js');
|
||||
$oPage->LinkScriptFromAppRoot('js/extkeywidget.js');
|
||||
$oPage->LinkScriptFromAppRoot('js/forms-json-utils.js');
|
||||
|
||||
$bCreate = (!$this->bSearchMode) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_MODIFY) && $bAllowTargetCreation);
|
||||
$bExtensions = true;
|
||||
@@ -368,7 +368,7 @@ JS
|
||||
*/
|
||||
public function DisplayRadio(WebPage $oPage, $iMaxComboLength, $bAllowTargetCreation, DBObjectset $oAllowedValues, $value, $sFieldName, $sDisplayStyle)
|
||||
{
|
||||
$oPage->add_linked_script('../js/forms-json-utils.js');
|
||||
$oPage->LinkScriptFromAppRoot('js/forms-json-utils.js');
|
||||
|
||||
$bCreate = (!$this->bSearchMode) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY) && $bAllowTargetCreation);
|
||||
$bExtensions = true;
|
||||
@@ -477,8 +477,8 @@ JS
|
||||
$this->bSearchMode = $bSearchMode;
|
||||
}
|
||||
$sTitle = addslashes($sTitle);
|
||||
$oPage->add_linked_script('../js/extkeywidget.js');
|
||||
$oPage->add_linked_script('../js/forms-json-utils.js');
|
||||
$oPage->LinkScriptFromAppRoot('js/extkeywidget.js');
|
||||
$oPage->LinkScriptFromAppRoot('js/forms-json-utils.js');
|
||||
|
||||
$bCreate = (!$this->bSearchMode) && (UserRights::IsActionAllowed($this->sTargetClass, UR_ACTION_BULK_MODIFY) && $bAllowTargetCreation);
|
||||
$bExtensions = true;
|
||||
@@ -734,7 +734,7 @@ HTML
|
||||
],
|
||||
});
|
||||
$('#fs_{$this->iId}').on('submit.uiAutocomplete', oACWidget_{$this->iId}.DoSearchObjects);
|
||||
$('#dc_{$this->iId}').resize(oACWidget_{$this->iId}.UpdateSizes);
|
||||
$('#dc_{$this->iId}').on('resize', oACWidget_{$this->iId}.UpdateSizes);
|
||||
JS
|
||||
);
|
||||
}
|
||||
|
||||
@@ -15,8 +15,11 @@
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
use Combodo\iTop\Application\Helper\CKEditorHelper;
|
||||
use Combodo\iTop\Application\Helper\WebResourcesHelper;
|
||||
use Combodo\iTop\Application\TwigBase\Twig\TwigHelper;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
use Combodo\iTop\Renderer\BlockRenderer;
|
||||
|
||||
/**
|
||||
* Class UIHTMLEditorWidget
|
||||
@@ -72,21 +75,32 @@ class UIHTMLEditorWidget
|
||||
// To change the default settings of the editor,
|
||||
// a) edit the file /js/ckeditor/config.js
|
||||
// b) or override some of the configuration settings, using the second parameter of ckeditor()
|
||||
$aConfig = utils::GetCkeditorPref();
|
||||
$sJSDefineWidth = '';
|
||||
$aConfig = CKEditorHelper::GetCkeditorPref();
|
||||
$sWidthSpec = addslashes(trim($this->m_oAttDef->GetWidth()));
|
||||
if ($sWidthSpec != '')
|
||||
{
|
||||
$aConfig['width'] = $sWidthSpec;
|
||||
if ($sWidthSpec != '') {
|
||||
/*N°6543 - the function min allow to keep text inside the column when width is defined*/
|
||||
$aConfig['width'] = "min($sWidthSpec,100%)";
|
||||
$sJSDefineWidth = '$("#cke_'.$iId.' iframe").contents().find("body").css("width", "'.$sWidthSpec.'")';
|
||||
}
|
||||
$sHeightSpec = addslashes(trim($this->m_oAttDef->GetHeight()));
|
||||
if ($sHeightSpec != '')
|
||||
{
|
||||
if ($sHeightSpec != '') {
|
||||
$aConfig['height'] = $sHeightSpec;
|
||||
}
|
||||
// TODO 3.2.0 Add the configuration for the editor
|
||||
$sConfigJS = json_encode($aConfig);
|
||||
|
||||
WebResourcesHelper::EnableCKEditorToWebPage($oPage);
|
||||
$oPage->add_ready_script("$('#$iId').ckeditor(function() { /* callback code */ }, $sConfigJS);"); // Transform $iId into a CKEdit
|
||||
$oPage->add_ready_script("CombodoCKEditorHandler.CreateInstance('#$iId', $sConfigJS)");
|
||||
|
||||
// inject mention item renderer template
|
||||
$oTwig = TwigHelper::GetTwigEnvironment(BlockRenderer::TWIG_BASE_PATH);
|
||||
$sTemplate = $oTwig->render('application/object/set/option_renderer.html.twig');
|
||||
$oPage->add(<<<HTML
|
||||
<template id="{$iId}_items_template">
|
||||
$sTemplate
|
||||
</template>
|
||||
HTML);
|
||||
|
||||
// Please read...
|
||||
// ValidateCKEditField triggers a timer... calling itself indefinitely
|
||||
@@ -111,6 +125,7 @@ $('#$iId').on('update', function(evt){
|
||||
else
|
||||
{
|
||||
oMe.data('ckeditorInstance').setReadOnly(oMe.prop('disabled'));
|
||||
$sJSDefineWidth
|
||||
}
|
||||
};
|
||||
setTimeout(delayedSetReadOnly, 50);
|
||||
|
||||
@@ -99,7 +99,7 @@ HTML
|
||||
});
|
||||
$('#dlg_{$this->m_iInputId}').dialog('option', {title:'$sTitle'});
|
||||
$('#SearchFormToAdd_{$this->m_iInputId} form').on('submit.uilinksWizard', oForeignKeysWidget{$this->m_iInputId}.SearchObjectsToAdd);
|
||||
$('#SearchFormToAdd_{$this->m_iInputId}').resize(oForeignKeysWidget{$this->m_iInputId}.UpdateSizes);
|
||||
$('#SearchFormToAdd_{$this->m_iInputId}').on('resize', oForeignKeysWidget{$this->m_iInputId}.UpdateSizes);
|
||||
JS
|
||||
);
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@ class UserDashboard extends DBObject
|
||||
(
|
||||
"category" => "gui",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "user_id",
|
||||
"name_attcode" => array('user_id', 'menu_code'),
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_app_dashboards",
|
||||
@@ -47,6 +47,15 @@ class UserDashboard extends DBObject
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("user_id", array("targetclass"=>"User", "allowed_values"=>null, "sql"=>"user_id", "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("menu_code", array("allowed_values"=>null, "sql"=>"menu_code", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("contents", array("allowed_values"=>null, "sql"=>"contents", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
|
||||
MetaModel::Init_SetZListItems('default_search', array (
|
||||
0 => 'user_id',
|
||||
1 => 'menu_code',
|
||||
));
|
||||
MetaModel::Init_SetZListItems('list', array (
|
||||
0 => 'user_id',
|
||||
1 => 'menu_code',
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -167,7 +167,11 @@ class utils
|
||||
|
||||
private static $iNextId = 0;
|
||||
|
||||
private static $m_sAppRootUrl = null;
|
||||
/**
|
||||
* @var ?string
|
||||
* @used-by GetAbsoluteUrlAppRoot
|
||||
*/
|
||||
private static $sAbsoluteUrlAppRootCache = null;
|
||||
|
||||
protected static function LoadParamFile($sParamFile)
|
||||
{
|
||||
@@ -1037,28 +1041,27 @@ class utils
|
||||
return $bTrustProxies;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the absolute URL to the application root path
|
||||
*
|
||||
* @param bool $bForceTrustProxy
|
||||
*
|
||||
* @return string The absolute URL to the application root, without the first slash
|
||||
*
|
||||
* @throws \Exception
|
||||
*
|
||||
* @since 2.7.4 $bForceTrustProxy param added
|
||||
*/
|
||||
/**
|
||||
* Returns the absolute URL to the application root path
|
||||
*
|
||||
* @param bool $bForceTrustProxy
|
||||
*
|
||||
* @return string The absolute URL to the application root, without the first slash
|
||||
*
|
||||
* @throws \Exception
|
||||
*
|
||||
* @since 2.7.4 $bForceTrustProxy param added
|
||||
*/
|
||||
public static function GetAbsoluteUrlAppRoot($bForceTrustProxy = false)
|
||||
{
|
||||
$sUrl = static::$m_sAppRootUrl;
|
||||
if ($sUrl === null || $bForceTrustProxy)
|
||||
if (static::$sAbsoluteUrlAppRootCache === null || $bForceTrustProxy)
|
||||
{
|
||||
$sUrl = self::GetConfig()->Get('app_root_url');
|
||||
if ($sUrl == '')
|
||||
static::$sAbsoluteUrlAppRootCache = self::GetConfig()->Get('app_root_url');
|
||||
if (static::$sAbsoluteUrlAppRootCache == '')
|
||||
{
|
||||
$sUrl = self::GetDefaultUrlAppRoot($bForceTrustProxy);
|
||||
static::$sAbsoluteUrlAppRootCache = self::GetDefaultUrlAppRoot($bForceTrustProxy);
|
||||
}
|
||||
elseif (strpos($sUrl, SERVER_NAME_PLACEHOLDER) > -1)
|
||||
elseif (strpos(static::$sAbsoluteUrlAppRootCache, SERVER_NAME_PLACEHOLDER) > -1)
|
||||
{
|
||||
if (isset($_SERVER['SERVER_NAME']))
|
||||
{
|
||||
@@ -1069,11 +1072,10 @@ class utils
|
||||
// CLI mode ?
|
||||
$sServerName = php_uname('n');
|
||||
}
|
||||
$sUrl = str_replace(SERVER_NAME_PLACEHOLDER, $sServerName, $sUrl);
|
||||
static::$sAbsoluteUrlAppRootCache = str_replace(SERVER_NAME_PLACEHOLDER, $sServerName, static::$sAbsoluteUrlAppRootCache);
|
||||
}
|
||||
static::$m_sAppRootUrl = $sUrl;
|
||||
}
|
||||
return static::$m_sAppRootUrl;
|
||||
return static::$sAbsoluteUrlAppRootCache;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2778,76 +2780,6 @@ SQL;
|
||||
return static::$iNextId++;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the CKEditor config as an array
|
||||
*
|
||||
* @return array
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \MySQLException
|
||||
* @since 3.0.0
|
||||
*/
|
||||
public static function GetCkeditorPref()
|
||||
{
|
||||
$sLanguage = strtolower(trim(UserRights::GetUserLanguage()));
|
||||
|
||||
$aDefaultConf = array(
|
||||
'language'=> $sLanguage,
|
||||
'contentsLanguage' => $sLanguage,
|
||||
'extraPlugins' => 'disabler,codesnippet,mentions,objectshortcut,font,uploadimage',
|
||||
'uploadUrl' => utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php',
|
||||
'contentsCss' => array(utils::GetAbsoluteUrlAppRoot().'js/ckeditor/contents.css', utils::GetAbsoluteUrlAppRoot().'css/ckeditor/contents.css'),
|
||||
);
|
||||
|
||||
// Mentions
|
||||
$aMentionsAllowedClasses = MetaModel::GetConfig()->Get('mentions.allowed_classes');
|
||||
if(!empty($aMentionsAllowedClasses)) {
|
||||
$aDefaultConf['mentions'] = [];
|
||||
|
||||
foreach($aMentionsAllowedClasses as $sMentionMarker => $sMentionScope) {
|
||||
// Retrieve mention class
|
||||
// - First test if the conf is a simple Datamodel class
|
||||
if (MetaModel::IsValidClass($sMentionScope)) {
|
||||
$sMentionClass = $sMentionScope;
|
||||
}
|
||||
// - Otherwise it must be a valid OQL
|
||||
else {
|
||||
$oTmpSearch = DBSearch::FromOQL($sMentionScope);
|
||||
$sMentionClass = $oTmpSearch->GetClass();
|
||||
unset($oTmpSearch);
|
||||
}
|
||||
|
||||
// Note: Endpoints are defaults only and should be overloaded by other GUIs such as the end-users portal
|
||||
$sMentionEndpoint = utils::GetAbsoluteUrlAppRoot().'pages/ajax.render.php?operation=cke_mentions&marker='.urlencode($sMentionMarker).'&needle={encodedQuery}';
|
||||
$sMentionItemUrl = utils::GetAbsoluteUrlAppRoot().'pages/UI.php?operation=details&class='.$sMentionClass.'&id={id}';
|
||||
|
||||
$sMentionItemPictureTemplate = (empty(MetaModel::GetImageAttributeCode($sMentionClass))) ? '' : <<<HTML
|
||||
<span class="ibo-vendors-ckeditor--autocomplete-item-image" style="{picture_style}">{initials}</span>
|
||||
HTML;
|
||||
$sMentionItemTemplate = <<<HTML
|
||||
<li class="ibo-vendors-ckeditor--autocomplete-item" data-id="{id}">{$sMentionItemPictureTemplate}<span class="ibo-vendors-ckeditor--autocomplete-item-title">{friendlyname}</span></li>
|
||||
HTML;
|
||||
$sMentionOutputTemplate = <<<HTML
|
||||
<a href="$sMentionItemUrl" data-role="object-mention" data-object-class="{class}" data-object-id="{id}">{$sMentionMarker}{friendlyname}</a>
|
||||
HTML;
|
||||
|
||||
$aDefaultConf['mentions'][] = [
|
||||
'feed' => $sMentionEndpoint,
|
||||
'marker' => $sMentionMarker,
|
||||
'minChars' => MetaModel::GetConfig()->Get('min_autocomplete_chars'),
|
||||
'itemTemplate' => $sMentionItemTemplate,
|
||||
'outputTemplate' => $sMentionOutputTemplate,
|
||||
'throttle' => 500,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
$aRichTextConfig = json_decode(appUserPreferences::GetPref('richtext_config', '{}'), true);
|
||||
|
||||
|
||||
return array_merge($aDefaultConf, $aRichTextConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sInterface
|
||||
* @param string $sClassNameFilter
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"type": "project",
|
||||
"license": "AGPL-3.0-only",
|
||||
"require": {
|
||||
"php": ">=8.1.0 <8.2.0",
|
||||
"php": ">=8.1.0 <8.4.0",
|
||||
"ext-ctype": "*",
|
||||
"ext-dom": "*",
|
||||
"ext-gd": "*",
|
||||
@@ -13,42 +13,42 @@
|
||||
"ext-mysqli": "*",
|
||||
"ext-soap": "*",
|
||||
"apereo/phpcas": "~1.6.0",
|
||||
"combodo/tcpdf": "~6.4.4",
|
||||
"firebase/php-jwt": "~6.4.0",
|
||||
"firebase/php-jwt": "^6.4.0",
|
||||
"guzzlehttp/guzzle": "^7.5.1",
|
||||
"laminas/laminas-mail": "^2.11",
|
||||
"laminas/laminas-servicemanager": "^3.5",
|
||||
"league/oauth2-google": "^3.0",
|
||||
"nikic/php-parser": "~4.14.0",
|
||||
"league/oauth2-google": "^4.0.1",
|
||||
"nikic/php-parser": "^4.14.0",
|
||||
"pear/archive_tar": "~1.4.14",
|
||||
"pelago/emogrifier": "^6.0.0",
|
||||
"scssphp/scssphp": "^1.10.3",
|
||||
"pelago/emogrifier": "^7.2.0",
|
||||
"psr/log": "^3.0.0",
|
||||
"scssphp/scssphp": "^1.12.1",
|
||||
"symfony/console": "~6.4.0",
|
||||
"symfony/dotenv": "~6.4.0",
|
||||
"symfony/form": "~6.4.0",
|
||||
"symfony/framework-bundle": "~6.4.0",
|
||||
"symfony/http-foundation": "~6.4.0",
|
||||
"symfony/http-kernel": "~6.4.0",
|
||||
"symfony/runtime": "~6.4.0",
|
||||
"symfony/serializer": "^6.4",
|
||||
"symfony/twig-bundle": "~6.4.0",
|
||||
"symfony/validator": "~6.4.0",
|
||||
"symfony/var-dumper": "~6.4.0",
|
||||
"symfony/yaml": "~6.4.0",
|
||||
"thenetworg/oauth2-azure": "^2.0"
|
||||
"tecnickcom/tcpdf": "^6.6.0",
|
||||
"thenetworg/oauth2-azure": "^2.0",
|
||||
"masterminds/html5": "^2.8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/debug-bundle": "~6.4.0",
|
||||
"symfony/stopwatch": "~6.4.0",
|
||||
"symfony/web-profiler-bundle": "~6.4.0",
|
||||
"symfony/debug-bundle": "~6.4.0"
|
||||
"symfony/web-profiler-bundle": "~6.4.0"
|
||||
},
|
||||
"suggest": {
|
||||
"ext-libsodium": "Required to use the AttributeEncryptedString.",
|
||||
"ext-openssl": "Can be used as a polyfill if libsodium is not installed",
|
||||
"ext-mcrypt": "Can be used as a polyfill if either libsodium and openssl are not installed (libsodium and openssl are more secure)",
|
||||
"ext-apcu": "For better performance and stability",
|
||||
"ext-imap": "Required by the extension \"Mail to ticket automation\"",
|
||||
"ext-ldap": "Required to use LDAP as an identity provider",
|
||||
"ext-posix": "Not required by the core, but some extensions uses it.",
|
||||
"ext-imap": "Required by the extension \"Mail to ticket automation\""
|
||||
"ext-posix": "Not required by the core, but some extensions uses it."
|
||||
},
|
||||
"config": {
|
||||
"platform": {
|
||||
@@ -95,12 +95,13 @@
|
||||
"require": "3.4.*"
|
||||
},
|
||||
"runtime": {
|
||||
"dotenv_path": "symfony/.env"
|
||||
"dotenv_path": "resources/symfony/.env"
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"post-install-cmd": ["@rmDeniedTestDir"],
|
||||
"post-update-cmd": ["@rmDeniedTestDir"],
|
||||
"rmDeniedTestDir": "@php .make/composer/rmDeniedTestDir.php"
|
||||
"post-install-cmd": ["@rmUnnecessaryFolders", "@tcpdfCustomFonts"],
|
||||
"post-update-cmd": ["@rmUnnecessaryFolders", "@tcpdfCustomFonts"],
|
||||
"rmUnnecessaryFolders": "@php .make/dependencies/rmUnnecessaryFolders.php --manager composer",
|
||||
"tcpdfCustomFonts": "@php .make/dependencies/composer/tcpdf/tcpdfUpdateFonts.php"
|
||||
}
|
||||
}
|
||||
|
||||
1449
composer.lock
generated
1449
composer.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -521,6 +521,6 @@ class Str
|
||||
|
||||
public static function islowcase($sString)
|
||||
{
|
||||
return (strtolower($sString) == $sString);
|
||||
return (mb_strtolower($sString) == $sString);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,11 @@
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
use Combodo\iTop\Application\TwigBase\Twig\TwigHelper;
|
||||
use Combodo\iTop\Application\UI\Base\Component\DataTable\DataTableUIBlockFactory;
|
||||
use Combodo\iTop\Application\WebPage\WebPage;
|
||||
use Combodo\iTop\Service\Notification\NotificationsRepository;
|
||||
use Combodo\iTop\Service\Notification\NotificationsService;
|
||||
use Combodo\iTop\Service\Router\Router;
|
||||
|
||||
/**
|
||||
* Persistent classes (internal): user defined actions
|
||||
@@ -77,6 +81,7 @@ abstract class Action extends cmdbAbstractObject
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeLinkedSetIndirect("trigger_list",
|
||||
array("linked_class" => "lnkTriggerAction", "ext_key_to_me" => "action_id", "ext_key_to_remote" => "trigger_id", "allowed_values" => null, "count_min" => 0, "count_max" => 0, "depends_on" => array(), "display_style" => 'property')));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("asynchronous", array("allowed_values" => new ValueSetEnum(['use_global_setting' => 'Use global settings','yes' => 'Yes' ,'no' => 'No']), "sql" => "asynchronous", "default_value" => 'use_global_setting', "is_null_allowed" => false, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
// - Attributes to be displayed for the complete details
|
||||
@@ -168,6 +173,100 @@ abstract class Action extends cmdbAbstractObject
|
||||
$this->m_aCheckWarnings[] = Dict::S('Action:WarningNoTriggerLinked');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.2.0 N°5472 method creation
|
||||
*/
|
||||
public function DisplayBareRelations(WebPage $oPage, $bEditMode = false)
|
||||
{
|
||||
parent::DisplayBareRelations($oPage, false);
|
||||
|
||||
if ($oPage instanceof iTopWebPage) {
|
||||
$this->GenerateLastExecutionsTab($oPage, $bEditMode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.2.0 N°5472 method creation
|
||||
*/
|
||||
protected function GenerateLastExecutionsTab(iTopWebPage $oPage, $bEditMode)
|
||||
{
|
||||
$oRouter = Router::GetInstance();
|
||||
$sActionLastExecutionsPageUrl = $oRouter->GenerateUrl('notifications.action.last_executions_tab', ['action_id' => $this->GetKey()]);
|
||||
$oPage->AddAjaxTab('action_errors', $sActionLastExecutionsPageUrl, false, Dict::S('Action:last_executions_tab'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Combodo\iTop\Application\WebPage\WebPage $oPage
|
||||
*
|
||||
* @throws \ApplicationException
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \ConfigException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \InvalidConfigParamException
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
* @throws \ReflectionException
|
||||
* @since 3.2.0 N°5472 method creation
|
||||
*/
|
||||
public function GetLastExecutionsTabContent(WebPage $oPage): void
|
||||
{
|
||||
$oConfig = utils::GetConfig();
|
||||
$sLastExecutionDaysConfigParamName = 'notifications.last_executions_days';
|
||||
$iLastExecutionDays = $oConfig->Get($sLastExecutionDaysConfigParamName);
|
||||
|
||||
if ($iLastExecutionDays < 0) {
|
||||
throw new InvalidConfigParamException("Invalid value for {$sLastExecutionDaysConfigParamName} config parameter. Param desc: " . $oConfig->GetDescription($sLastExecutionDaysConfigParamName));
|
||||
}
|
||||
|
||||
$sActionQueryOql = 'SELECT EventNotification WHERE action_id = :action_id';
|
||||
$aActionQueryParams = ['action_id' => $this->GetKey()];
|
||||
if ($iLastExecutionDays > 0) {
|
||||
$sActionQueryOql .= ' AND date > DATE_SUB(NOW(), INTERVAL :days DAY)';
|
||||
$aActionQueryParams['days'] = $iLastExecutionDays;
|
||||
$sActionQueryLimit = Dict::Format('Action:last_executions_tab_limit_days', $iLastExecutionDays);
|
||||
} else {
|
||||
$sActionQueryLimit = Dict::S('Action:last_executions_tab_limit_none');
|
||||
}
|
||||
|
||||
$oActionFilter = DBObjectSearch::FromOQL($sActionQueryOql, $aActionQueryParams);
|
||||
$oSet = new DBObjectSet($oActionFilter, ['date' => false]);
|
||||
|
||||
$sPanelTitle = Dict::Format('Action:last_executions_tab_panel_title', $sActionQueryLimit);
|
||||
$oExecutionsListBlock = DataTableUIBlockFactory::MakeForResult($oPage, 'action_executions_list', $oSet, ['panel_title' => $sPanelTitle]);
|
||||
|
||||
$oPage->AddUiBlock($oExecutionsListBlock);
|
||||
}
|
||||
|
||||
/**
|
||||
* Will be overloaded by the children classes to return the value of their global asynchronous setting (eg. `email_asynchronous` for `\ActionEmail`, `prefer_asynchronous` for `\ActionWebhook`, ...)
|
||||
*
|
||||
* @return bool true if the global setting for this kind of action if to be executed asynchronously, false otherwise.
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static function GetAsynchronousGlobalSetting(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool true if that action instance should be executed asynchronously, otherwise false
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreException
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function IsAsynchronous(): bool
|
||||
{
|
||||
$sAsynchronous = $this->Get('asynchronous');
|
||||
if ($sAsynchronous === 'use_global_setting') {
|
||||
return static::GetAsynchronousGlobalSetting();
|
||||
}
|
||||
return $sAsynchronous === 'yes';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -285,6 +384,7 @@ class ActionEmail extends ActionNotification
|
||||
"db_table" => "priv_action_email",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
'style' => new ormStyle(null, null, null, null, null, '../images/icons/icons8-mailing.svg'),
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
@@ -321,6 +421,7 @@ class ActionEmail extends ActionNotification
|
||||
),
|
||||
'fieldset:ActionEmail:trigger' => array(
|
||||
0 => 'trigger_list',
|
||||
1 => 'asynchronous'
|
||||
),
|
||||
),
|
||||
'col:col2' => array(
|
||||
@@ -355,27 +456,33 @@ class ActionEmail extends ActionNotification
|
||||
protected $m_aMailErrors; //array of strings explaining the issue
|
||||
|
||||
/**
|
||||
* Return a the list of emails as a string, or a detailed error description
|
||||
* Return the list of emails as a string, or a detailed error description
|
||||
*
|
||||
* @param string $sRecipAttCode
|
||||
* @param array $aArgs
|
||||
*
|
||||
* @return string
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \CoreWarning
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
protected function FindRecipients($sRecipAttCode, $aArgs)
|
||||
{
|
||||
$oTrigger = $aArgs['trigger->object()'] ?? null;
|
||||
$sOQL = $this->Get($sRecipAttCode);
|
||||
if (strlen($sOQL) === 0) return '';
|
||||
if (utils::IsNullOrEmptyString($sOQL)) return '';
|
||||
|
||||
try
|
||||
{
|
||||
$oSearch = DBObjectSearch::FromOQL($sOQL);
|
||||
if ($this->Get('ignore_notify') === 'no') {
|
||||
// In theory it is possible to notify *any* kind of object,
|
||||
// In theory, it is possible to notify *any* kind of object,
|
||||
// as long as there is an email attribute in the class
|
||||
// So let's not assume that the selected class is a Person
|
||||
$sFirstSelectedClass = $oSearch->GetClass();
|
||||
@@ -408,16 +515,29 @@ class ActionEmail extends ActionNotification
|
||||
return "The objects of the class '$sClass' do not have any email attribute";
|
||||
}
|
||||
|
||||
if($oTrigger !== null && in_array('Contact', MetaModel::EnumParentClasses($sClass, ENUM_CHILD_CLASSES_ALL), true)) {
|
||||
$aArgs['trigger_id'] = $oTrigger->GetKey();
|
||||
$aArgs['action_id'] = $this->GetKey();
|
||||
|
||||
$sSubscribedContactsOQL = NotificationsRepository::GetInstance()->GetSearchOQLContactUnsubscribedByTriggerAndAction();
|
||||
$sSubscribedContactsOQL->ApplyParameters($aArgs);
|
||||
$sAlias = $oSearch->GetClassAlias();
|
||||
$oSearch->AddConditionExpression(Expression::FromOQL("`$sAlias`.id NOT IN ($sSubscribedContactsOQL)"));
|
||||
}
|
||||
|
||||
$oSet = new DBObjectSet($oSearch, array() /* order */, $aArgs);
|
||||
$aRecipients = array();
|
||||
while ($oObj = $oSet->Fetch())
|
||||
{
|
||||
$sAddress = trim($oObj->Get($sEmailAttCode));
|
||||
if (strlen($sAddress) > 0)
|
||||
if (utils::IsNotNullOrEmptyString($sAddress))
|
||||
{
|
||||
$aRecipients[] = $sAddress;
|
||||
$this->m_iRecipients++;
|
||||
}
|
||||
if ($oTrigger !== null && in_array('Contact', MetaModel::EnumParentClasses($sClass, ENUM_CHILD_CLASSES_ALL), true)) {
|
||||
NotificationsService::GetInstance()->RegisterSubscription($oTrigger, $this, $oObj);
|
||||
}
|
||||
}
|
||||
return implode(', ', $aRecipients);
|
||||
}
|
||||
@@ -537,7 +657,7 @@ class ActionEmail extends ActionNotification
|
||||
else
|
||||
{
|
||||
$aErrors = [];
|
||||
$iRes = $oEmail->Send($aErrors, false, $oLog); // allow asynchronous mode
|
||||
$iRes = $oEmail->Send($aErrors, $this->IsAsynchronous() ? Email::ENUM_SEND_FORCE_ASYNCHRONOUS : Email::ENUM_SEND_FORCE_SYNCHRONOUS, $oLog);
|
||||
switch ($iRes)
|
||||
{
|
||||
case EMAIL_SEND_OK:
|
||||
@@ -566,8 +686,17 @@ class ActionEmail extends ActionNotification
|
||||
* @param \EventNotification $oLog
|
||||
*
|
||||
* @return array
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \Exception
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \CoreWarning
|
||||
* @throws \DictExceptionMissingString
|
||||
* @throws \DictExceptionUnknownLanguage
|
||||
* @throws \MissingQueryArgument
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \OQLException
|
||||
* @since 3.1.0 N°918
|
||||
*/
|
||||
protected function PrepareMessageContent($aContextArgs, &$oLog): array
|
||||
@@ -646,9 +775,7 @@ class ActionEmail extends ActionNotification
|
||||
$oLog->Set('body', HTMLSanitizer::Sanitize($aMessageContent['body']));
|
||||
}
|
||||
}
|
||||
$sStyles = file_get_contents(APPROOT.'css/email.css');
|
||||
$sStyles .= MetaModel::GetConfig()->Get('email_css');
|
||||
|
||||
|
||||
if ($this->IsBeingTested()) {
|
||||
$sTestBody = $aMessageContent['body'];
|
||||
$sTestBody .= "<div style=\"border: dashed;\">\n";
|
||||
@@ -677,10 +804,11 @@ class ActionEmail extends ActionNotification
|
||||
if (isset($aContextArgs['attachments']))
|
||||
{
|
||||
$aAttachmentReport = array();
|
||||
/** @var \ormDocument $oDocument */
|
||||
foreach($aContextArgs['attachments'] as $oDocument)
|
||||
{
|
||||
$aMessageContent['attachments'][] = ['data' => $oDocument->GetData(), 'filename' => $oDocument->GetFileName(), 'mime_type' => $oDocument->GetMimeType()];
|
||||
$aAttachmentReport[] = array($oDocument->GetFileName(), $oDocument->GetMimeType(), strlen($oDocument->GetData()));
|
||||
$aAttachmentReport[] = array($oDocument->GetFileName(), $oDocument->GetMimeType(), strlen($oDocument->GetData() ?? ''));
|
||||
}
|
||||
$oLog->Set('attachments', $aAttachmentReport);
|
||||
}
|
||||
@@ -790,4 +918,13 @@ class ActionEmail extends ActionNotification
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public static function GetAsynchronousGlobalSetting(): bool
|
||||
{
|
||||
return utils::GetConfig()->Get('email_asynchronous');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,14 +60,15 @@ function apc_store($key, $var = NULL, $ttl = 0)
|
||||
*/
|
||||
function apc_fetch($key)
|
||||
{
|
||||
if (is_array($key))
|
||||
{
|
||||
$aResult = array();
|
||||
foreach($key as $sKey)
|
||||
{
|
||||
if (is_array($key)) {
|
||||
$aResult = [];
|
||||
foreach ($key as $sKey) {
|
||||
$aResult[$sKey] = apcFile::FetchOneFile($sKey);
|
||||
}
|
||||
|
||||
return $aResult;
|
||||
} elseif (is_null($key)) {
|
||||
return false;
|
||||
}
|
||||
return apcFile::FetchOneFile($key);
|
||||
}
|
||||
@@ -97,6 +98,31 @@ function apc_delete($key)
|
||||
return $bRet1 || $bRet2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if APCu emulation key exists
|
||||
*
|
||||
* @param string|string[] $keys A string, or an array of strings, that contain keys.
|
||||
*
|
||||
* @return bool|string[] Returns TRUE if the key exists, otherwise FALSE
|
||||
* Or if an array was passed to keys, then an array is returned that
|
||||
* contains all existing keys, or an empty array if none exist.
|
||||
* @since 3.2.0 N°7068
|
||||
*/
|
||||
function apc_exists($keys)
|
||||
{
|
||||
if (is_array($keys)) {
|
||||
$aExistingKeys = [];
|
||||
foreach ($keys as $sKey) {
|
||||
if (apcFile::ExistsOneFile($sKey)) {
|
||||
$aExistingKeys[] = $sKey;
|
||||
}
|
||||
}
|
||||
return $aExistingKeys;
|
||||
} else {
|
||||
return apcFile::ExistsOneFile($keys);
|
||||
}
|
||||
}
|
||||
|
||||
class apcFile
|
||||
{
|
||||
// Check only once per request
|
||||
@@ -183,6 +209,16 @@ class apcFile
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if cache key exists
|
||||
* @param $sKey
|
||||
* @return bool
|
||||
* @since 3.2.0 N°7068
|
||||
*/
|
||||
static public function ExistsOneFile($sKey) {
|
||||
return is_file(self::GetCacheFileName('-' . $sKey)) || is_file(self::GetCacheFileName($sKey));
|
||||
}
|
||||
|
||||
/** Get one cache entry content.
|
||||
* @param $sKey
|
||||
* @return bool|mixed
|
||||
@@ -211,21 +247,16 @@ class apcFile
|
||||
*/
|
||||
static public function StoreOneFile($sKey, $value, $iTTL)
|
||||
{
|
||||
if (empty($sKey))
|
||||
{
|
||||
if (empty($sKey)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (is_file(self::GetCacheFileName($sKey)))
|
||||
{
|
||||
if (is_file(self::GetCacheFileName($sKey))) {
|
||||
@unlink(self::GetCacheFileName($sKey));
|
||||
}
|
||||
if (is_file(self::GetCacheFileName('-'.$sKey)))
|
||||
{
|
||||
if (is_file(self::GetCacheFileName('-'.$sKey))) {
|
||||
@unlink(self::GetCacheFileName('-'.$sKey));
|
||||
}
|
||||
if ($iTTL > 0)
|
||||
{
|
||||
if ($iTTL > 0) {
|
||||
// hint for ttl management
|
||||
$sKey = '-'.$sKey;
|
||||
}
|
||||
@@ -233,15 +264,14 @@ class apcFile
|
||||
$sFilename = self::GetCacheFileName($sKey);
|
||||
// try to create the folder
|
||||
$sDirname = dirname($sFilename);
|
||||
if (!file_exists($sDirname))
|
||||
{
|
||||
if (!@mkdir($sDirname, 0755, true))
|
||||
{
|
||||
if (!is_dir($sDirname)) {
|
||||
if (!@mkdir($sDirname, 0755, true)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
$bRes = !(@file_put_contents($sFilename, serialize($value), LOCK_EX) === false);
|
||||
self::AddFile($sFilename);
|
||||
|
||||
return $bRes;
|
||||
}
|
||||
|
||||
@@ -325,19 +355,15 @@ class apcFile
|
||||
*/
|
||||
static protected function ReadCacheLocked($sFilename)
|
||||
{
|
||||
if (!is_file($sFilename))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
$sContent = false;
|
||||
$file = @fopen($sFilename, 'r');
|
||||
if ($file === false)
|
||||
{
|
||||
return false;
|
||||
if ($file !== false) {
|
||||
if (flock($file, LOCK_SH)) {
|
||||
$sContent = file_get_contents($sFilename);
|
||||
flock($file, LOCK_UN);
|
||||
}
|
||||
fclose($file);
|
||||
}
|
||||
flock($file, LOCK_SH);
|
||||
$sContent = @fread($file, @filesize($sFilename));
|
||||
flock($file, LOCK_UN);
|
||||
fclose($file);
|
||||
return $sContent;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +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/>
|
||||
use Combodo\iTop\Service\Notification\Event\EventiTopNotificationService;
|
||||
|
||||
|
||||
/**
|
||||
@@ -457,3 +458,87 @@ class AsyncSendEmail extends AsyncTask
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An async notification to be sent to iTop users
|
||||
* @since 3.2.0
|
||||
*/
|
||||
class AsyncSendiTopNotifications extends AsyncTask {
|
||||
|
||||
public static function Init()
|
||||
{
|
||||
$aParams = array
|
||||
(
|
||||
"category" => "core/cmdb",
|
||||
"key_type" => "autoincrement",
|
||||
"name_attcode" => "created",
|
||||
"state_attcode" => "",
|
||||
"reconc_keys" => array(),
|
||||
"db_table" => "priv_async_send_itop_notifications",
|
||||
"db_key_field" => "id",
|
||||
"db_finalclass_field" => "",
|
||||
);
|
||||
MetaModel::Init_Params($aParams);
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
MetaModel::Init_AddAttribute(new AttributeText("recipients", array("allowed_values"=>null, "sql"=>"recipients", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("action_id", array("targetclass"=>"Action", "allowed_values"=>null, "sql"=>"action_id", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeExternalKey("trigger_id", array("targetclass"=>"Trigger", "allowed_values"=>null, "sql"=>"trigger_id", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("title", array("allowed_values"=>null, "sql"=>"title", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("message", array("allowed_values"=>null, "sql"=>"message", "default_value"=>null, "is_null_allowed"=>false, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeInteger("object_id", array("allowed_values"=>null, "sql"=>"object_id", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeString("object_class", array("allowed_values"=>null, "sql"=>"object_class", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeText("url", array("allowed_values"=>null, "sql"=>"url", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeDateTime("date", array("allowed_values"=>null, "sql"=>"date", "default_value"=>null, "is_null_allowed"=>false, "on_target_delete"=>DEL_AUTO, "depends_on"=>array())));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \ArchivedObjectException
|
||||
* @throws \CoreCannotSaveObjectException
|
||||
* @throws \CoreException
|
||||
* @throws \CoreUnexpectedValue
|
||||
* @throws \CoreWarning
|
||||
* @throws \MySQLException
|
||||
* @throws \OQLException
|
||||
*/
|
||||
public static function AddToQueue(int $iActionId, int $iTriggerId, array $aRecipients, string $sMessage, string $sTitle, string $sUrl, int $iObjectId, ?string $sObjectClass): void
|
||||
{
|
||||
$oNew = new static();
|
||||
$oNew->Set('action_id', $iActionId);
|
||||
$oNew->Set('trigger_id', $iTriggerId);
|
||||
$oNew->Set('recipients', json_encode($aRecipients));
|
||||
$oNew->Set('message', $sMessage);
|
||||
$oNew->Set('title', $sTitle);
|
||||
$oNew->Set('url', $sUrl);
|
||||
$oNew->Set('object_id', $iObjectId);
|
||||
$oNew->Set('object_class', $sObjectClass);
|
||||
$oNew->SetCurrentDate('date');
|
||||
|
||||
$oNew->DBInsert();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function DoProcess()
|
||||
{
|
||||
$oAction = MetaModel::GetObject('Action', $this->Get('action_id'));
|
||||
$iTriggerId = $this->Get('trigger_id');
|
||||
$aRecipients = json_decode($this->Get('recipients'));
|
||||
$sMessage = $this->Get('message');
|
||||
$sTitle = $this->Get('title');
|
||||
$sUrl = $this->Get('url');
|
||||
$iObjectId = $this->Get('object_id');
|
||||
$sObjectClass = $this->Get('object_class');
|
||||
$sDate = $this->Get('date');
|
||||
|
||||
foreach ($aRecipients as $iRecipientId)
|
||||
{
|
||||
$oEvent = EventiTopNotificationService::MakeEventFromAction($oAction, $iRecipientId, $iTriggerId, $sMessage, $sTitle, $sUrl, $iObjectId, $sObjectClass, $sDate);
|
||||
$oEvent->DBInsertNoReload();
|
||||
}
|
||||
|
||||
return "Sent";
|
||||
}
|
||||
}
|
||||
@@ -73,6 +73,11 @@ define('DEL_SILENT', 2);
|
||||
*/
|
||||
define('DEL_MOVEUP', 3);
|
||||
|
||||
/**
|
||||
* Do nothing at least automatically
|
||||
*/
|
||||
define('DEL_NONE', 4);
|
||||
|
||||
|
||||
/**
|
||||
* For Link sets: tracking_level
|
||||
@@ -3062,6 +3067,11 @@ class AttributeObjectKey extends AttributeDBFieldVoid
|
||||
return ((int) $proposedValue) !== 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* @param int|DBObject $proposedValue Object key or valid ({@see MetaModel::IsValidObject()}) datamodel object
|
||||
*/
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
if (is_null($proposedValue))
|
||||
@@ -3074,7 +3084,6 @@ class AttributeObjectKey extends AttributeDBFieldVoid
|
||||
}
|
||||
if (MetaModel::IsValidObject($proposedValue))
|
||||
{
|
||||
/** @var \DBObject $proposedValue */
|
||||
return $proposedValue->GetKey();
|
||||
}
|
||||
|
||||
@@ -3192,9 +3201,19 @@ class AttributeDecimal extends AttributeDBField
|
||||
{
|
||||
$iNbDigits = $this->Get('digits');
|
||||
$iPrecision = $this->Get('decimals');
|
||||
$iNbIntegerDigits = $iNbDigits - $iPrecision - 1; // -1 because the first digit is treated separately in the pattern below
|
||||
$iNbIntegerDigits = $iNbDigits - $iPrecision;
|
||||
|
||||
return "^[\-\+]?[0-9]\d{0,$iNbIntegerDigits}(\.\d{0,$iPrecision})?$";
|
||||
return "^[\-\+]?\d{1,$iNbIntegerDigits}(\.\d{0,$iPrecision})?$";
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function CheckFormat($value)
|
||||
{
|
||||
$sRegExp = $this->GetValidationPattern();
|
||||
return preg_match("/$sRegExp/", $value);
|
||||
}
|
||||
|
||||
public function GetBasicFilterOperators()
|
||||
@@ -3289,7 +3308,7 @@ class AttributeDecimal extends AttributeDBField
|
||||
|
||||
if (!is_null($value) && ($value !== ''))
|
||||
{
|
||||
$value = sprintf("%01.".$this->Get('decimals')."F", $value);
|
||||
$value = sprintf("%1.".$this->Get('decimals')."F", $value);
|
||||
}
|
||||
return $value; // null or string
|
||||
}
|
||||
@@ -3506,7 +3525,7 @@ class AttributeBoolean extends AttributeInteger
|
||||
$sProposedValue, $bLocalizedValue = false, $sSepItem = null, $sSepAttribute = null, $sSepValue = null,
|
||||
$sAttributeQualifier = null
|
||||
) {
|
||||
$sInput = strtolower(trim($sProposedValue));
|
||||
$sInput = mb_strtolower(trim($sProposedValue));
|
||||
if ($bLocalizedValue)
|
||||
{
|
||||
switch ($sInput)
|
||||
@@ -4531,7 +4550,6 @@ class AttributeText extends AttributeString
|
||||
$sStyle = '';
|
||||
if (count($aStyles) > 0)
|
||||
{
|
||||
$aStyles[] = 'overflow:auto';
|
||||
$sStyle = 'style="'.implode(';', $aStyles).'"';
|
||||
}
|
||||
|
||||
@@ -6511,32 +6529,46 @@ class AttributeDateTime extends AttributeDBField
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* @param int|DateTime|string $proposedValue possible values :
|
||||
* - timestamp ({@see DateTime::getTimestamp())
|
||||
* - {@see \DateTime} PHP object
|
||||
* - string, following the {@see GetInternalFormat} format.
|
||||
*
|
||||
* @throws \CoreUnexpectedValue if invalid value type or the string passed cannot be converted
|
||||
*/
|
||||
public function MakeRealValue($proposedValue, $oHostObj)
|
||||
{
|
||||
if (is_null($proposedValue))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
if (is_string($proposedValue) && ($proposedValue == "") && $this->IsNullAllowed())
|
||||
{
|
||||
return null;
|
||||
|
||||
if (is_numeric($proposedValue)) {
|
||||
return date(static::GetInternalFormat(), $proposedValue);
|
||||
}
|
||||
if (!is_numeric($proposedValue))
|
||||
{
|
||||
// Check the format
|
||||
try
|
||||
{
|
||||
$oFormat = new DateTimeFormat($this->GetInternalFormat());
|
||||
|
||||
if (is_object($proposedValue) && ($proposedValue instanceof DateTime)) {
|
||||
return $proposedValue->format(static::GetInternalFormat());
|
||||
}
|
||||
|
||||
if (is_string($proposedValue)) {
|
||||
if (($proposedValue === '') && $this->IsNullAllowed()) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
$oFormat = new DateTimeFormat(static::GetInternalFormat());
|
||||
$oFormat->Parse($proposedValue);
|
||||
} catch (Exception $e)
|
||||
{
|
||||
throw new Exception('Wrong format for date attribute '.$this->GetCode().', expecting "'.$this->GetInternalFormat().'" and got "'.$proposedValue.'"');
|
||||
} catch (Exception $e) {
|
||||
throw new CoreUnexpectedValue('Wrong format for date attribute '.$this->GetCode().', expecting "'.$this->GetInternalFormat().'" and got "'.$proposedValue.'"');
|
||||
}
|
||||
|
||||
return $proposedValue;
|
||||
}
|
||||
|
||||
return date(static::GetInternalFormat(), $proposedValue);
|
||||
throw new CoreUnexpectedValue('Wrong format for date attribute '.$this->GetCode());
|
||||
}
|
||||
|
||||
public function ScalarToSQL($value)
|
||||
@@ -8300,9 +8332,9 @@ class AttributeBlob extends AttributeDefinition
|
||||
}
|
||||
|
||||
/**
|
||||
* Users can provide the document from an URL (including an URL on iTop itself)
|
||||
* for CSV import. Administrators can even provide the path to a local file
|
||||
* {@inheritDoc}
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @param string $proposedValue Can be an URL (including an URL to iTop itself), or a local path (CSV import)
|
||||
*
|
||||
* @see AttributeDefinition::MakeRealValue()
|
||||
*/
|
||||
@@ -8543,7 +8575,7 @@ class AttributeBlob extends AttributeDefinition
|
||||
$sFingerprint = '';
|
||||
if ($value instanceOf ormDocument)
|
||||
{
|
||||
$sFingerprint = md5($value->GetData());
|
||||
$sFingerprint = $value->GetSignature();
|
||||
}
|
||||
|
||||
return $sFingerprint;
|
||||
@@ -8654,6 +8686,20 @@ class AttributeImage extends AttributeBlob
|
||||
parent::__construct($sCode, $aParams);
|
||||
}
|
||||
|
||||
public function Get($sParamName)
|
||||
{
|
||||
$oParamValue = parent::Get($sParamName);
|
||||
|
||||
if ($sParamName === 'default_image') {
|
||||
/** @noinspection NestedPositiveIfStatementsInspection */
|
||||
if (!empty($oParamValue)) {
|
||||
return utils::GetAbsoluteUrlModulesRoot() . $oParamValue;
|
||||
}
|
||||
}
|
||||
|
||||
return $oParamValue;
|
||||
}
|
||||
|
||||
public function GetEditClass()
|
||||
{
|
||||
return "Image";
|
||||
|
||||
@@ -35,11 +35,37 @@ abstract class CellChangeSpec
|
||||
return $this->m_proposedValue;
|
||||
}
|
||||
|
||||
public function GetDisplayableValue()
|
||||
/**
|
||||
* @throws \Exception
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function GetCLIValue(bool $bLocalizedValues = false): string
|
||||
{
|
||||
if (is_object($this->m_proposedValue)) {
|
||||
if ($this->m_proposedValue instanceof ReportValue) {
|
||||
return $this->m_proposedValue->GetAsCSV($bLocalizedValues, ',', '"');
|
||||
}
|
||||
throw new Exception('Unexpected class : '. get_class($this->m_proposedValue));
|
||||
}
|
||||
return $this->m_proposedValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function GetHTMLValue(bool $bLocalizedValues = false): string
|
||||
{
|
||||
if (is_object($this->m_proposedValue)) {
|
||||
if ($this->m_proposedValue instanceof ReportValue) {
|
||||
return $this->m_proposedValue->GetAsHTML($bLocalizedValues);
|
||||
}
|
||||
throw new Exception('Unexpected class : '. get_class($this->m_proposedValue));
|
||||
}
|
||||
return utils::EscapeHtml($this->m_proposedValue);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @since 3.1.0 N°5305
|
||||
*/
|
||||
@@ -54,12 +80,12 @@ abstract class CellChangeSpec
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 3.1.0 N°5305
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function GetDisplayableValueAndDescription(): string
|
||||
public function GetCLIValueAndDescription(): string
|
||||
{
|
||||
return sprintf("%s%s",
|
||||
$this->GetDisplayableValue(),
|
||||
$this->GetCLIValue(),
|
||||
$this->GetDescription()
|
||||
);
|
||||
}
|
||||
@@ -108,13 +134,25 @@ class CellStatus_Issue extends CellStatus_Modify
|
||||
parent::__construct($proposedValue, $previousValue);
|
||||
}
|
||||
|
||||
public function GetDisplayableValue()
|
||||
public function GetCLIValue(bool $bLocalizedValues = false): string
|
||||
{
|
||||
if (is_null($this->m_proposedValue)) {
|
||||
return Dict::Format('UI:CSVReport-Value-SetIssue');
|
||||
}
|
||||
return Dict::Format('UI:CSVReport-Value-ChangeIssue',$this->m_proposedValue);
|
||||
}
|
||||
|
||||
public function GetHTMLValue(bool $bLocalizedValues = false): string
|
||||
{
|
||||
if (is_null($this->m_proposedValue))
|
||||
{
|
||||
return Dict::Format('UI:CSVReport-Value-SetIssue');
|
||||
}
|
||||
return Dict::Format('UI:CSVReport-Value-ChangeIssue', \utils::EscapeHtml($this->m_proposedValue));
|
||||
if ($this->m_proposedValue instanceof ReportValue)
|
||||
{
|
||||
return Dict::Format('UI:CSVReport-Value-ChangeIssue', $this->m_proposedValue->GetAsHTML($bLocalizedValues));
|
||||
}
|
||||
return Dict::Format('UI:CSVReport-Value-ChangeIssue',utils::EscapeHtml($this->m_proposedValue));
|
||||
}
|
||||
|
||||
public function GetDescription()
|
||||
@@ -122,12 +160,12 @@ class CellStatus_Issue extends CellStatus_Modify
|
||||
return $this->m_sReason;
|
||||
}
|
||||
/*
|
||||
* @since 3.1.0 N°5305
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function GetDisplayableValueAndDescription(): string
|
||||
public function GetCLIValueAndDescription(): string
|
||||
{
|
||||
return sprintf("%s. %s",
|
||||
$this->GetDisplayableValue(),
|
||||
$this->GetCLIValue(),
|
||||
$this->GetDescription()
|
||||
);
|
||||
}
|
||||
@@ -163,7 +201,7 @@ class CellStatus_SearchIssue extends CellStatus_Issue
|
||||
* @param null $sAllowedValues : used for additional message that provides allowed values $sAllowedValues for current class
|
||||
* @param string|null $sAllowedValuesSearch : used to search all allowed values
|
||||
*/
|
||||
public function __construct($sSerializedSearch, $sReason, $sClass=null, $sAllowedValues=null, string $sAllowedValuesSearch=null)
|
||||
public function __construct($sSerializedSearch, $sReason, $sClass = null, $sAllowedValues = null, string $sAllowedValuesSearch = null)
|
||||
{
|
||||
parent::__construct(null, null, $sReason);
|
||||
$this->sSerializedSearch = $sSerializedSearch;
|
||||
@@ -172,7 +210,7 @@ class CellStatus_SearchIssue extends CellStatus_Issue
|
||||
$this->sAllowedValuesSearch = $sAllowedValuesSearch;
|
||||
}
|
||||
|
||||
public function GetDisplayableValue()
|
||||
public function GetCLIValue(bool $bLocalizedValues = false): string
|
||||
{
|
||||
if (null === $this->m_sReason) {
|
||||
return Dict::Format('UI:CSVReport-Value-NoMatch', '');
|
||||
@@ -181,6 +219,15 @@ class CellStatus_SearchIssue extends CellStatus_Issue
|
||||
return $this->m_sReason;
|
||||
}
|
||||
|
||||
public function GetHTMLValue(bool $bLocalizedValues = false): string
|
||||
{
|
||||
if (null === $this->m_sReason) {
|
||||
return Dict::Format('UI:CSVReport-Value-NoMatch', '');
|
||||
}
|
||||
|
||||
return utils::EscapeHtml($this->m_sReason);
|
||||
}
|
||||
|
||||
public function GetDescription()
|
||||
{
|
||||
if (\utils::IsNullOrEmptyString($this->m_sAllowedValues) ||
|
||||
@@ -198,7 +245,7 @@ class CellStatus_SearchIssue extends CellStatus_Issue
|
||||
public function GetSearchLinkUrl()
|
||||
{
|
||||
return sprintf("UI.php?operation=search&filter=%s",
|
||||
rawurlencode($this->sSerializedSearch)
|
||||
rawurlencode($this->sSerializedSearch ?? "")
|
||||
);
|
||||
}
|
||||
|
||||
@@ -209,7 +256,7 @@ class CellStatus_SearchIssue extends CellStatus_Issue
|
||||
public function GetAllowedValuesLinkUrl(): ?string
|
||||
{
|
||||
return sprintf("UI.php?operation=search&filter=%s",
|
||||
rawurlencode($this->sAllowedValuesSearch)
|
||||
rawurlencode($this->sAllowedValuesSearch ?? "")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -227,6 +274,33 @@ class CellStatus_NullIssue extends CellStatus_Issue
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Class to differ formatting depending on the caller
|
||||
*/
|
||||
class ReportValue
|
||||
{
|
||||
/**
|
||||
* @param DBObject $oObject
|
||||
* @param string $sAttCode
|
||||
* @param bool $bOriginal
|
||||
*/
|
||||
public function __construct(protected DBObject $oObject, protected string $sAttCode, protected bool $bOriginal){}
|
||||
|
||||
public function GetAsHTML(bool $bLocalizedValues)
|
||||
{
|
||||
if ($this->bOriginal) {
|
||||
return $this->oObject->GetOriginalAsHTML($this->sAttCode, $bLocalizedValues);
|
||||
}
|
||||
return $this->oObject->GetAsHTML($this->sAttCode, $bLocalizedValues);
|
||||
}
|
||||
public function GetAsCSV (bool $bLocalizedValues, string $sCsvSep, string $sCsvDelimiter) {
|
||||
if ($this->bOriginal) {
|
||||
return $this->oObject->GetOriginalAsCSV($this->sAttCode, $sCsvSep, $sCsvDelimiter, $bLocalizedValues);
|
||||
}
|
||||
return $this->oObject->GetAsCSV($this->sAttCode, $sCsvSep, $sCsvDelimiter, $bLocalizedValues);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class CellStatus_Ambiguous extends CellStatus_Issue
|
||||
{
|
||||
@@ -265,7 +339,7 @@ class CellStatus_Ambiguous extends CellStatus_Issue
|
||||
public function GetSearchLinkUrl()
|
||||
{
|
||||
return sprintf("UI.php?operation=search&filter=%s",
|
||||
rawurlencode($this->sSerializedSearch)
|
||||
rawurlencode($this->sSerializedSearch ?? "")
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -413,22 +487,6 @@ class BulkChange
|
||||
$this->m_aExtKeysMappingCache = array();
|
||||
}
|
||||
|
||||
protected $m_bReportHtml = false;
|
||||
protected $m_sReportCsvSep = ',';
|
||||
protected $m_sReportCsvDelimiter = '"';
|
||||
|
||||
public function SetReportHtml()
|
||||
{
|
||||
$this->m_bReportHtml = true;
|
||||
}
|
||||
|
||||
public function SetReportCsv($sSeparator = ',', $sDelimiter = '"')
|
||||
{
|
||||
$this->m_bReportHtml = false;
|
||||
$this->m_sReportCsvSep = $sSeparator;
|
||||
$this->m_sReportCsvDelimiter = $sDelimiter;
|
||||
}
|
||||
|
||||
protected function ResolveExternalKey($aRowData, $sAttCode, &$aResults)
|
||||
{
|
||||
$oExtKey = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
|
||||
@@ -446,7 +504,7 @@ class BulkChange
|
||||
$value = $oForeignAtt->MakeValueFromString($aRowData[$iCol], $this->m_bLocalizedValues);
|
||||
}
|
||||
$oReconFilter->AddCondition($sReconKeyAttCode, $value, '=');
|
||||
$aResults[$iCol] = new CellStatus_Void(utils::HtmlEntities($aRowData[$iCol]));
|
||||
$aResults[$iCol] = new CellStatus_Void($aRowData[$iCol]);
|
||||
}
|
||||
|
||||
$oExtObjects = new CMDBObjectSet($oReconFilter);
|
||||
@@ -470,7 +528,7 @@ class BulkChange
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \DBObject $oTargetObj
|
||||
* @param DBObject $oTargetObj
|
||||
* @param array $aRowData
|
||||
* @param array $aErrors
|
||||
*
|
||||
@@ -533,7 +591,7 @@ class BulkChange
|
||||
}
|
||||
$aCacheKeys[] = $value;
|
||||
$oReconFilter->AddCondition($sReconKeyAttCode, $value, '=');
|
||||
$aResults[$iCol] = new CellStatus_Void(utils::HtmlEntities($aRowData[$iCol]));
|
||||
$aResults[$iCol] = new CellStatus_Void($aRowData[$iCol]);
|
||||
}
|
||||
$sCacheKey = implode('_|_', $aCacheKeys); // Unique key for this query...
|
||||
$iForeignKey = null;
|
||||
@@ -602,7 +660,7 @@ class BulkChange
|
||||
foreach ($aReconKeys as $sReconKeyAttCode => $iCol)
|
||||
{
|
||||
// Report the change on reconciliation values as well
|
||||
$aResults[$iCol] = new CellStatus_Modify(utils::HtmlEntities($aRowData[$iCol]));
|
||||
$aResults[$iCol] = new CellStatus_Modify($aRowData[$iCol]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -680,50 +738,32 @@ class BulkChange
|
||||
// Reporting on fields
|
||||
//
|
||||
$aChangedFields = $oTargetObj->ListChanges();
|
||||
foreach ($this->m_aAttList as $sAttCode => $iCol)
|
||||
{
|
||||
if ($sAttCode == 'id')
|
||||
{
|
||||
$aResults[$iCol]= new CellStatus_Void(utils::HtmlEntities($aRowData[$iCol]));
|
||||
foreach ($this->m_aAttList as $sAttCode => $iCol) {
|
||||
if ($sAttCode == 'id') {
|
||||
$aResults[$iCol]= new CellStatus_Void($aRowData[$iCol]);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ($this->m_bReportHtml)
|
||||
{
|
||||
$sCurValue = $oTargetObj->GetAsHTML($sAttCode, $this->m_bLocalizedValues);
|
||||
$sOrigValue = $oTargetObj->GetOriginalAsHTML($sAttCode, $this->m_bLocalizedValues);
|
||||
else {
|
||||
$sCurValue = new ReportValue($oTargetObj, $sAttCode, false);
|
||||
$sOrigValue = new ReportValue($oTargetObj, $sAttCode, true);
|
||||
if (isset($aErrors[$sAttCode])) {
|
||||
$aResults[$iCol]= new CellStatus_Issue($aRowData[$iCol], $sOrigValue, $aErrors[$sAttCode]);
|
||||
}
|
||||
else
|
||||
{
|
||||
$sCurValue = $oTargetObj->GetAsCSV($sAttCode, $this->m_sReportCsvSep, $this->m_sReportCsvDelimiter, $this->m_bLocalizedValues);
|
||||
$sOrigValue = $oTargetObj->GetOriginalAsCSV($sAttCode, $this->m_sReportCsvSep, $this->m_sReportCsvDelimiter, $this->m_bLocalizedValues);
|
||||
}
|
||||
if (isset($aErrors[$sAttCode]))
|
||||
{
|
||||
$aResults[$iCol]= new CellStatus_Issue(utils::HtmlEntities($aRowData[$iCol]), $sOrigValue, $aErrors[$sAttCode]);
|
||||
}
|
||||
elseif (array_key_exists($sAttCode, $aChangedFields))
|
||||
{
|
||||
if ($oTargetObj->IsNew())
|
||||
{
|
||||
elseif (array_key_exists($sAttCode, $aChangedFields)){
|
||||
if ($oTargetObj->IsNew()) {
|
||||
$aResults[$iCol]= new CellStatus_Void($sCurValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
$aResults[$iCol]= new CellStatus_Modify($sCurValue, $sOrigValue);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
// By default... nothing happens
|
||||
$oAttDef = MetaModel::GetAttributeDef($this->m_sClass, $sAttCode);
|
||||
if ($oAttDef instanceof AttributeDateTime)
|
||||
{
|
||||
if ($oAttDef instanceof AttributeDateTime) {
|
||||
$aResults[$iCol]= new CellStatus_Void($oAttDef->GetFormat()->Format($aRowData[$iCol]));
|
||||
}
|
||||
else
|
||||
{
|
||||
$aResults[$iCol]= new CellStatus_Void(utils::HtmlEntities($aRowData[$iCol]));
|
||||
else {
|
||||
$aResults[$iCol]= new CellStatus_Void($aRowData[$iCol]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -788,7 +828,7 @@ class BulkChange
|
||||
// Possibles values are displayed to UI user. we have to limit the amount of displayed values
|
||||
$oExtObjectSetWithCurrentUserPermissions->SetLimit(4);
|
||||
for($i = 0; $i < 3; $i++){
|
||||
/** @var \DBObject $oVisibleObject */
|
||||
/** @var DBObject $oVisibleObject */
|
||||
$oVisibleObject = $oExtObjectSetWithCurrentUserPermissions->Fetch();
|
||||
if (is_null($oVisibleObject)){
|
||||
break;
|
||||
@@ -1155,7 +1195,7 @@ class BulkChange
|
||||
if (!preg_match($sRegExp, $sValue))
|
||||
{
|
||||
$aResult[$iRow]["__STATUS__"]= new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-DateFormat'));
|
||||
$aResult[$iRow][$iCol] = new CellStatus_Issue(utils::HtmlEntities($sValue), null, $sErrorMsg);
|
||||
$aResult[$iRow][$iCol] = new CellStatus_Issue($sValue, null, $sErrorMsg);
|
||||
|
||||
}
|
||||
else
|
||||
@@ -1168,6 +1208,7 @@ class BulkChange
|
||||
}
|
||||
else
|
||||
{
|
||||
// almost impossible ti reproduce since even incorrect dates with correct formats are formated and $oDate will not be false
|
||||
// Leave the cell unchanged
|
||||
$aResult[$iRow]["__STATUS__"]= new RowStatus_Issue(Dict::S('UI:CSVReport-Row-Issue-DateFormat'));
|
||||
$aResult[$iRow][$iCol] = new CellStatus_Issue($sValue, null, $sErrorMsg);
|
||||
@@ -1307,7 +1348,7 @@ class BulkChange
|
||||
{
|
||||
if (!array_key_exists($iCol, $aResult[$iRow]))
|
||||
{
|
||||
$aResult[$iRow][$iCol] = new CellStatus_Void(utils::HtmlEntities($aRowData[$iCol]));
|
||||
$aResult[$iRow][$iCol] = new CellStatus_Void($aRowData[$iCol]);
|
||||
}
|
||||
}
|
||||
foreach($this->m_aExtKeys as $sAttCode => $aForeignAtts)
|
||||
@@ -1321,7 +1362,7 @@ class BulkChange
|
||||
if (!array_key_exists($iCol, $aResult[$iRow]))
|
||||
{
|
||||
// The foreign attribute is one of our reconciliation key
|
||||
$aResult[$iRow][$iCol] = new CellStatus_Void(utils::HtmlEntities($aRowData[$iCol]));
|
||||
$aResult[$iRow][$iCol] = new CellStatus_Void($aRowData[$iCol]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1446,7 +1487,7 @@ EOF
|
||||
<<<EOF
|
||||
function OnTruncatedHistoryToggle(bShowAll)
|
||||
{
|
||||
$('#csv_history_reload').html('<img src="../images/indicator.gif"/>');
|
||||
$('#csv_history_reload').html('<img src="' + GetAbsoluteUrlAppRoot() + 'images/indicator.gif"/>');
|
||||
$.get(GetAbsoluteUrlAppRoot()+'pages/ajax.render.php?{$sAppContext}', {operation: 'displayCSVHistory', showall: bShowAll}, function(data)
|
||||
{
|
||||
$('#$sAjaxDivId').html(data);
|
||||
|
||||
@@ -335,7 +335,7 @@ abstract class CMDBObject extends DBObject
|
||||
$oMyChangeOp->Set("objclass", MetaModel::GetRootClass(get_class($this)));
|
||||
$oMyChangeOp->Set("objkey", $objkey);
|
||||
$oMyChangeOp->Set("fclass", get_class($this));
|
||||
$oMyChangeOp->Set("fname", substr($this->GetRawName(), 0, 255)); // Protect against very long friendly names
|
||||
$oMyChangeOp->SetTrim("fname", $this->GetRawName()); // Protect against very long friendly names
|
||||
$iId = $oMyChangeOp->DBInsertNoReload();
|
||||
}
|
||||
|
||||
|
||||
@@ -549,10 +549,9 @@ class CMDBSource
|
||||
/**
|
||||
* @param string $sSQLQuery
|
||||
*
|
||||
* @return \mysqli_result|null
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
* @throws \CoreException
|
||||
* @return mysqli_result|null
|
||||
* @throws MySQLException
|
||||
* @throws MySQLHasGoneAwayException
|
||||
*
|
||||
* @since 2.7.0 N°679 handles nested transactions
|
||||
*/
|
||||
|
||||
@@ -447,14 +447,14 @@ class Config
|
||||
'show_in_conf_sample' => true,
|
||||
],
|
||||
'export_pdf_font' => [ // @since 2.7.0 PR #49 / N°1947
|
||||
'type' => 'string',
|
||||
'description' => 'Font used when generating a PDF file',
|
||||
'default' => 'DejaVuSans', // DejaVuSans is a UTF-8 Unicode font, embedded in the TCPPDF lib we're using
|
||||
// Standard PDF fonts like helvetica or times newroman are NOT Unicode
|
||||
// A new DroidSansFallback can be used to improve CJK support (se PR #49)
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
'type' => 'string',
|
||||
'description' => 'Font used when generating a PDF file',
|
||||
'default' => 'DejaVuSans', // DejaVuSans is a UTF-8 Unicode font, embedded in the TCPPDF lib we're using
|
||||
// Standard PDF fonts like helvetica or times newroman are NOT Unicode
|
||||
// A new DroidSansFallback can be used to improve CJK support (se PR #49)
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'access_mode' => [
|
||||
'type' => 'integer',
|
||||
@@ -1119,6 +1119,14 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'purge_data.max_chunk_size' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Maximum number of items deleted per loop. Used in function MetaModel::PurgeData',
|
||||
'default' => 1000,
|
||||
'value' => 1000,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'max_history_length' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Maximum length of the history table (in the "History" tab on each object) before it gets truncated. Latest modifications are displayed first.',
|
||||
@@ -1324,9 +1332,9 @@ class Config
|
||||
'draft_attachments_lifetime' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Lifetime (in seconds) of drafts\' attachments and inline images: after this duration, the garbage collector will delete them.',
|
||||
'default' => 86400,
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'default' => 86400,
|
||||
'value' => '',
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'date_and_time_format' => [
|
||||
@@ -1611,6 +1619,14 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'notifications.itop.send_asynchronously' => [
|
||||
'type' => 'bool',
|
||||
'description' => 'If true then iTop notifications will be sent asynchronously',
|
||||
'default' => false,
|
||||
'value' => false,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'notifications.itop.newsroom_cache_time' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Duration in min between each fetch for notifications in newsroom',
|
||||
@@ -1619,6 +1635,14 @@ class Config
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'notifications.last_executions_days' => [
|
||||
'type' => 'integer',
|
||||
'description' => 'Number of days to display in the Action\'s last executions tab (0 means no limit)',
|
||||
'default' => 30 + 31, // 2 months
|
||||
'value' => 61,
|
||||
'source_of_value' => '',
|
||||
'show_in_conf_sample' => false,
|
||||
],
|
||||
'regenerate_session_id_enabled' => [
|
||||
'type' => 'bool',
|
||||
'description' => 'If true then session id will be regenerated on each login, to prevent session fixation.',
|
||||
@@ -1874,6 +1898,7 @@ class Config
|
||||
* @var integer Number of seconds between two reloads of the display (standard)
|
||||
*/
|
||||
protected $m_iStandardReloadInterval;
|
||||
|
||||
/**
|
||||
* @var integer Number of seconds between two reloads of the display (fast)
|
||||
*/
|
||||
@@ -2545,9 +2570,9 @@ class Config
|
||||
|
||||
// Old fashioned integer settings
|
||||
$aIntValues = array(
|
||||
'fast_reload_interval' => $this->m_iFastReloadInterval,
|
||||
'max_display_limit' => $this->m_iMaxDisplayLimit,
|
||||
'min_display_limit' => $this->m_iMinDisplayLimit,
|
||||
'fast_reload_interval' => $this->m_iFastReloadInterval,
|
||||
'max_display_limit' => $this->m_iMaxDisplayLimit,
|
||||
'min_display_limit' => $this->m_iMinDisplayLimit,
|
||||
'standard_reload_interval' => $this->m_iStandardReloadInterval,
|
||||
);
|
||||
foreach ($aIntValues as $sKey => $iValue)
|
||||
|
||||
@@ -1,6 +1,97 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<itop_design xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.2">
|
||||
<classes>
|
||||
<class id="lnkActionNotificationToContact" _delta="define">
|
||||
<parent>cmdbAbstractObject</parent>
|
||||
<properties>
|
||||
<category>core/cmdb,application</category>
|
||||
<abstract>false</abstract>
|
||||
<key_type>autoincrement</key_type>
|
||||
<db_table>priv_lnk_action_notif_to_contact</db_table>
|
||||
<db_key_field>id</db_key_field>
|
||||
<db_final_class_field/>
|
||||
<naming>
|
||||
<attributes>
|
||||
<attribute id="action_id"/>
|
||||
<attribute id="contact_id"/>
|
||||
</attributes>
|
||||
</naming>
|
||||
<uniqueness_rules>
|
||||
<rule>
|
||||
<attributes>
|
||||
<attribute id="action_id"/>
|
||||
<attribute id="contact_id"/>
|
||||
<attribute id="trigger_id"/>
|
||||
</attributes>
|
||||
<filter/>
|
||||
<disabled>false</disabled>
|
||||
<is_blocking>true</is_blocking>
|
||||
</rule>
|
||||
</uniqueness_rules>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="action_id" xsi:type="AttributeExternalKey">
|
||||
<sql>action_id</sql>
|
||||
<target_class>ActionNotification</target_class>
|
||||
<default_value/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
<field id="contact_id" xsi:type="AttributeExternalKey">
|
||||
<sql>contact_id</sql>
|
||||
<target_class>Contact</target_class>
|
||||
<default_value/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
<field id="trigger_id" xsi:type="AttributeExternalKey">
|
||||
<sql>trigger_id</sql>
|
||||
<target_class>Trigger</target_class>
|
||||
<default_value/>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
<field id="subscribed" xsi:type="AttributeBoolean">
|
||||
<sql>subscribed</sql>
|
||||
<default_value>true</default_value>
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
</fields>
|
||||
<presentation>
|
||||
<details>
|
||||
<items>
|
||||
<item id="col:col1">
|
||||
<items>
|
||||
<item id="fieldset:lnkActionNotificationToContact:content">
|
||||
<items>
|
||||
<item id="action_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="contact_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
<item id="title">
|
||||
<rank>30</rank>
|
||||
</item>
|
||||
</items>
|
||||
</item>
|
||||
</items>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
<list>
|
||||
<items>
|
||||
<item id="action_id">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="contact_id">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
<item id="title">
|
||||
<rank>30</rank>
|
||||
</item>
|
||||
</items>
|
||||
</list>
|
||||
</presentation>
|
||||
<methods/>
|
||||
</class>
|
||||
<class id="ActioniTopNotification" _delta="define">
|
||||
<php_parent>
|
||||
<name>ActionNotification</name>
|
||||
@@ -15,9 +106,12 @@
|
||||
<db_final_class_field/>
|
||||
<naming>
|
||||
<attributes>
|
||||
<attribute id="title"/>
|
||||
<attribute id="name"/>
|
||||
</attributes>
|
||||
</naming>
|
||||
<style>
|
||||
<icon>../../images/icons/icons8-notification.svg</icon>
|
||||
</style>
|
||||
</properties>
|
||||
<fields>
|
||||
<field id="title" xsi:type="AttributeString">
|
||||
@@ -38,7 +132,7 @@
|
||||
<display_max_height>96</display_max_height>
|
||||
<storage_max_width>256</storage_max_width>
|
||||
<storage_max_height>256</storage_max_height>
|
||||
<default_image>null</default_image>
|
||||
<default_image />
|
||||
</field>
|
||||
<field id="priority" xsi:type="AttributeEnum">
|
||||
<sql>priority</sql>
|
||||
@@ -94,6 +188,16 @@
|
||||
</item>
|
||||
</items>
|
||||
</item>
|
||||
<item id="fieldset:ActioniTopNotification:trigger">
|
||||
<items>
|
||||
<item id="trigger_list">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="asynchronous">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</item>
|
||||
</items>
|
||||
</item>
|
||||
<item id="col:col2">
|
||||
@@ -152,29 +256,62 @@
|
||||
<static>false</static>
|
||||
<access>public</access>
|
||||
<code><![CDATA[
|
||||
public function DoExecute($oTrigger, $aContextArgs)
|
||||
public function DoExecute($oTrigger, $aContextArgs)
|
||||
{
|
||||
$oRecipientsSearch = DBObjectSearch::FromOQL($this->Get('recipients'));
|
||||
$oRecipientsSearch->AllowAllData();
|
||||
$oRecipientsSet = new DBObjectSet($oRecipientsSearch);
|
||||
$oRecipientsSet = new DBObjectSet($oRecipientsSearch, array(), $aContextArgs);
|
||||
$bIsAsync = $this->IsAsynchronous();
|
||||
[$sPreviousLanguage, $aPreviousPluginProperties] = $this->SetNotificationLanguage();
|
||||
while ($oRecipient = $oRecipientsSet->Fetch()) {
|
||||
$oEvent = new EventiTopNotification();
|
||||
$oEvent->Set('title', MetaModel::ApplyParams($this->Get('title'), $aContextArgs));
|
||||
$oEvent->Set('message', MetaModel::ApplyParams($this->Get('message'), $aContextArgs));
|
||||
$oIcon = !$this->Get('icon')->IsEmpty() ? $this->Get('icon') : MetaModel::GetAttributeDef('EventiTopNotification', 'icon')->MakeRealValue(Combodo\iTop\Application\Branding::GetCompactMainLogoAbsoluteUrl(), $oEvent);
|
||||
$oEvent->Set('icon', $oIcon);
|
||||
$oEvent->Set('priority', $this->Get('priority'));
|
||||
$oEvent->Set('contact_id', $oRecipient->GetKey());
|
||||
$oEvent->Set('trigger_id', $oTrigger->GetKey());
|
||||
$oEvent->Set('action_id', $this->GetKey());
|
||||
$iObjectId = array_key_exists('this->object()', $aContextArgs) ? $aContextArgs['this->object()']->GetKey() : 0;
|
||||
$oEvent->Set('object_id', $iObjectId);
|
||||
$oEvent->Set('url', MetaModel::ApplyParams($this->Get('url'), $aContextArgs));
|
||||
$oEvent->DBInsertNoReload();
|
||||
|
||||
if($bIsAsync === true){
|
||||
$aRecipients = [];
|
||||
}
|
||||
|
||||
$sMessage = MetaModel::ApplyParams($this->Get('message'), $aContextArgs);
|
||||
$sTitle = MetaModel::ApplyParams($this->Get('title'), $aContextArgs);
|
||||
$sUrl = MetaModel::ApplyParams($this->Get('url'), $aContextArgs);
|
||||
$iObjectId = 0;
|
||||
$sObjectClass = null;
|
||||
if (array_key_exists('this->object()', $aContextArgs)) {
|
||||
$iObjectId = $aContextArgs['this->object()']->GetKey();
|
||||
$sObjectClass = get_class($aContextArgs['this->object()']);
|
||||
}
|
||||
|
||||
while ($oRecipient = $oRecipientsSet->Fetch()) {
|
||||
// Skip recipients that have no users
|
||||
if (get_class($oRecipient) === Person::class && UserRights::GetUserFromPerson($oRecipient) === null) {
|
||||
continue;
|
||||
}
|
||||
if (!\Combodo\iTop\Service\Notification\NotificationsService::GetInstance()->IsSubscribed($oTrigger, $this, $oRecipient)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if($bIsAsync === true) {
|
||||
$aRecipients[] = $oRecipient->GetKey();
|
||||
} else {
|
||||
$oEvent = Combodo\iTop\Service\Notification\Event\EventiTopNotificationService::MakeEventFromAction($this, $oRecipient->GetKey(), $oTrigger->GetKey(), $sMessage, $sTitle, $sUrl, $iObjectId, $sObjectClass);
|
||||
$oEvent->DBInsertNoReload();
|
||||
}
|
||||
|
||||
\Combodo\iTop\Service\Notification\NotificationsService::GetInstance()->RegisterSubscription($oTrigger, $this, $oRecipient);
|
||||
}
|
||||
if ($bIsAsync === true) {
|
||||
AsyncSendiTopNotifications::AddToQueue($this->GetKey(), $oTrigger->GetKey(), $aRecipients, $sMessage, $sTitle, $sUrl, $iObjectId, $sObjectClass);
|
||||
}
|
||||
$this->SetNotificationLanguage($sPreviousLanguage, $aPreviousPluginProperties['language_code'] ?? null);
|
||||
}
|
||||
]]></code>
|
||||
</method>
|
||||
<method id="GetAsynchronousGlobalSetting">
|
||||
<comment></comment>
|
||||
<static>true</static>
|
||||
<access>public</access>
|
||||
<code><![CDATA[
|
||||
public static function GetAsynchronousGlobalSetting(): bool
|
||||
{
|
||||
return utils::GetConfig()->Get('notifications.itop.send_asynchronously');
|
||||
}
|
||||
]]></code>
|
||||
</method>
|
||||
</methods>
|
||||
@@ -207,7 +344,7 @@
|
||||
<sql>icon</sql>
|
||||
<default_value/>
|
||||
<is_null_allowed>true</is_null_allowed>
|
||||
<default_image>null</default_image>
|
||||
<default_image />
|
||||
</field>
|
||||
<field id="priority" xsi:type="AttributeEnum">
|
||||
<sql>priority</sql>
|
||||
@@ -259,7 +396,46 @@
|
||||
<is_null_allowed>false</is_null_allowed>
|
||||
</field>
|
||||
</fields>
|
||||
<presentation/>
|
||||
<presentation>
|
||||
<details>
|
||||
<items>
|
||||
<item id="date">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="title">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
<item id="message">
|
||||
<rank>30</rank>
|
||||
</item>
|
||||
<item id="contact_id">
|
||||
<rank>40</rank>
|
||||
</item>
|
||||
<item id="trigger_id">
|
||||
<rank>50</rank>
|
||||
</item>
|
||||
<item id="action_id">
|
||||
<rank>60</rank>
|
||||
</item>
|
||||
<item id="read">
|
||||
<rank>70</rank>
|
||||
</item>
|
||||
<item id="url">
|
||||
<rank>80</rank>
|
||||
</item>
|
||||
</items>
|
||||
</details>
|
||||
<summary>
|
||||
<items>
|
||||
<item id="date">
|
||||
<rank>10</rank>
|
||||
</item>
|
||||
<item id="message">
|
||||
<rank>20</rank>
|
||||
</item>
|
||||
</items>
|
||||
</summary>
|
||||
</presentation>
|
||||
<methods/>
|
||||
</class>
|
||||
</classes>
|
||||
|
||||
@@ -210,6 +210,7 @@ abstract class DBObject implements iDisplay
|
||||
const MAX_UPDATE_LOOP_COUNT = 10;
|
||||
|
||||
private $aEventListeners = [];
|
||||
private array $aAllowedTransitions = [];
|
||||
|
||||
/**
|
||||
* DBObject constructor.
|
||||
@@ -608,11 +609,10 @@ abstract class DBObject implements iDisplay
|
||||
* Attributes setter
|
||||
*
|
||||
* Set $sAttCode to $value.
|
||||
* The value must be valid according to the type of attribute.
|
||||
* The value must be valid according to the type of attribute : see the different {@see AttributeDefinition::MakeRealValue()} implementations
|
||||
* The value will not be recorded into the DB until DBObject::DBWrite() is called.
|
||||
*
|
||||
* @api
|
||||
* @see DBWrite()
|
||||
*
|
||||
* @param string $sAttCode
|
||||
* @param mixed $value
|
||||
@@ -620,6 +620,8 @@ abstract class DBObject implements iDisplay
|
||||
* @return bool
|
||||
* @throws CoreException
|
||||
* @throws CoreUnexpectedValue
|
||||
*
|
||||
* @see DBWrite()
|
||||
*/
|
||||
public function Set($sAttCode, $value)
|
||||
{
|
||||
@@ -2317,16 +2319,17 @@ abstract class DBObject implements iDisplay
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aUniquenessRuleProperties uniqueness rule properties
|
||||
*
|
||||
* @param string $sUniquenessRuleId uniqueness rule ID
|
||||
* @return \DBSearch
|
||||
* @throws \OQLException
|
||||
* @throws \CoreException
|
||||
*
|
||||
* @internal
|
||||
*
|
||||
* @param string $sUniquenessRuleId uniqueness rule ID
|
||||
* @param array $aUniquenessRuleProperties uniqueness rule properties
|
||||
*
|
||||
* @return \DBSearch
|
||||
* @throws \CoreException
|
||||
* @throws \OQLException
|
||||
* @since 2.6.0 N°659 uniqueness constraint
|
||||
* @api
|
||||
* @since 2.6.0 N°659 uniqueness constraint
|
||||
* @since 2.7.11 3.1.2 3.2.0 N°4314 Fix Uniqueness rules not working with Silo
|
||||
*/
|
||||
protected function GetSearchForUniquenessRule($sUniquenessRuleId, $aUniquenessRuleProperties)
|
||||
{
|
||||
@@ -2355,6 +2358,8 @@ abstract class DBObject implements iDisplay
|
||||
$oUniquenessQuery->AddConditionForInOperatorUsingParam('finalclass', $aChildClassesWithRuleDisabled, false);
|
||||
}
|
||||
|
||||
$oUniquenessQuery->AllowAllData();
|
||||
|
||||
return $oUniquenessQuery;
|
||||
}
|
||||
|
||||
@@ -4401,9 +4406,32 @@ abstract class DBObject implements iDisplay
|
||||
]);
|
||||
}
|
||||
|
||||
$this->aAllowedTransitions = $aSortedTransitions;
|
||||
$this->FireEvent(EVENT_ENUM_TRANSITIONS, ['allowed_stimuli' => array_keys($aSortedTransitions)]);
|
||||
$aSortedTransitions = $this->aAllowedTransitions;
|
||||
$this->aAllowedTransitions = [];
|
||||
|
||||
return $aSortedTransitions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a transition for a specific stimulus.
|
||||
* This is only usable by EVENT_ENUM_TRANSITIONS listeners in order
|
||||
* to manage the allowed transitions in the current object state.
|
||||
*
|
||||
* @param string $sStimulus
|
||||
*
|
||||
* @return void
|
||||
* @api
|
||||
* @since 3.1.2
|
||||
*/
|
||||
public function DenyTransition(string $sStimulus): void
|
||||
{
|
||||
if (isset($this->aAllowedTransitions[$sStimulus])) {
|
||||
unset($this->aAllowedTransitions[$sStimulus]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to reset a stop-watch
|
||||
* Suitable for use as a lifecycle action
|
||||
@@ -4489,14 +4517,6 @@ abstract class DBObject implements iDisplay
|
||||
$sNewState = $aTransitionDef['target_state'];
|
||||
$this->Set($sStateAttCode, $sNewState);
|
||||
|
||||
$aEventData = [
|
||||
'stimulus' => $sStimulusCode,
|
||||
'previous_state' => $sPreviousState,
|
||||
'new_state' => $sNewState,
|
||||
'save_object' => !$bDoNotWrite,
|
||||
];
|
||||
$this->FireEvent(EVENT_DB_BEFORE_APPLY_STIMULUS, $aEventData);
|
||||
|
||||
// $aTransitionDef is an
|
||||
// array('target_state'=>..., 'actions'=>array of handlers procs, 'user_restriction'=>TBD
|
||||
|
||||
@@ -4581,8 +4601,6 @@ abstract class DBObject implements iDisplay
|
||||
if (!$bDoNotWrite) {
|
||||
$this->DBWrite();
|
||||
}
|
||||
|
||||
$this->FireEvent(EVENT_DB_AFTER_APPLY_STIMULUS, $aEventData);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -4591,8 +4609,6 @@ abstract class DBObject implements iDisplay
|
||||
{
|
||||
$this->m_aCurrValues[$sAttCode] = $aBackupValues[$sAttCode];
|
||||
}
|
||||
$aEventData['action'] = $sActionDesc;
|
||||
$this->FireEvent(EVENT_DB_APPLY_STIMULUS_FAILED, $aEventData);
|
||||
}
|
||||
return $bSuccess;
|
||||
}
|
||||
@@ -4729,7 +4745,7 @@ abstract class DBObject implements iDisplay
|
||||
}
|
||||
}
|
||||
$oDate->modify($sModifier);
|
||||
$this->Set($sAttCode, $oDate->format('Y-m-d H:i:s'));
|
||||
$this->Set($sAttCode, $oDate);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -5346,16 +5362,19 @@ abstract class DBObject implements iDisplay
|
||||
* @throws \MySQLException
|
||||
* @throws \MySQLHasGoneAwayException
|
||||
*/
|
||||
protected function GetReferencingObjects($bAllowAllData = false)
|
||||
protected function GetReferencingObjectsForDeletion($bAllowAllData = false)
|
||||
{
|
||||
$aDependentObjects = array();
|
||||
$aRererencingMe = MetaModel::EnumReferencingClasses(get_class($this));
|
||||
foreach($aRererencingMe as $sRemoteClass => $aExtKeys)
|
||||
{
|
||||
/** @var \AttributeExternalKey $oExtKeyAttDef */
|
||||
foreach($aExtKeys as $sExtKeyAttCode => $oExtKeyAttDef)
|
||||
{
|
||||
// skip if external key doesn't require the deletion cascading
|
||||
if($oExtKeyAttDef->GetDeletionPropagationOption() === DEL_NONE) continue;
|
||||
|
||||
// skip if this external key is behind an external field
|
||||
/** @var \AttributeDefinition $oExtKeyAttDef */
|
||||
if (!$oExtKeyAttDef->IsExternalKey(EXTKEY_ABSOLUTE)) continue;
|
||||
|
||||
$oSearch = new DBObjectSearch($sRemoteClass);
|
||||
@@ -5419,13 +5438,11 @@ abstract class DBObject implements iDisplay
|
||||
$this->CheckToWriteForTargetObjects(true);
|
||||
$oDeletionPlan->SetDeletionIssues($this, $this->m_aDeleteIssues, $this->m_bSecurityIssue);
|
||||
|
||||
$aDependentObjects = $this->GetReferencingObjects(true /* allow all data */);
|
||||
|
||||
// Getting and setting time limit are not symmetric:
|
||||
// www.php.net/manual/fr/function.set-time-limit.php#72305
|
||||
$iPreviousTimeLimit = ini_get('max_execution_time');
|
||||
|
||||
foreach ($aDependentObjects as $aPotentialDeletes)
|
||||
foreach ($this->GetReferencingObjectsForDeletion(true /* allow all data */) as $aPotentialDeletes)
|
||||
{
|
||||
foreach ($aPotentialDeletes as $aData)
|
||||
{
|
||||
|
||||
@@ -851,11 +851,11 @@ abstract class DBSearch
|
||||
return;
|
||||
}
|
||||
|
||||
if (count($aColumns) == 0)
|
||||
{
|
||||
$aColumns = array_keys(MetaModel::ListAttributeDefs($this->GetClass()));
|
||||
// Add the standard id (as first column)
|
||||
array_unshift($aColumns, 'id');
|
||||
if (count($aColumns) == 0)
|
||||
{
|
||||
$aColumns = array_keys(MetaModel::ListAttributeDefs($this->GetClass()));
|
||||
// Add the standard id (as first column)
|
||||
array_unshift($aColumns, 'id');
|
||||
}
|
||||
|
||||
$aQueryCols = CMDBSource::GetColumns($resQuery, $sSQL);
|
||||
@@ -885,6 +885,55 @@ abstract class DBSearch
|
||||
return $aRes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Selects a column ($sAttCode) from the specified class ($sClassAlias - default main class) of the DBsearch object and gives the result as an array
|
||||
* @param string $sAttCode
|
||||
* @param string|null $sClassAlias
|
||||
*
|
||||
* @return array
|
||||
* @throws ConfigException
|
||||
* @throws CoreException
|
||||
* @throws MissingQueryArgument
|
||||
* @throws MySQLException
|
||||
* @throws MySQLHasGoneAwayException
|
||||
*/
|
||||
public function SelectAttributeToArray(string $sAttCode, ?string $sClassAlias = null):array
|
||||
{
|
||||
if(is_null($sClassAlias)) {
|
||||
$sClassAlias = $this->GetClassAlias();
|
||||
}
|
||||
|
||||
$sClass = $this->GetClass();
|
||||
if($sAttCode === 'id'){
|
||||
$aAttToLoad[$sClassAlias]=[];
|
||||
} else {
|
||||
$aAttToLoad[$sClassAlias][$sAttCode] = MetaModel::GetAttributeDef($sClass, $sAttCode);
|
||||
}
|
||||
|
||||
$sSQL = $this->MakeSelectQuery([], [], $aAttToLoad);
|
||||
$resQuery = CMDBSource::Query($sSQL);
|
||||
if (!$resQuery)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
$sColName = $sClassAlias.$sAttCode;
|
||||
|
||||
$aRes = [];
|
||||
while ($aRow = CMDBSource::FetchArray($resQuery))
|
||||
{
|
||||
$aMappedRow = array();
|
||||
if($sAttCode === 'id') {
|
||||
$aMappedRow[$sAttCode] = $aRow[$sColName];
|
||||
} else {
|
||||
$aMappedRow[$sAttCode] = $aAttToLoad[$sClassAlias][$sAttCode]->FromSQLToValue($aRow, $sColName);
|
||||
}
|
||||
$aRes[] = $aMappedRow;
|
||||
}
|
||||
CMDBSource::FreeResult($resQuery);
|
||||
return $aRes;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Construction of the SQL queries
|
||||
|
||||
@@ -28,8 +28,13 @@ namespace Combodo\iTop;
|
||||
|
||||
use DOMDocument;
|
||||
use DOMFormatException;
|
||||
use DOMNode;
|
||||
use DOMNodeList;
|
||||
use DOMXPath;
|
||||
use Exception;
|
||||
use IssueLog;
|
||||
use LogAPI;
|
||||
use MFElement;
|
||||
use utils;
|
||||
|
||||
/**
|
||||
@@ -41,6 +46,11 @@ use utils;
|
||||
*/
|
||||
class DesignDocument extends DOMDocument
|
||||
{
|
||||
|
||||
/** To fix DOMNode::getLineNo() ref https://www.php.net/manual/en/domnode.getlineno.php */
|
||||
public const XML_PARSE_BIG_LINES = 4194304;
|
||||
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
@@ -64,16 +74,22 @@ class DesignDocument extends DOMDocument
|
||||
/**
|
||||
* Overload of the standard API
|
||||
*
|
||||
* @param $filename
|
||||
* @param string $filename
|
||||
* @param int $options
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function load($filename, $options = null)
|
||||
public function load(string $filename, int $options = 0): bool
|
||||
{
|
||||
libxml_clear_errors();
|
||||
if (parent::load($filename, LIBXML_NOBLANKS) === false) {
|
||||
$aErrors = libxml_get_errors();
|
||||
IssueLog::Error("Error loading $filename", LogAPI::CHANNEL_DEFAULT, $aErrors);
|
||||
if (is_file($filename)) {
|
||||
libxml_clear_errors();
|
||||
if (parent::load($filename, LIBXML_NOBLANKS | LIBXML_BIGLINES | LIBXML_PARSEHUGE | self::XML_PARSE_BIG_LINES) === false) {
|
||||
$aErrors = libxml_get_errors();
|
||||
IssueLog::Error("Error loading $filename", LogAPI::CHANNEL_DEFAULT, $aErrors);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -227,6 +243,56 @@ class DesignElement extends \DOMElement
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Compatibility with PHP8.0
|
||||
*
|
||||
* @return \DOMElement|null
|
||||
*
|
||||
* @since 3.1.2
|
||||
*/
|
||||
public function GetFirstElementChild()
|
||||
{
|
||||
if (property_exists($this, 'firstElementChild')) {
|
||||
return $this->firstElementChild;
|
||||
}
|
||||
|
||||
$oChildNode = $this->firstChild;
|
||||
while (!is_null($oChildNode)) {
|
||||
if ($oChildNode instanceof \DOMElement) {
|
||||
return $oChildNode;
|
||||
}
|
||||
$oChildNode = $oChildNode->nextSibling;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compatibility with PHP8.0
|
||||
*
|
||||
* @return \DOMElement|null
|
||||
*
|
||||
* @since 3.1.2
|
||||
*/
|
||||
public function GetNextElementSibling()
|
||||
{
|
||||
if (property_exists($this, 'nextElementSibling')) {
|
||||
return $this->nextElementSibling;
|
||||
}
|
||||
|
||||
$oSibling = $this->nextSibling;
|
||||
while (!is_null($oSibling)) {
|
||||
if ($oSibling instanceof \DOMElement) {
|
||||
return $oSibling;
|
||||
}
|
||||
$oSibling = $oSibling->nextSibling;
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the node directly under the given node
|
||||
* @param $sTagName
|
||||
@@ -307,4 +373,146 @@ class DesignElement extends \DOMElement
|
||||
}
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check that the current node is actually a class node, under classes
|
||||
* @since 3.1.2 3.2.0 N°6974
|
||||
*/
|
||||
public function IsClassNode(): bool
|
||||
{
|
||||
if ($this->tagName == 'class') {
|
||||
// Beware: classes/class also exists in the group definition
|
||||
if (($this->parentNode->tagName == 'classes') && ($this->parentNode->parentNode->tagName == 'itop_design')) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* True if the node is contained in a _delta="merge" tree
|
||||
* @return bool
|
||||
*/
|
||||
public function IsInSpecifiedMerge(): bool
|
||||
{
|
||||
// Iterate through the parents: reset the flag if any of them has a flag set
|
||||
for ($oParent = $this; $oParent instanceof MFElement; $oParent = $oParent->parentNode) {
|
||||
$sDeltaSpec = $oParent->getAttribute('_delta');
|
||||
if ($sDeltaSpec === 'merge') {
|
||||
return true;
|
||||
}
|
||||
if (in_array($sDeltaSpec, ['define', 'define_if_not_exists', 'force', 'redefine'])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the child node matching the given node.
|
||||
* UNSAFE: may return nodes marked as _alteration="removed"
|
||||
* A method with the same signature MUST exist in MFDocument for the recursion to work fine
|
||||
*
|
||||
* @param DesignElement $oRefNode The node to search for
|
||||
* @param null|string $sSearchId substitutes to the value of the 'id' attribute
|
||||
*
|
||||
* @return DesignElement|null
|
||||
* @throws \Exception
|
||||
* @since 3.1.2 3.2.0 N°6974
|
||||
*/
|
||||
public function _FindChildNode(DesignElement $oRefNode, $sSearchId = null): ?DesignElement
|
||||
{
|
||||
return self::_FindNode($this, $oRefNode, $sSearchId);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find the child node matching the given node.
|
||||
* UNSAFE: may return nodes marked as _alteration="removed"
|
||||
* A method with the same signature MUST exist in MFDocument for the recursion to work fine
|
||||
*
|
||||
* @param DesignElement $oRefNode The node to search for
|
||||
*
|
||||
* @return DesignElement|null
|
||||
* @throws \Exception
|
||||
* @since 3.1.2 3.2.0 N°6974
|
||||
*/
|
||||
public function _FindChildNodes(DesignElement $oRefNode): ?DesignElement
|
||||
{
|
||||
return self::_FindNodes($this, $oRefNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the child node matching the given node under the specified parent.
|
||||
* UNSAFE: may return nodes marked as _alteration="removed"
|
||||
*
|
||||
* @param \DOMNode $oParent
|
||||
* @param DesignElement $oRefNode
|
||||
* @param string|null $sSearchId
|
||||
*
|
||||
* @return DesignElement|null
|
||||
* @throws Exception
|
||||
* @since 3.1.2 3.2.0 N°6974
|
||||
*/
|
||||
public static function _FindNode(DOMNode $oParent, DesignElement $oRefNode, string $sSearchId = null): ?DesignElement
|
||||
{
|
||||
$oNodes = self::_FindNodes($oParent, $oRefNode, $sSearchId);
|
||||
if ($oNodes instanceof DOMNodeList) {
|
||||
/** @var DesignElement $oNode */
|
||||
$oNode = $oNodes->item(0);
|
||||
|
||||
return $oNode;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the child node matching the given node under the specified parent.
|
||||
* UNSAFE: may return nodes marked as _alteration="removed"
|
||||
*
|
||||
* @param \DOMNode $oParent
|
||||
* @param DesignElement $oRefNode
|
||||
* @param string|null $sSearchId
|
||||
*
|
||||
* @return \DOMNodeList|false|mixed
|
||||
* @since 3.1.2 3.2.0 N°6974
|
||||
*/
|
||||
public static function _FindNodes(DOMNode $oParent, DesignElement $oRefNode, string $sSearchId = null)
|
||||
{
|
||||
if ($oParent instanceof DOMDocument)
|
||||
{
|
||||
$oDoc = $oParent->firstChild->ownerDocument;
|
||||
$oRoot = $oParent;
|
||||
}
|
||||
else
|
||||
{
|
||||
$oDoc = $oParent->ownerDocument;
|
||||
$oRoot = $oParent;
|
||||
}
|
||||
|
||||
$oXPath = new DOMXPath($oDoc);
|
||||
if ($oRefNode->hasAttribute('id'))
|
||||
{
|
||||
// Find the elements having the same tag name and id
|
||||
if (!$sSearchId)
|
||||
{
|
||||
$sSearchId = $oRefNode->getAttribute('id');
|
||||
}
|
||||
$sXPath = './'.$oRefNode->tagName."[@id='$sSearchId']";
|
||||
|
||||
$oRes = $oXPath->query($sXPath, $oRoot);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get the elements having the same tag name
|
||||
$sXPath = './'.$oRefNode->tagName;
|
||||
|
||||
$oRes = $oXPath->query($sXPath, $oRoot);
|
||||
}
|
||||
|
||||
return $oRes;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,6 +37,7 @@ class DisplayableNode extends GraphNode
|
||||
{
|
||||
public $x;
|
||||
public $y;
|
||||
public bool $bFiltered;
|
||||
|
||||
/**
|
||||
* Create a new node inside a graph
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
//
|
||||
// You should have received a copy of the GNU Affero General Public License
|
||||
// along with iTop. If not, see <http://www.gnu.org/licenses/>
|
||||
use Masterminds\HTML5;
|
||||
|
||||
/**
|
||||
* Base class for all possible implementations of HTML Sanitization
|
||||
*/
|
||||
@@ -287,7 +289,7 @@ class HTMLDOMSanitizer extends DOMSanitizer
|
||||
'u' => array(),
|
||||
'em' => array(),
|
||||
'strong' => array(),
|
||||
'img' => array('src', 'style', 'alt', 'title'),
|
||||
'img' => array('src', 'style', 'alt', 'title', 'width', 'height'),
|
||||
'ul' => array('style'),
|
||||
'ol' => array('reversed', 'start', 'style', 'type'),
|
||||
'li' => array('style', 'value'),
|
||||
@@ -321,6 +323,8 @@ class HTMLDOMSanitizer extends DOMSanitizer
|
||||
'hr' => array('style'),
|
||||
'pre' => array(),
|
||||
'center' => array(),
|
||||
'figure' => array('class'), // Ckeditor 5 puts images in figures
|
||||
'mark' => array('class')
|
||||
);
|
||||
|
||||
protected static $aAttrsWhiteList = array(
|
||||
@@ -332,6 +336,7 @@ class HTMLDOMSanitizer extends DOMSanitizer
|
||||
* @see https://www.itophub.io/wiki/page?id=2_6_0%3Aadmin%3Arich_text_limitations
|
||||
*/
|
||||
protected static $aStylesWhiteList = array(
|
||||
'aspect-ratio',
|
||||
'background-color',
|
||||
'border',
|
||||
'border-collapse',
|
||||
|
||||
@@ -536,6 +536,11 @@ JS
|
||||
|
||||
$sAbsoluteUrlAppRoot = utils::GetAbsoluteUrlAppRoot();
|
||||
$sToggleFullScreen = utils::EscapeHtml(Dict::S('UI:ToggleFullScreen'));
|
||||
return <<<JS
|
||||
$('.htmlEditor').each(function() {
|
||||
CombodoCKEditorHandler.EnableImageUpload('#' + $(this).attr('id'), '$sAbsoluteUrlAppRoot'+'pages/ajax.render.php?operation=cke_img_upload&temp_id=$sTempId&obj_class=$sObjClass&obj_key=$iObjKey');
|
||||
});
|
||||
JS;
|
||||
|
||||
return
|
||||
<<<JS
|
||||
@@ -605,6 +610,13 @@ JS
|
||||
JS
|
||||
;
|
||||
}
|
||||
public static function EnableCKEditor5ImageUpload(DBObject $oObject, $sTempId){
|
||||
return <<<JS
|
||||
// Hook the file upload of all CKEditor instances
|
||||
JS;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
|
||||
@@ -575,6 +575,12 @@ class LogChannels
|
||||
*/
|
||||
public const DATATABLE = 'Datatable';
|
||||
|
||||
/**
|
||||
* @var string Everything related to the data integrity
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public const DATA_INTEGRITY = 'DataIntegrity';
|
||||
|
||||
public const DEADLOCK = 'DeadLock';
|
||||
/**
|
||||
* @var string Everything related to PHP sessions tracking
|
||||
@@ -1090,6 +1096,11 @@ class DeadLockLog extends LogAPI
|
||||
*/
|
||||
class DeprecatedCallsLog extends LogAPI
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
* @since 3.2.0 N°4897
|
||||
*/
|
||||
public const ENUM_CHANNEL_PHP_API = 'deprecated-php-api';
|
||||
public const ENUM_CHANNEL_PHP_METHOD = 'deprecated-php-method';
|
||||
/**
|
||||
* @var string
|
||||
@@ -1283,6 +1294,35 @@ class DeprecatedCallsLog extends LogAPI
|
||||
static::Warning($sMessage, static::ENUM_CHANNEL_FILE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sImplementationClass Class implementing the deprecated API
|
||||
* @param string $sDeprecatedApi Class name of the deprecated API
|
||||
* @param string $sDeprecatedMethod Method name of the deprecated API
|
||||
* @param string|null $sAdditionalMessage Additional message, mostly used to explain what API to use instead
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0 N°4897
|
||||
*/
|
||||
public static function NotifyDeprecatedPhpApi(string $sImplementationClass, string $sDeprecatedApi, string $sDeprecatedMethod, ?string $sAdditionalMessage = null): void
|
||||
{
|
||||
try {
|
||||
if (!static::IsLogLevelEnabled(self::LEVEL_WARNING, self::ENUM_CHANNEL_PHP_API)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (ConfigException $oException) {
|
||||
return;
|
||||
}
|
||||
|
||||
$sMessage = "Implementation of {$sDeprecatedApi}::{$sDeprecatedMethod}() in class {$sImplementationClass}";
|
||||
|
||||
if (!is_null($sAdditionalMessage)) {
|
||||
$sMessage .= " : $sAdditionalMessage";
|
||||
}
|
||||
|
||||
static::Warning($sMessage, self::ENUM_CHANNEL_PHP_API);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $sAdditionalMessage
|
||||
*
|
||||
@@ -1301,19 +1341,7 @@ class DeprecatedCallsLog extends LogAPI
|
||||
}
|
||||
|
||||
$aStack = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3);
|
||||
$iStackDeprecatedMethodLevel = 1; // level 0 = current method, level 1 = method containing the `NotifyDeprecatedPhpMethod` call
|
||||
$sDeprecatedObject = $aStack[$iStackDeprecatedMethodLevel]['class'];
|
||||
$sDeprecatedMethod = $aStack[$iStackDeprecatedMethodLevel]['function'];
|
||||
$sCallerFile = $aStack[$iStackDeprecatedMethodLevel]['file'];
|
||||
$sCallerLine = $aStack[$iStackDeprecatedMethodLevel]['line'];
|
||||
$sMessage = "Call to {$sDeprecatedObject}::{$sDeprecatedMethod} in {$sCallerFile}#L{$sCallerLine}";
|
||||
|
||||
$iStackCallerMethodLevel = $iStackDeprecatedMethodLevel + 1; // level 2 = caller of the deprecated method
|
||||
if (array_key_exists($iStackCallerMethodLevel, $aStack)) {
|
||||
$sCallerObject = $aStack[$iStackCallerMethodLevel]['class'];
|
||||
$sCallerMethod = $aStack[$iStackCallerMethodLevel]['function'];
|
||||
$sMessage .= " ({$sCallerObject}::{$sCallerMethod})";
|
||||
}
|
||||
$sMessage = self::GetMessageFromStack($aStack);
|
||||
|
||||
if (!is_null($sAdditionalMessage)) {
|
||||
$sMessage .= ' : '.$sAdditionalMessage;
|
||||
@@ -1322,6 +1350,45 @@ class DeprecatedCallsLog extends LogAPI
|
||||
static::Warning($sMessage, self::ENUM_CHANNEL_PHP_METHOD);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $aDebugBacktrace data from {@see debug_backtrace()}
|
||||
*
|
||||
* @return string message to print to the log
|
||||
*/
|
||||
private static function GetMessageFromStack(array $aDebugBacktrace): string
|
||||
{
|
||||
// level 0 = current method
|
||||
// level 1 = deprecated method, containing the `NotifyDeprecatedPhpMethod` call
|
||||
$sMessage = 'Call'.self::GetMessageForCurrentStackLevel($aDebugBacktrace[1], " to ");
|
||||
|
||||
// level 2 = caller of the deprecated method
|
||||
if (array_key_exists(2, $aDebugBacktrace)) {
|
||||
$sMessage .= ' (from ';
|
||||
$sMessage .= self::GetMessageForCurrentStackLevel($aDebugBacktrace[2]);
|
||||
$sMessage .= ')';
|
||||
}
|
||||
|
||||
return $sMessage;
|
||||
}
|
||||
|
||||
private static function GetMessageForCurrentStackLevel(array $aCurrentLevelDebugTrace, ?string $sPrefix = ""): string
|
||||
{
|
||||
$sMessage = "";
|
||||
if (array_key_exists('class', $aCurrentLevelDebugTrace)) {
|
||||
$sDeprecatedObject = $aCurrentLevelDebugTrace['class'];
|
||||
$sDeprecatedMethod = $aCurrentLevelDebugTrace['function'] ?? "";
|
||||
$sMessage = "{$sPrefix}{$sDeprecatedObject}::{$sDeprecatedMethod} in ";
|
||||
}
|
||||
|
||||
if (array_key_exists('file', $aCurrentLevelDebugTrace)) {
|
||||
$sCallerFile = $aCurrentLevelDebugTrace['file'];
|
||||
$sCallerLine = $aCurrentLevelDebugTrace['line'] ?? "";
|
||||
$sMessage .= "{$sCallerFile}#L{$sCallerLine}";
|
||||
}
|
||||
|
||||
return $sMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $sAdditionalMessage
|
||||
* @since 3.1.0
|
||||
|
||||
@@ -6846,18 +6846,6 @@ abstract class MetaModel
|
||||
$sClass = $aRow[$sClassAlias."finalclass"];
|
||||
}
|
||||
|
||||
// if an object is already being updated, then this method will return this object instead of recreating a new one.
|
||||
// At this point the method DBUpdate of a new object with the same class and id won't do anything due to reentrance protection,
|
||||
// so to ensure that the potential modifications are correctly saved, the object currently being updated is returned.
|
||||
// DBUpdate() method then will take care that all the modifications will be saved.
|
||||
if (array_key_exists($sClassAlias.'id', $aRow)) {
|
||||
$iKey = $aRow[$sClassAlias."id"];
|
||||
$oObject = self::GetReentranceObject($sClass, $iKey);
|
||||
if ($oObject !== false) {
|
||||
return $oObject;
|
||||
}
|
||||
}
|
||||
|
||||
return new $sClass($aRow, $sClassAlias, $aAttToLoad, $aExtendedDataSpec);
|
||||
}
|
||||
|
||||
@@ -7180,32 +7168,45 @@ abstract class MetaModel
|
||||
*/
|
||||
public static function PurgeData($oFilter)
|
||||
{
|
||||
$iMaxChunkSize = MetaModel::GetConfig()->Get('purge_data.max_chunk_size');
|
||||
$sTargetClass = $oFilter->GetClass();
|
||||
$oSet = new DBObjectSet($oFilter);
|
||||
$oSet->OptimizeColumnLoad(array($sTargetClass => array('finalclass')));
|
||||
$aIdToClass = $oSet->GetColumnAsArray('finalclass', true);
|
||||
$iNbIdsDeleted = 0;
|
||||
$bExecuteQuery = true;
|
||||
|
||||
$aIds = array_keys($aIdToClass);
|
||||
if (count($aIds) > 0)
|
||||
{
|
||||
$aQuotedIds = CMDBSource::Quote($aIds);
|
||||
$sIdList = implode(',', $aQuotedIds);
|
||||
$aTargetClasses = array_merge(
|
||||
self::EnumChildClasses($sTargetClass, ENUM_CHILD_CLASSES_ALL),
|
||||
self::EnumParentClasses($sTargetClass, ENUM_PARENT_CLASSES_EXCLUDELEAF)
|
||||
);
|
||||
foreach($aTargetClasses as $sSomeClass)
|
||||
{
|
||||
$sTable = MetaModel::DBGetTable($sSomeClass);
|
||||
$sPKField = MetaModel::DBGetKey($sSomeClass);
|
||||
// This loop allows you to delete objects in batches of $iMaxChunkSize elements
|
||||
while ($bExecuteQuery) {
|
||||
$oSet = new DBObjectSet($oFilter);
|
||||
$oSet->SetLimit($iMaxChunkSize);
|
||||
$oSet->OptimizeColumnLoad(array($sTargetClass => array('finalclass')));
|
||||
$aIdToClass = $oSet->GetColumnAsArray('finalclass', true);
|
||||
|
||||
$sDeleteSQL = "DELETE FROM `$sTable` WHERE `$sPKField` IN ($sIdList)";
|
||||
CMDBSource::DeleteFrom($sDeleteSQL);
|
||||
$aIds = array_keys($aIdToClass);
|
||||
$iNbIds = count($aIds);
|
||||
if ($iNbIds > 0) {
|
||||
$aQuotedIds = CMDBSource::Quote($aIds);
|
||||
$sIdList = implode(',', $aQuotedIds);
|
||||
$aTargetClasses = array_merge(
|
||||
self::EnumChildClasses($sTargetClass, ENUM_CHILD_CLASSES_ALL),
|
||||
self::EnumParentClasses($sTargetClass, ENUM_PARENT_CLASSES_EXCLUDELEAF)
|
||||
);
|
||||
foreach ($aTargetClasses as $sSomeClass) {
|
||||
$sTable = MetaModel::DBGetTable($sSomeClass);
|
||||
$sPKField = MetaModel::DBGetKey($sSomeClass);
|
||||
|
||||
$sDeleteSQL = "DELETE FROM `$sTable` WHERE `$sPKField` IN ($sIdList)";
|
||||
CMDBSource::DeleteFrom($sDeleteSQL);
|
||||
}
|
||||
$iNbIdsDeleted += $iNbIds;
|
||||
}
|
||||
|
||||
// stop loop if query returned fewer objects than $iMaxChunkSize. In this case, all objects have been deleted.
|
||||
if ($iNbIds < $iMaxChunkSize) {
|
||||
$bExecuteQuery = false;
|
||||
}
|
||||
}
|
||||
return count($aIds);
|
||||
}
|
||||
|
||||
return $iNbIdsDeleted;
|
||||
}
|
||||
// Links
|
||||
//
|
||||
//
|
||||
|
||||
@@ -739,7 +739,7 @@ class PHP_ParserGenerator
|
||||
while (isset($errmsg[$restart]) && $errmsg[$restart] == ' ') {
|
||||
$restart++;
|
||||
}
|
||||
printf("%s%.${end}s\n", $prefix, $errmsg);
|
||||
printf("%s%.{$end}s\n", $prefix, $errmsg);
|
||||
$errmsg = substr($errmsg, $restart);
|
||||
}
|
||||
}
|
||||
@@ -771,7 +771,7 @@ class PHP_ParserGenerator
|
||||
for ($j = $i; $j < $this->nsymbol; $j += $skip) {
|
||||
$sp = $this->symbols[$j];
|
||||
//assert( sp->index==j );
|
||||
printf(" %3d %-${maxlen}.${maxlen}s", $j, $sp->name);
|
||||
printf(" %3d %-{$maxlen}.{$maxlen}s", $j, $sp->name);
|
||||
}
|
||||
print "\n";
|
||||
}
|
||||
|
||||
@@ -231,19 +231,19 @@ class PHP_ParserGenerator_Action
|
||||
switch ($this->type)
|
||||
{
|
||||
case self::SHIFT:
|
||||
fprintf($fp, "%${indent}s shift %d", $this->sp->name, $this->x->statenum);
|
||||
fprintf($fp, "%{$indent}s shift %d", $this->sp->name, $this->x->statenum);
|
||||
break;
|
||||
case self::REDUCE:
|
||||
fprintf($fp, "%${indent}s reduce %d", $this->sp->name, $this->x->index);
|
||||
fprintf($fp, "%{$indent}s reduce %d", $this->sp->name, $this->x->index);
|
||||
break;
|
||||
case self::ACCEPT:
|
||||
fprintf($fp, "%${indent}s accept", $this->sp->name);
|
||||
fprintf($fp, "%{$indent}s accept", $this->sp->name);
|
||||
break;
|
||||
case self::ERROR:
|
||||
fprintf($fp, "%${indent}s error", $this->sp->name);
|
||||
fprintf($fp, "%{$indent}s error", $this->sp->name);
|
||||
break;
|
||||
case self::CONFLICT:
|
||||
fprintf($fp, "%${indent}s reduce %-3d ** Parsing conflict **", $this->sp->name, $this->x->index);
|
||||
fprintf($fp, "%{$indent}s reduce %-3d ** Parsing conflict **", $this->sp->name, $this->x->index);
|
||||
break;
|
||||
case self::SH_RESOLVED:
|
||||
case self::RD_RESOLVED:
|
||||
|
||||
@@ -170,7 +170,7 @@ class ormCaseLog {
|
||||
}
|
||||
|
||||
// Process the case of an eventual remainder (quick migration of AttributeText fields)
|
||||
if ($iPos < (strlen($this->m_sLog) - 1))
|
||||
if ($iPos < (utils::StrLen($this->m_sLog) - 1))
|
||||
{
|
||||
$sTextEntry = substr($this->m_sLog, $iPos);
|
||||
|
||||
@@ -293,7 +293,7 @@ class ormCaseLog {
|
||||
}
|
||||
|
||||
// Process the case of an eventual remainder (quick migration of AttributeText fields)
|
||||
if ($iPos < (strlen($this->m_sLog) - 1)) {
|
||||
if ($iPos < (utils::StrLen($this->m_sLog) - 1)) {
|
||||
$sTextEntry = substr($this->m_sLog, $iPos);
|
||||
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", utils::EscapeHtml($sTextEntry));
|
||||
|
||||
@@ -374,7 +374,7 @@ class ormCaseLog {
|
||||
}
|
||||
|
||||
// Process the case of an eventual remainder (quick migration of AttributeText fields)
|
||||
if ($iPos < (strlen($this->m_sLog) - 1)) {
|
||||
if ($iPos < (utils::StrLen($this->m_sLog) - 1)) {
|
||||
$sTextEntry = substr($this->m_sLog, $iPos);
|
||||
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", utils::EscapeHtml($sTextEntry));
|
||||
|
||||
@@ -468,7 +468,7 @@ class ormCaseLog {
|
||||
$oBlock->AddSubBlock($oCollapsibleBlock);
|
||||
}
|
||||
// Process the case of an eventual remainder (quick migration of AttributeText fields)
|
||||
if ($iPos < (strlen($this->m_sLog) - 1)) {
|
||||
if ($iPos < (utils::StrLen($this->m_sLog) - 1)) {
|
||||
// In this case the format is always "text"
|
||||
$sTextEntry = substr($this->m_sLog, $iPos);
|
||||
$sTextEntry = str_replace(array("\r\n", "\n", "\r"), "<br/>", utils::EscapeHtml($sTextEntry));
|
||||
@@ -516,7 +516,7 @@ class ormCaseLog {
|
||||
$sScript = '<script src="'.$sFileAbsUrl.'"></></script>';
|
||||
$sHtml .= $sScript;
|
||||
} else {
|
||||
$oP->add_linked_script($sFileAbsUrl);
|
||||
$oP->LinkScriptFromURI($sFileAbsUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,6 +344,6 @@ class ormDocument
|
||||
*/
|
||||
public function GetSignature(): string
|
||||
{
|
||||
return md5($this->GetData());
|
||||
return md5($this->GetData() ?? '');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -217,7 +217,7 @@ class ormStopWatch
|
||||
}
|
||||
else
|
||||
{
|
||||
$aProperties['Elapsed'] = 'running <img src="../images/indicator.gif">';
|
||||
$aProperties['Elapsed'] = 'running <img src="' . utils::GetAbsoluteUrlAppRoot() . 'images/indicator.gif">';
|
||||
}
|
||||
|
||||
$aProperties['Started'] = $oAttDef->SecondsToDate($this->iStarted);
|
||||
|
||||
@@ -53,9 +53,10 @@ abstract class Trigger extends cmdbAbstractObject
|
||||
MetaModel::Init_AddAttribute(new AttributeEnumSet("context", array("allowed_values" => null, "possible_values" => new ValueSetEnumPadded($aTags, true), "sql" => "context", "depends_on" => array(), "is_null_allowed" => true, "max_items" => 12)));
|
||||
// "complement" is a computed field, fed by Trigger sub-classes, in general in ComputeValues method, for eg. the TriggerOnObject fed it with target_class info
|
||||
MetaModel::Init_AddAttribute(new AttributeString("complement", array("allowed_values" => null, "sql" => "complement", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
MetaModel::Init_AddAttribute(new AttributeEnum("subscription_policy", array("allowed_values" => new ValueSetEnum(Combodo\iTop\Core\Trigger\Enum\SubscriptionPolicy::cases()), "sql" => "subscription_policy", "default_value" => \Combodo\iTop\Core\Trigger\Enum\SubscriptionPolicy::AllowNoChannel->value, "is_null_allowed" => false, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('finalclass', 'description', 'context', 'action_list', 'complement')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('finalclass', 'description', 'context', 'subscription_policy', 'action_list', 'complement')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'complement')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
// MetaModel::Init_SetZListItems('standard_search', array('name')); // Criteria of the std search form
|
||||
@@ -111,19 +112,31 @@ abstract class Trigger extends cmdbAbstractObject
|
||||
return;
|
||||
}
|
||||
|
||||
$aContextArgs['trigger->object()'] = $this;
|
||||
|
||||
// Find the related actions
|
||||
$oLinkedActions = $this->Get('action_list');
|
||||
while ($oLink = $oLinkedActions->Fetch())
|
||||
{
|
||||
/** @var \DBObject $oLink */
|
||||
$iActionId = $oLink->Get('action_id');
|
||||
/** @var \Action $oAction */
|
||||
$oAction = MetaModel::GetObject('Action', $iActionId);
|
||||
if ($oAction->IsActive())
|
||||
{
|
||||
$oKPI = new ExecutionKPI();
|
||||
$oAction->DoExecute($this, $aContextArgs);
|
||||
$oKPI->ComputeStatsForExtension($oAction, 'DoExecute');
|
||||
|
||||
// Order actions as expected
|
||||
$aActionListOrdered = [];
|
||||
while ($oLink = $oLinkedActions->Fetch()) {
|
||||
$aActionListOrdered[(int) $oLink->Get('order')][] = $oLink;
|
||||
}
|
||||
ksort($aActionListOrdered);
|
||||
|
||||
// Execute actions
|
||||
foreach ($aActionListOrdered as $aActionSubList) {
|
||||
foreach ($aActionSubList as $oLink) /** @var \DBObject $oLink */ {
|
||||
/** @var \DBObject $oLink */
|
||||
$iActionId = $oLink->Get('action_id');
|
||||
/** @var \Action $oAction */
|
||||
$oAction = MetaModel::GetObject('Action', $iActionId);
|
||||
if ($oAction->IsActive()) {
|
||||
$oKPI = new ExecutionKPI();
|
||||
$aContextArgs['action->object()'] = $oAction;
|
||||
$oAction->DoExecute($this, $aContextArgs);
|
||||
$oKPI->ComputeStatsForExtension($oAction, 'DoExecute');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -172,7 +185,7 @@ abstract class TriggerOnObject extends Trigger
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("filter", array("allowed_values" => null, "sql" => "filter", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class', 'description')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('default_search', array('description', 'target_class')); // Default criteria of the search banner
|
||||
@@ -372,7 +385,7 @@ class TriggerOnPortalUpdate extends TriggerOnObject
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class', 'description')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
}
|
||||
@@ -405,7 +418,7 @@ abstract class TriggerOnStateChange extends TriggerOnObject
|
||||
MetaModel::Init_AddAttribute(new AttributeClassState("state", array("class_field" => 'target_class', "allowed_values" => null, "sql" => "state", "default_value" => null, "is_null_allowed" => false, "depends_on" => array('target_class'))));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'state', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'state', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class', 'state')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class', 'state')); // Criteria of the std search form
|
||||
@@ -438,7 +451,7 @@ class TriggerOnStateEnter extends TriggerOnStateChange
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'state', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'state', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('target_class', 'state')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class', 'state')); // Criteria of the std search form
|
||||
@@ -471,7 +484,7 @@ class TriggerOnStateLeave extends TriggerOnStateChange
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'state', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'state', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('target_class', 'state')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class', 'state')); // Criteria of the std search form
|
||||
@@ -504,7 +517,7 @@ class TriggerOnObjectCreate extends TriggerOnObject
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
|
||||
@@ -537,7 +550,7 @@ class TriggerOnObjectDelete extends TriggerOnObject
|
||||
MetaModel::Init_InheritAttributes();
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
|
||||
@@ -572,7 +585,7 @@ class TriggerOnObjectUpdate extends TriggerOnObject
|
||||
MetaModel::Init_AddAttribute(new AttributeClassAttCodeSet('target_attcodes', array("allowed_values" => null, "class_field" => "target_class", "sql" => "target_attcodes", "default_value" => null, "is_null_allowed" => true, "max_items" => 20, "min_items" => 0, "attribute_definition_exclusion_list" => "AttributeDashboard,AttributeExternalField,AttributeFinalClass,AttributeFriendlyName,AttributeObsolescenceDate,AttributeObsolescenceFlag,AttributeSubItem", "attribute_definition_list" => null, "depends_on" => array('target_class'))));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'target_attcodes', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'target_attcodes', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
|
||||
@@ -668,7 +681,7 @@ class TriggerOnObjectMention extends TriggerOnObject
|
||||
MetaModel::Init_AddAttribute(new AttributeOQL("mentioned_filter", array("allowed_values" => null, "sql" => "mentioned_filter", "default_value" => null, "is_null_allowed" => true, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'mentioned_filter', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'filter', 'mentioned_filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('finalclass', 'target_class')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
|
||||
@@ -827,7 +840,7 @@ class TriggerOnThresholdReached extends TriggerOnObject
|
||||
MetaModel::Init_AddAttribute(new AttributeString("threshold_index", array("allowed_values" => null, "sql" => "threshold_index", "default_value" => null, "is_null_allowed" => false, "depends_on" => array())));
|
||||
|
||||
// Display lists
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'stop_watch_code', 'threshold_index', 'filter', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('details', array('description', 'context', 'target_class', 'stop_watch_code', 'threshold_index', 'filter', 'subscription_policy', 'action_list')); // Attributes to be displayed for the complete details
|
||||
MetaModel::Init_SetZListItems('list', array('target_class', 'threshold_index', 'threshold_index')); // Attributes to be displayed for a list
|
||||
// Search criteria
|
||||
MetaModel::Init_SetZListItems('standard_search', array('description', 'target_class')); // Criteria of the std search form
|
||||
|
||||
@@ -162,7 +162,7 @@ abstract class UserRightsAddOnAPI
|
||||
$oSearchSharers->AllowAllData();
|
||||
$oSearchSharers->AddCondition_ReferencedBy($oShareSearch, 'sharing_org_id');
|
||||
$aSharers = array();
|
||||
foreach($oSearchSharers->ToDataArray(array('id')) as $aRow)
|
||||
foreach($oSearchSharers->SelectAttributeToArray('id') as $aRow)
|
||||
{
|
||||
$aSharers[] = $aRow['id'];
|
||||
}
|
||||
@@ -187,7 +187,7 @@ abstract class UserRightsAddOnAPI
|
||||
$oOrgField = new FieldExpression('org_id', $sShareClass);
|
||||
$oSearchShares->AddConditionExpression(new BinaryExpression($oOrgField, 'IN', $oListExpr));
|
||||
$aShared = array();
|
||||
foreach($oSearchShares->ToDataArray(array($sShareAttCode)) as $aRow)
|
||||
foreach($oSearchShares->SelectAttributeToArray($sShareAttCode) as $aRow)
|
||||
{
|
||||
$aShared[] = $aRow[$sShareAttCode];
|
||||
}
|
||||
|
||||
@@ -476,6 +476,7 @@ class ValueSetEnum extends ValueSetDefinition
|
||||
* @param bool $bLocalizedSort
|
||||
*
|
||||
* @since 3.1.0 N°1646 Add $bLocalizedSort parameter
|
||||
* @since 3.2.0 N°7157 $Values can be an array of backed-enum cases
|
||||
*/
|
||||
public function __construct($Values, bool $bSortByValues = false)
|
||||
{
|
||||
@@ -523,13 +524,21 @@ class ValueSetEnum extends ValueSetDefinition
|
||||
*/
|
||||
protected function LoadValues($aArgs)
|
||||
{
|
||||
$aValues = [];
|
||||
if (is_array($this->m_values))
|
||||
{
|
||||
$aValues = $this->m_values;
|
||||
foreach ($this->m_values as $key => $value) {
|
||||
// Handle backed-enum case
|
||||
if (is_object($value) && enum_exists(get_class($value))) {
|
||||
$aValues[$value->value] = $value->value;
|
||||
continue;
|
||||
}
|
||||
|
||||
$aValues[$key] = $value;
|
||||
}
|
||||
}
|
||||
elseif (is_string($this->m_values) && strlen($this->m_values) > 0)
|
||||
{
|
||||
$aValues = array();
|
||||
foreach (explode(",", $this->m_values) as $sVal)
|
||||
{
|
||||
$sVal = trim($sVal);
|
||||
@@ -539,7 +548,7 @@ class ValueSetEnum extends ValueSetDefinition
|
||||
}
|
||||
else
|
||||
{
|
||||
$aValues = array();
|
||||
$aValues = [];
|
||||
}
|
||||
$this->m_aValues = $aValues;
|
||||
return true;
|
||||
|
||||
@@ -49,3 +49,63 @@
|
||||
.ibo-navigation-menu.ibo-is-active .ibo-navigation-menu--drawer{
|
||||
transform: translate3d(0,0,0);
|
||||
}
|
||||
|
||||
// Toggler legacy CSS that has somehow been added to iTop 3.0 and that is now used by some extensions
|
||||
// Round Toggle
|
||||
/* The switch - the box around the slider */
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 36px;
|
||||
height: 20px;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
/* Hide default HTML checkbox */
|
||||
.switch input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* The slider */
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: $ibo-color-secondary-600;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 15px;
|
||||
width: 15px;
|
||||
left: 3px;
|
||||
bottom: 3px;
|
||||
background-color: $ibo-color-secondary-300;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
input:checked + .slider {
|
||||
background-color: $ibo-color-primary-600;
|
||||
}
|
||||
|
||||
input:focus + .slider {
|
||||
box-shadow: 0 0 1px $ibo-color-primary-600;
|
||||
}
|
||||
|
||||
input:checked + .slider:before {
|
||||
transform: translateX(14.5px);
|
||||
}
|
||||
|
||||
/* Rounded sliders */
|
||||
.slider.round {
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.slider.round:before {
|
||||
border-radius: 7px;
|
||||
}
|
||||
|
||||
@@ -11,10 +11,6 @@ $ibo-scrollbar--scrollbar-thumb-background-color: $ibo-color-grey-300 !default;
|
||||
$ibo-scrollbar--scrollbar-thumb-border: none !default;
|
||||
$ibo-scrollbar--scrollbar-thumb-border-radius: $ibo-border-radius-500 !default;
|
||||
|
||||
$ibo-hyperlink-color: $ibo-color-primary-700 !default;
|
||||
$ibo-hyperlink-color--on-hover: $ibo-color-primary-800 !default;
|
||||
$ibo-hyperlink-color--on-active: $ibo-color-primary-900 !default;
|
||||
|
||||
$ibo-svg-illustration--fill: $ibo-color-primary-500 !default;
|
||||
|
||||
$ibo-content-block--background-color: $ibo-color-white-100 !default;
|
||||
@@ -29,10 +25,6 @@ $ibo-content-block--border: 1px solid $ibo-color-grey-400 !default;
|
||||
--ibo-scrollbar--scrollbar-thumb-background-color: #{$ibo-scrollbar--scrollbar-thumb-background-color};
|
||||
--ibo-scrollbar--scrollbar-thumb-border: #{$ibo-scrollbar--scrollbar-thumb-border};
|
||||
--ibo-scrollbar--scrollbar-thumb-border-radius: #{$ibo-scrollbar--scrollbar-thumb-border-radius};
|
||||
|
||||
--ibo-hyperlink-color: #{$ibo-hyperlink-color};
|
||||
--ibo-hyperlink-color--on-hover: #{$ibo-hyperlink-color--on-hover};
|
||||
--ibo-hyperlink-color--on-active: #{$ibo-hyperlink-color--on-active};
|
||||
}
|
||||
|
||||
/* Box sizing reset */
|
||||
@@ -73,17 +65,19 @@ html{
|
||||
/* Hyperlinks reset, ensure that they are of the right color and without decoration everywhere (of course this can be overloaded in some components) */
|
||||
a{
|
||||
color: var(--ibo-hyperlink-color);
|
||||
text-decoration: none;
|
||||
text-decoration: var(--ibo-hyperlink-text-decoration);
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
&:visited{
|
||||
text-decoration: none;
|
||||
text-decoration: var(--ibo-hyperlink-text-decoration);
|
||||
}
|
||||
&:hover{
|
||||
color: var(--ibo-hyperlink-color--on-hover);
|
||||
text-decoration: var(--ibo-hyperlink-text-decoration--on-hover);
|
||||
}
|
||||
&:active{
|
||||
color: var(--ibo-hyperlink-color--on-active);
|
||||
text-decoration: var(--ibo-hyperlink-text-decoration--on-active);
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,7 @@ $ibo-alert-colors: (
|
||||
$bg-color: nth($aColorValues, 1);
|
||||
$highlight-color: nth($aColorValues, 2);
|
||||
$text-color: nth($aColorValues, 3);
|
||||
.ibo-alert.ibo-is-#{$sColor} {
|
||||
%ibo-alert-#{$sColor}, .ibo-alert.ibo-is-#{$sColor} {
|
||||
background-color: $bg-color;
|
||||
color: $text-color;
|
||||
a {
|
||||
|
||||
@@ -32,4 +32,5 @@
|
||||
@import "search-form";
|
||||
@import "field-badge";
|
||||
@import "file-select";
|
||||
@import "medallion-icon";
|
||||
@import "medallion-icon";
|
||||
@import "toast";
|
||||
@@ -80,16 +80,29 @@ $ibo-field--enable-bulk--checkbox--margin-left: $ibo-spacing-300 !default;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*N°6543 - We need the rule to keep text inside the column when width is defined*/
|
||||
&[data-attribute-type="AttributeHtml"],
|
||||
&[data-attribute-type="AttributeText"] {
|
||||
&[data-attribute-flag-read-only="true"] {
|
||||
display: grid;
|
||||
|
||||
> .ibo-field--value {
|
||||
max-width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Large field = Label on top, value below */
|
||||
.ibo-field-large {
|
||||
display: block;
|
||||
/* Large field = Label on top, value below */
|
||||
.ibo-field-large {
|
||||
display: block;
|
||||
|
||||
.ibo-field--label {
|
||||
position: relative; /* Necessary for fullscreen toggler */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.ibo-field--label {
|
||||
position: relative; /* Necessary for fullscreen toggler */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
max-width: initial;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@@ -19,9 +19,19 @@ $ibo-navigation-menu--notifications--item--content--padding-x: 14px !default;
|
||||
$ibo-navigation-menu--notifications--item--content--img--max-height: 100px !default;
|
||||
$ibo-navigation-menu--notifications--item--content--img--padding: 5px !default;
|
||||
|
||||
$ibo-navigation-menu--notifications--item--new-message-indicator--width: 10px !default;
|
||||
$ibo-navigation-menu--notifications--item--new-message-indicator--height: 10px !default;
|
||||
$ibo-navigation-menu--notifications--item--new-message-indicator--background-color: $ibo-color-blue-500 !default;
|
||||
$ibo-navigation-menu--notifications--item--new-message-indicator--width: 13px !default;
|
||||
$ibo-navigation-menu--notifications--item--new-message-indicator--height: 13px !default;
|
||||
$ibo-navigation-menu--notifications--item--new-message-indicator--background-color: $ibo-color-white-100 !default;
|
||||
$ibo-navigation-menu--notifications--item--new-message-indicator--border: solid 2px $ibo-color-grey-500 !default;
|
||||
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-1--background-color: $ibo-color-red-100 !default;
|
||||
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-1--border: solid 2px $ibo-color-red-500 !default;
|
||||
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-2--background-color: $ibo-color-orange-100 !default;
|
||||
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-2--border: solid 2px $ibo-color-orange-500 !default;
|
||||
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-3--background-color: $ibo-color-blue-100 !default;
|
||||
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-3--border: solid 2px $ibo-color-blue-500 !default;
|
||||
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-4--background-color: $ibo-navigation-menu--notifications--item--new-message-indicator--background-color !default;
|
||||
$ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-4--border: $ibo-navigation-menu--notifications--item--new-message-indicator--border !default;
|
||||
|
||||
$ibo-navigation-menu--notifications--item--new-message-indicator--border-radius: $ibo-border-radius-full !default;
|
||||
$ibo-navigation-menu--notifications--item--new-message-indicator--margin-top: $ibo-spacing-200 !default;
|
||||
|
||||
@@ -36,31 +46,30 @@ $ibo-popover-menu--item--no-message--image--svg--padding : 15px !default;
|
||||
#ibo-navigation-menu--notifications-menu {
|
||||
flex-flow: column;
|
||||
min-width: $ibo-navigation-menu--notifications-menu--min-width;
|
||||
.ibo-navigation-menu--notifications--messages-section{
|
||||
.ibo-navigation-menu--notifications--messages-section {
|
||||
overflow: auto;
|
||||
}
|
||||
}
|
||||
.ibo-navigation-menu--notifications--show-all-messages, .ibo-navigation-menu--notifications-dismiss-all, .ibo-navigation-menu--notifications-show-all-multiple{
|
||||
.ibo-navigation-menu--notifications--show-all-messages, .ibo-navigation-menu--notifications-dismiss-all, .ibo-navigation-menu--notifications-show-all-multiple {
|
||||
overflow-x: inherit;
|
||||
text-align: center;
|
||||
min-height: 45px;
|
||||
}
|
||||
|
||||
.ibo-navigation-menu--notifications--item--image{
|
||||
.ibo-navigation-menu--notifications--item--image {
|
||||
max-width: $ibo-navigation-menu--notifications--item--image--max-width;
|
||||
max-height: $ibo-navigation-menu--notifications--item--image--max-height;
|
||||
margin: $ibo-navigation-menu--notifications--item--image--margin-y $ibo-navigation-menu--notifications--item--image--margin-x;
|
||||
border-radius: $ibo-navigation-menu--notifications--item--image--border-radius;
|
||||
}
|
||||
|
||||
img.ibo-navigation-menu--notifications--item--image[src=""]{
|
||||
.ibo-navigation-menu--notifications--item--image[src=""] {
|
||||
display: none;
|
||||
}
|
||||
img.ibo-navigation-menu--notifications--item--image:not([src=""]) ~ i.ibo-navigation-menu--notifications--item--image
|
||||
{
|
||||
.ibo-navigation-menu--notifications--item--image:not([src=""]) ~ .ibo-navigation-menu--notifications--item--image {
|
||||
display: none;
|
||||
}
|
||||
.ibo-navigation-menu--notifications--item--bottom-text{
|
||||
.ibo-navigation-menu--notifications--item--bottom-text {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
@@ -68,41 +77,63 @@ img.ibo-navigation-menu--notifications--item--image:not([src=""]) ~ i.ibo-naviga
|
||||
align-self: center;
|
||||
margin-left: $ibo-navigation-menu--notifications--item--bottom-text--margin-left;
|
||||
}
|
||||
.ibo-navigation-menu--notifications--item--content{
|
||||
.ibo-navigation-menu--notifications--item--content {
|
||||
padding: $ibo-navigation-menu--notifications--item--content--padding-y $ibo-navigation-menu--notifications--item--content--padding-x;
|
||||
img{
|
||||
|
||||
img {
|
||||
max-height: $ibo-navigation-menu--notifications--item--content--img--max-height;
|
||||
padding: $ibo-navigation-menu--notifications--item--content--img--padding;
|
||||
}
|
||||
}
|
||||
.ibo-navigation-menu--notifications-item{
|
||||
.ibo-navigation-menu--notifications-item {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
.ibo-navigation-menu--notifications--item--content a {
|
||||
@extend %ibo-hyperlink-forced-colors;
|
||||
}
|
||||
}
|
||||
.ibo-navigation-menu--notifications--item--new-message-indicator{
|
||||
.ibo-navigation-menu--notifications--item--new-message-indicator {
|
||||
width: $ibo-navigation-menu--notifications--item--new-message-indicator--width;
|
||||
height: $ibo-navigation-menu--notifications--item--new-message-indicator--height;
|
||||
background-color: $ibo-navigation-menu--notifications--item--new-message-indicator--background-color;
|
||||
border: $ibo-navigation-menu--notifications--item--new-message-indicator--border;
|
||||
border-radius: $ibo-navigation-menu--notifications--item--new-message-indicator--border-radius;
|
||||
margin-top: $ibo-navigation-menu--notifications--item--new-message-indicator--margin-top;
|
||||
&.ibo-is-priority-1{
|
||||
background-color: $ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-1--background-color;
|
||||
border: $ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-1--border;
|
||||
}
|
||||
&.ibo-is-priority-2{
|
||||
background-color: $ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-2--background-color;
|
||||
border: $ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-2--border;
|
||||
}
|
||||
&.ibo-is-priority-3{
|
||||
background-color: $ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-3--background-color;
|
||||
border: $ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-3--border;
|
||||
}
|
||||
&.ibo-is-priority-4{
|
||||
background-color: $ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-4--background-color;
|
||||
border: $ibo-navigation-menu--notifications--item--new-message-indicator--is-priority-4--border;
|
||||
}
|
||||
}
|
||||
|
||||
.ibo-navigation-menu--notifications-show-all-multiple ~ .ibo-popover-menu{
|
||||
.ibo-navigation-menu--notifications--item--new-message-indicator{
|
||||
.ibo-navigation-menu--notifications-show-all-multiple ~ .ibo-popover-menu {
|
||||
.ibo-navigation-menu--notifications--item--new-message-indicator {
|
||||
display: inline-block;
|
||||
margin-right: $ibo-navigation-menu--notifications-show-all-multiple--ibo-popover-menu--indicator--margin-right;
|
||||
}
|
||||
.ibo-navigation-menu--notifications-show-all-multiple--counter{
|
||||
.ibo-navigation-menu--notifications-show-all-multiple--counter {
|
||||
@extend %ibo-font-weight-600;
|
||||
}
|
||||
}
|
||||
.ibo-navigation-menu--notifications-dismiss-all--icon{
|
||||
.ibo-navigation-menu--notifications-dismiss-all--icon {
|
||||
margin: $ibo-navigation-menu--notifications-dismiss-all--icon--margin;
|
||||
}
|
||||
.ibo-popover-menu--item--no-message{
|
||||
.ibo-popover-menu--item--no-message {
|
||||
text-align: center;
|
||||
}
|
||||
.ibo-popover-menu--item--no-message--image>svg{
|
||||
.ibo-popover-menu--item--no-message--image > svg {
|
||||
display: flex;
|
||||
width: $ibo-popover-menu--item--no-message--image--svg--width;
|
||||
height: $ibo-popover-menu--item--no-message--image--svg--height;
|
||||
|
||||
@@ -85,6 +85,9 @@ $ibo-panel--collapsible-toggler--margin-right: $ibo-spacing-300 !default;
|
||||
$ibo-panel--collapsible-toggler--font-size: $ibo-font-size-250 !default;
|
||||
$ibo-panel--collapsible-toggler--color: $ibo-color-grey-700 !default;
|
||||
|
||||
$ibo-panel--is-selectable--body--after--z-index: $ibo-panel--header--z-index + 1 !default;
|
||||
$ibo-panel--is-selectable--body--after--font-size: $ibo-font-size-700 !default;
|
||||
|
||||
/* Rules */
|
||||
.ibo-panel {
|
||||
--ibo-main-color: #{map-get($ibo-panel-colors, 'neutral')}; /* --ibo-main-color is to allow overload from custom dynamic value from the DM. The overload will be done through an additional CSS class of a particular DM class or DM attribute */
|
||||
@@ -128,6 +131,30 @@ $ibo-panel--collapsible-toggler--color: $ibo-color-grey-700 !default;
|
||||
}
|
||||
}
|
||||
}
|
||||
&.ibo-is-selectable .ibo-panel--body::after {
|
||||
@include ibo-selectable;
|
||||
position: absolute;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
z-index: $ibo-panel--is-selectable--body--after--z-index;
|
||||
font-size: $ibo-panel--is-selectable--body--after--font-size;
|
||||
}
|
||||
&.ibo-is-selectable:hover .ibo-panel--body::after {
|
||||
@include ibo-selectable-hover;
|
||||
display: flex;
|
||||
}
|
||||
&.ibo-is-selected .ibo-panel--body::after {
|
||||
@include ibo-selected;
|
||||
display: flex;
|
||||
}
|
||||
&.ibo-is-selected:hover .ibo-panel--body::after {
|
||||
@include ibo-selected-hover;
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.ibo-panel--header {
|
||||
|
||||
62
css/backoffice/components/_toast.scss
Normal file
62
css/backoffice/components/_toast.scss
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/* SCSS variables */
|
||||
$ibo-toast--padding-y: $ibo-spacing-400 !default;
|
||||
$ibo-toast--padding-right: $ibo-spacing-300 !default;
|
||||
$ibo-toast--padding-left: $ibo-spacing-500 !default;
|
||||
$ibo-toast--border-radius: $ibo-border-radius-300 !default;
|
||||
$ibo-toast--box-shadow: $ibo-elevation-200 !default;
|
||||
$ibo-toast--max-width: calc(50% - 20px) !default;
|
||||
|
||||
@keyframes decreaseHighlight {
|
||||
0% {
|
||||
height: 100%;
|
||||
}
|
||||
8%{
|
||||
border-radius: 0 0 0 3px;
|
||||
}
|
||||
100% {
|
||||
height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.ibo-toast {
|
||||
display: inline-flex;
|
||||
position: fixed;
|
||||
align-items: center;
|
||||
|
||||
max-width: $ibo-toast--max-width ;
|
||||
padding: $ibo-toast--padding-y $ibo-toast--padding-right $ibo-toast--padding-y $ibo-toast--padding-left;
|
||||
border-radius: $ibo-toast--border-radius;
|
||||
|
||||
box-shadow: $ibo-toast--box-shadow;
|
||||
transition: all 0.4s cubic-bezier(0.215, 0.61, 0.355, 1);
|
||||
z-index: 2147483647;
|
||||
&::before {
|
||||
@include ibo-vertical-highlight;
|
||||
top: initial;
|
||||
bottom: 0;
|
||||
border-radius: $ibo-toast--border-radius 0 0 $ibo-toast--border-radius;
|
||||
}
|
||||
&.ibo-is-auto-closeable::before{
|
||||
animation: decreaseHighlight 5s linear forwards;
|
||||
}
|
||||
&:hover::before {
|
||||
animation: none; /* Pause animation on hover */
|
||||
}
|
||||
&.ibo-is-error{
|
||||
@extend %ibo-alert-danger;
|
||||
}
|
||||
&.ibo-is-warning{
|
||||
@extend %ibo-alert-warning;
|
||||
}
|
||||
&.ibo-is-success{
|
||||
@extend %ibo-alert-success;
|
||||
}
|
||||
&.ibo-is-information{
|
||||
@extend %ibo-alert-information;
|
||||
}
|
||||
}
|
||||
@@ -123,6 +123,13 @@ $ibo-fieldsorter--selected--background-color: $ibo-color-blue-200 !default;
|
||||
.ibo-datatable--row-actions-toolbar{
|
||||
justify-content: end;
|
||||
}
|
||||
/* N°6543 - We need the rule to keep text inside the column when width is defined */
|
||||
> [data-attribute-type="AttributeHtml"],
|
||||
> [data-attribute-type="AttributeText"] {
|
||||
max-width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,9 @@ $ibo-datatableconfig--settings-panel--option--margin-right: $ibo-spacing-200 !de
|
||||
}
|
||||
.ibo-datatableconfig--attributes-panel--per-page--input{
|
||||
margin: $ibo-datatableconfig--attributes-panel--per-page--input--margin-y $ibo-datatableconfig--attributes-panel--per-page--input--margin-x;
|
||||
max-width: 4em;
|
||||
@extend .ibo-input;
|
||||
display: initial;
|
||||
}
|
||||
|
||||
.ibo-datatableconfig--settings-panel .ibo-panel--body{
|
||||
|
||||
@@ -16,3 +16,4 @@
|
||||
@import "input-one-way-password";
|
||||
@import "input-set";
|
||||
@import "input-text";
|
||||
@import "input-toggler";
|
||||
|
||||
@@ -49,10 +49,7 @@ $ibo-input-select--autocomplete-item-image--border: 1px solid $ibo-color-grey-60
|
||||
.ibo-input-select {
|
||||
display: inline-flex;
|
||||
min-width: $ibo-input-select--value--min-midth;
|
||||
|
||||
&:not(.ibo-input-select-autocomplete):not(.ibo-input-selectize) {
|
||||
appearance: none;
|
||||
}
|
||||
appearance: none;
|
||||
|
||||
&.ibo-input-selectize {
|
||||
padding-right: 0;
|
||||
@@ -108,7 +105,7 @@ $ibo-input-select--autocomplete-item-image--border: 1px solid $ibo-color-grey-60
|
||||
outline: none !important; /* Overwrite browsers default focus outline */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
&.input-active{
|
||||
border: 1px solid $ibo-input--focus--border-color;
|
||||
}
|
||||
@@ -123,15 +120,16 @@ $ibo-input-select--autocomplete-item-image--border: 1px solid $ibo-color-grey-60
|
||||
}
|
||||
.ibo-input-select-wrapper::after{
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
content: "\f0d7";
|
||||
font-family: "Font Awesome 5 Free";
|
||||
font-weight: 600;
|
||||
|
||||
|
||||
height: $ibo-input-select-wrapper--after--height;
|
||||
margin-left: $ibo-input-select-wrapper--after--margin-left;
|
||||
margin-top: $ibo-input-select-wrapper--after--margin-top;
|
||||
padding-top: $ibo-input-select-wrapper--after--padding-top;
|
||||
|
||||
|
||||
background-color: $ibo-input-select-wrapper--after--background-color;
|
||||
color: $ibo-input-select-wrapper--after--color;
|
||||
pointer-events: none;
|
||||
@@ -146,6 +144,7 @@ $ibo-input-select--autocomplete-item-image--border: 1px solid $ibo-color-grey-60
|
||||
|
||||
.ibo-input-select-wrapper--with-buttons:not(.ibo-input-select-autocomplete-wrapper)::after {
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
content: "\f0d7";
|
||||
font-family: "Font Awesome 5 Free";
|
||||
font-weight: 600;
|
||||
@@ -163,6 +162,7 @@ $ibo-input-select--autocomplete-item-image--border: 1px solid $ibo-color-grey-60
|
||||
}
|
||||
.ibo-input-select--action-buttons{
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
display: flex;
|
||||
height: $ibo-input-select--action-button--height;
|
||||
margin-top: $ibo-input-select--action-button--margin-top;
|
||||
@@ -224,7 +224,11 @@ $ibo-input-select--autocomplete-item-image--border: 1px solid $ibo-color-grey-60
|
||||
margin-right: $ibo-input-select--autocomplete-item-image--margin-right;
|
||||
background-color: $ibo-input-select--autocomplete-item-image--background-color;
|
||||
border: $ibo-input-select--autocomplete-item-image--border;
|
||||
|
||||
&.ibo-is-not-medallion{
|
||||
border: unset;
|
||||
border-radius: 0;
|
||||
background-color: unset;
|
||||
}
|
||||
@extend %ibo-fully-centered-content;
|
||||
}
|
||||
|
||||
|
||||
72
css/backoffice/components/input/_input-toggler.scss
Normal file
72
css/backoffice/components/input/_input-toggler.scss
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
$ibo-toggler--wrapper--width: 36px !default;
|
||||
$ibo-toggler--wrapper--height: 20px !default;
|
||||
|
||||
$ibo-toggler--slider--border-radius: $ibo-border-radius-900 !default;
|
||||
$ibo-toggler--slider--background-color: $ibo-color-secondary-600 !default;
|
||||
|
||||
$ibo-toggler--slider--before--height: 15px !default;
|
||||
$ibo-toggler--slider--before--width: 15px !default;
|
||||
$ibo-toggler--slider--before--border-radius: $ibo-border-radius-full !default;
|
||||
$ibo-toggler--slider--before--background-color: $ibo-color-grey-100 !default;
|
||||
|
||||
$ibo-toggler--slider--checked--background-color: $ibo-color-primary-600 !default;
|
||||
$ibo-toggler--slider--focus--box-shadow: 0 0 1px $ibo-color-primary-600 !default;
|
||||
|
||||
$ibo-toggler--label--margin-left: 4px !default;
|
||||
|
||||
|
||||
.ibo-toggler--wrapper {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: $ibo-toggler--wrapper--width;
|
||||
height: $ibo-toggler--wrapper--height;
|
||||
vertical-align: baseline;
|
||||
.ibo-toggler {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.ibo-toggler--slider{
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
border-radius: $ibo-toggler--slider--border-radius;
|
||||
background-color: $ibo-toggler--slider--background-color;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
.ibo-toggler--slider:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
left: 3px;
|
||||
bottom: 3px;
|
||||
height: $ibo-toggler--slider--before--height;
|
||||
width: $ibo-toggler--slider--before--width;
|
||||
border-radius: $ibo-toggler--slider--before--border-radius;
|
||||
background-color: $ibo-toggler--slider--before--background-color;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
.ibo-toggler--wrapper input:checked + .ibo-toggler--slider {
|
||||
background-color: $ibo-toggler--slider--checked--background-color;
|
||||
}
|
||||
|
||||
input:focus + .ibo-toggler--slider {
|
||||
box-shadow: $ibo-toggler--slider--focus--box-shadow;
|
||||
}
|
||||
|
||||
input:checked + .ibo-toggler--slider:before {
|
||||
transform: translateX(14.5px);
|
||||
}
|
||||
|
||||
label ~ .ibo-toggler--wrapper {
|
||||
margin-left: $ibo-toggler--label--margin-left;
|
||||
}
|
||||
@@ -8,7 +8,11 @@ $ibo-input--width: 100% !default;
|
||||
|
||||
$ibo-input--color: $ibo-color-grey-900 !default;
|
||||
$ibo-input--background-color: $ibo-color-white-100 !default;
|
||||
|
||||
$ibo-input--border-color: $ibo-color-grey-500 !default;
|
||||
$ibo-input--border-size: 1px !default;
|
||||
$ibo-input--border-style: solid !default;
|
||||
$ibo-input--border: $ibo-input--border-size $ibo-input--border-style $ibo-input--border-color !default;
|
||||
|
||||
$ibo-input--padding-x: 10px !default;
|
||||
$ibo-input--padding-y: $ibo-spacing-0 !default;
|
||||
@@ -34,13 +38,13 @@ $ibo-input--margin-x: $ibo-spacing-200 !default;
|
||||
background-color: $ibo-input--background-color;
|
||||
color: $ibo-input--color;
|
||||
padding: $ibo-input--padding-y $ibo-input--padding-x;
|
||||
border: 1px solid $ibo-input--border-color;
|
||||
border: $ibo-input--border;
|
||||
border-radius: $ibo-input--border-radius;
|
||||
|
||||
@extend %ibo-font-ral-nor-150;
|
||||
|
||||
&:focus{
|
||||
border: 1px solid $ibo-input--focus--border-color;
|
||||
border-color: $ibo-input--focus--border-color;
|
||||
}
|
||||
&:disabled{
|
||||
background-color: $ibo-input--disabled--background-color;
|
||||
@@ -54,8 +58,8 @@ textarea.ibo-input{
|
||||
height:unset;
|
||||
}
|
||||
.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;
|
||||
.ibo-input, .ibo-input-vanilla, .ck-editor, textarea {
|
||||
border-color: $ibo-input-wrapper--is-error--border-color;
|
||||
}
|
||||
.ibo-input-vanilla input{
|
||||
border: 0;
|
||||
|
||||
@@ -62,63 +62,4 @@ $ibo-top-bar--toolbar-dashboard-title--max-width: 350px !default;
|
||||
@extend %ibo-full-height-content;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
// Round Toggle
|
||||
/* The switch - the box around the slider */
|
||||
.switch {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 36px;
|
||||
height: 20px;
|
||||
vertical-align: baseline;
|
||||
}
|
||||
|
||||
/* Hide default HTML checkbox */
|
||||
.switch input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* The slider */
|
||||
.slider {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: $ibo-color-secondary-600;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
.slider:before {
|
||||
position: absolute;
|
||||
content: "";
|
||||
height: 15px;
|
||||
width: 15px;
|
||||
left: 3px;
|
||||
bottom: 3px;
|
||||
background-color: $ibo-color-secondary-300;
|
||||
transition: .4s;
|
||||
}
|
||||
|
||||
input:checked + .slider {
|
||||
background-color: $ibo-color-primary-600;
|
||||
}
|
||||
|
||||
input:focus + .slider {
|
||||
box-shadow: 0 0 1px $ibo-color-primary-600;
|
||||
}
|
||||
|
||||
input:checked + .slider:before {
|
||||
transform: translateX(14.5px);
|
||||
}
|
||||
|
||||
/* Rounded sliders */
|
||||
.slider.round {
|
||||
border-radius: 20px;
|
||||
}
|
||||
|
||||
.slider.round:before {
|
||||
border-radius: 7px;
|
||||
}
|
||||
}
|
||||
@@ -83,6 +83,7 @@ $ibo-object-details--header-right--padding-right--is-sticking: $ibo-spacing-300
|
||||
|
||||
.ibo-object-details--status + .ibo-object-details--object-class {
|
||||
margin-left: 0.5rem;
|
||||
display: inline-flex; /* To avoid having spaces around the class name due to the indentation */
|
||||
|
||||
&::before {
|
||||
content: "(";
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
$ibo-object-summary--header--margin-y: $ibo-panel--highlight--height!default;
|
||||
$ibo-object-summary--header--margin-top: $ibo-panel--highlight--height!default;
|
||||
$ibo-object-summary--header--margin-bottom: $ibo-spacing-0!default;
|
||||
$ibo-object-summary--header--margin-x: $ibo-spacing-0 !default;
|
||||
|
||||
$ibo-object-summary--header--padding-y: $ibo-spacing-300 !default;
|
||||
@@ -51,7 +52,7 @@ $ibo-object-summary--content--attributes--code--padding-right: $ibo-spacing-500
|
||||
}
|
||||
|
||||
.ibo-object-summary--header{
|
||||
margin: $ibo-object-summary--header--margin-y $ibo-object-summary--header--margin-x;
|
||||
margin: $ibo-object-summary--header--margin-top $ibo-object-summary--header--margin-x $ibo-object-summary--header--margin-bottom $ibo-object-summary--header--margin-x;
|
||||
padding: $ibo-object-summary--header--padding-y $ibo-object-summary--header--padding-x;
|
||||
background-color: $ibo-object-summary--header--background-color;
|
||||
border-bottom: $ibo-object-summary--header--border;
|
||||
|
||||
@@ -15,4 +15,6 @@
|
||||
@import "global-search";
|
||||
@import "run-query";
|
||||
@import "welcome-popup";
|
||||
@import "oauth.wizard";
|
||||
@import "oauth.wizard";
|
||||
@import "notifications";
|
||||
@import "notifications-center";
|
||||
18
css/backoffice/pages/_notifications-center.scss
Normal file
18
css/backoffice/pages/_notifications-center.scss
Normal file
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
$ibo-input-select--notification-item--mixed-value--color: $ibo-color-primary-800 !default;
|
||||
$ibo-input-select--notification-item--mixed-value--margin-left: 4px !default;
|
||||
|
||||
.ibo-input-select--notification-item {
|
||||
display: flex !important; // override selectize default display with a stronger rule
|
||||
flex-direction: row;
|
||||
@extend .ibo-input-select--autocomplete-item
|
||||
}
|
||||
|
||||
.ibo-input-select--notification-item--mixed-value{
|
||||
font-size: $ibo-font-size-100;
|
||||
color: $ibo-input-select--notification-item--mixed-value--color;
|
||||
margin-left: $ibo-input-select--notification-item--mixed-value--margin-left;
|
||||
}
|
||||
82
css/backoffice/pages/_notifications.scss
Normal file
82
css/backoffice/pages/_notifications.scss
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
$ibo-notifications--view-all--container--grid-gap: $ibo-spacing-600 !default;
|
||||
$ibo-notifications--view-all--container--object-summary--panel--body--max-height: unset !default;
|
||||
|
||||
$ibo-notifications--view-all--item--unread--highlight--background-color: $ibo-color-red-600 !default;
|
||||
$ibo-notifications--view-all--item--read--highlight--background-color: $ibo-color-grey-200 !default;
|
||||
|
||||
$ibo-notifications--view-all--container--large--grid-template-columns: repeat(3, 1fr) !default;
|
||||
$ibo-notifications--view-all--container--medium--grid-template-columns: repeat(2, 1fr) !default;
|
||||
$ibo-notifications--view-all--container--small--grid-template-columns: repeat(1, 1fr) !default;
|
||||
|
||||
$ibo-notifications--view-all--empty--margin-top: $ibo-spacing-950 !default;
|
||||
$ibo-notifications--view-all--empty--svg--max-width: 30% !default;
|
||||
|
||||
.ibo-notifications--view-all--container{
|
||||
display: grid;
|
||||
grid-gap: $ibo-notifications--view-all--container--grid-gap;
|
||||
.ibo-object-summary .ibo-panel--title{
|
||||
font-size: $ibo-font-size-250;
|
||||
}
|
||||
.ibo-object-summary .ibo-panel--toolbar{
|
||||
min-width: 102px;
|
||||
}
|
||||
.ibo-object-summary > .ibo-panel--body{
|
||||
box-shadow: none;
|
||||
max-height: $ibo-notifications--view-all--container--object-summary--panel--body--max-height;
|
||||
}
|
||||
.ibo-object-summary + .ibo-object-summary{
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
@include mobile {
|
||||
grid-template-columns: $ibo-notifications--view-all--container--small--grid-template-columns;
|
||||
}
|
||||
@include desktop {
|
||||
grid-template-columns: $ibo-notifications--view-all--container--medium--grid-template-columns;
|
||||
}
|
||||
@include fullhd {
|
||||
grid-template-columns: $ibo-notifications--view-all--container--large--grid-template-columns; }
|
||||
}
|
||||
.ibo-notifications--view-all--toolbar {
|
||||
justify-content: space-between;
|
||||
}
|
||||
.ibo-notifications--view-all--toggler {
|
||||
display: flex;
|
||||
align-content: center;
|
||||
}
|
||||
|
||||
.ibo-notifications--view-all--item--read .ibo-panel--body::before{
|
||||
background-color: $ibo-notifications--view-all--item--read--highlight--background-color;
|
||||
}
|
||||
.ibo-notifications--view-all--item--unread .ibo-panel--body::before{
|
||||
background-color: $ibo-notifications--view-all--item--unread--highlight--background-color;
|
||||
}
|
||||
|
||||
.ibo-notifications--view-all--container {
|
||||
.ibo-notifications--view-all--read-action, .ibo-notifications--view-all--unread-action {
|
||||
margin-left: 0 !important;
|
||||
}
|
||||
}
|
||||
|
||||
.ibo-notifications--view-all--item--read .ibo-notifications--view-all--read-action {
|
||||
display: none;
|
||||
}
|
||||
.ibo-notifications--view-all--item--unread .ibo-notifications--view-all--unread-action {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.ibo-notifications--view-all--empty {
|
||||
@extend %ibo-fully-centered-content;
|
||||
flex-direction: column;
|
||||
margin-top: $ibo-notifications--view-all--empty--margin-top;
|
||||
|
||||
svg {
|
||||
max-width: $ibo-notifications--view-all--empty--svg--max-width;
|
||||
height: auto;
|
||||
}
|
||||
}
|
||||
@@ -12,6 +12,23 @@ $ibo-has-description--font-size: 0.7em !default; /* Font size is em on purpose a
|
||||
$ibo-is-code--background-color: $ibo-color-white-200 !default;
|
||||
$ibo-is-code--padding: 1.25rem 1.5rem !default;
|
||||
|
||||
$ibo-hyperlink-color: $ibo-color-primary-700 !default;
|
||||
$ibo-hyperlink-text-decoration: none !default;
|
||||
$ibo-hyperlink-color--on-hover: $ibo-color-primary-800 !default;
|
||||
$ibo-hyperlink-text-decoration--on-hover: $ibo-hyperlink-text-decoration !default;
|
||||
$ibo-hyperlink-color--on-active: $ibo-color-primary-900 !default;
|
||||
$ibo-hyperlink-text-decoration--on-active: $ibo-hyperlink-text-decoration !default;
|
||||
|
||||
/* CSS variables */
|
||||
:root{
|
||||
--ibo-hyperlink-color: #{$ibo-hyperlink-color};
|
||||
--ibo-hyperlink-text-decoration: #{$ibo-hyperlink-text-decoration};
|
||||
--ibo-hyperlink-color--on-hover: #{$ibo-hyperlink-color--on-hover};
|
||||
--ibo-hyperlink-text-decoration--on-hover: #{$ibo-hyperlink-text-decoration--on-hover};
|
||||
--ibo-hyperlink-color--on-active: #{$ibo-hyperlink-color--on-active};
|
||||
--ibo-hyperlink-text-decoration--on-active: #{$ibo-hyperlink-text-decoration--on-active};
|
||||
}
|
||||
|
||||
/* Rules */
|
||||
%ibo-text-truncated-with-ellipsis {
|
||||
white-space: nowrap;
|
||||
@@ -32,6 +49,20 @@ $ibo-is-code--padding: 1.25rem 1.5rem !default;
|
||||
color: inherit;
|
||||
}
|
||||
}
|
||||
/* Use this when you want the hyperlink to be of the color of its container's text instead of the global hyperlink color */
|
||||
%ibo-hyperlink-forced-colors {
|
||||
color: $ibo-hyperlink-color;
|
||||
text-decoration: $ibo-hyperlink-text-decoration;
|
||||
|
||||
&:hover {
|
||||
color: $ibo-hyperlink-color--on-hover;
|
||||
text-decoration: $ibo-hyperlink-text-decoration--on-hover;
|
||||
}
|
||||
&:active {
|
||||
color: $ibo-hyperlink-color--on-active;
|
||||
text-decoration: $ibo-hyperlink-text-decoration--on-active;
|
||||
}
|
||||
}
|
||||
|
||||
.ibo-is-broken-hyperlink {
|
||||
text-decoration: line-through;
|
||||
|
||||
@@ -3,4 +3,5 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
@import "highlight";
|
||||
@import "highlight";
|
||||
@import "selectable";
|
||||
40
css/backoffice/utils/mixins/_selectable.scss
Normal file
40
css/backoffice/utils/mixins/_selectable.scss
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
$ibo-selectable--background-color: transparent !default;
|
||||
|
||||
$ibo-selectable--hover--color: $ibo-color-grey-100 !default;
|
||||
$ibo-selectable--hover--background-color: $ibo-color-grey-600 !default;
|
||||
$ibo-selectable--hover--background-opacity: 0.6 !default;
|
||||
|
||||
$ibo-selected--color: $ibo-color-grey-100 !default;
|
||||
$ibo-selected--background-color: $ibo-color-grey-900 !default;
|
||||
$ibo-selected--background-opacity: 0.5 !default;
|
||||
|
||||
$ibo-selected--hover--background-color: $ibo-color-grey-700 !default;
|
||||
$ibo-selected--hover--background-opacity: 0.5 !default;
|
||||
@mixin ibo-selectable {
|
||||
content: ' ';
|
||||
@extend %fa-solid-base;
|
||||
background-color: $ibo-selectable--background-color;
|
||||
cursor: pointer;
|
||||
}
|
||||
@mixin ibo-selectable-hover {
|
||||
@extend %fa-regular-base;
|
||||
content: '\f058';
|
||||
color: $ibo-selectable--hover--color;
|
||||
background-color: transparentize($ibo-selectable--hover--background-color, $ibo-selectable--hover--background-opacity);
|
||||
}
|
||||
|
||||
@mixin ibo-selected {
|
||||
@extend %fa-solid-base;
|
||||
content: '\f058';
|
||||
color: $ibo-selected--color;
|
||||
background-color: transparentize($ibo-selected--background-color, $ibo-selected--background-opacity);
|
||||
}
|
||||
|
||||
@mixin ibo-selected-hover {
|
||||
background-color: transparentize($ibo-selected--hover--background-color, $ibo-selected--hover--background-opacity);
|
||||
}
|
||||
@@ -13,6 +13,7 @@ $ibo-spacing-600: $ibo-size-300 !default;
|
||||
$ibo-spacing-700: $ibo-size-350 !default;
|
||||
$ibo-spacing-800: $ibo-size-400 !default;
|
||||
$ibo-spacing-900: $ibo-size-450 !default;
|
||||
$ibo-spacing-950: $ibo-size-500 !default;
|
||||
|
||||
:root{
|
||||
--ibo-spacing-0: #{$ibo-size-0};
|
||||
|
||||
@@ -15,6 +15,9 @@ $ibo-font-size-400: 2rem !default; /* 24px */
|
||||
$ibo-font-size-450: 2.5rem !default; /* 30px */
|
||||
$ibo-font-size-500: 3rem !default; /* 36px */
|
||||
$ibo-font-size-550: 4rem !default; /* 48px */
|
||||
$ibo-font-size-600: 5rem !default; /* 60px */
|
||||
$ibo-font-size-650: 6rem !default; /* 72px */
|
||||
$ibo-font-size-700: 7rem !default; /* 84px */
|
||||
|
||||
/* Value Common weight name (https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight) */
|
||||
$ibo-font-weight-100: 100 !default; /* 100 Thin (Harline) */
|
||||
|
||||
3
css/backoffice/vendors/_all.scss
vendored
3
css/backoffice/vendors/_all.scss
vendored
@@ -17,4 +17,5 @@
|
||||
@import "jquery-treeview";
|
||||
@import "jquery-blockui";
|
||||
@import "magnific-popup";
|
||||
@import "selectize";
|
||||
@import "selectize";
|
||||
@import "toastify";
|
||||
4
css/backoffice/vendors/_ckeditor.scss
vendored
4
css/backoffice/vendors/_ckeditor.scss
vendored
@@ -22,6 +22,10 @@ $ibo-vendors-ckeditor--autocomplete-item-image--border: 1px solid $ibo-color-gre
|
||||
|
||||
$ibo-vendors-ckeditor--autocomplete-item-title--text-color: #3A3A3A !default;
|
||||
|
||||
.ck-editor__editable_inline:not(.ck-comment__input *) {
|
||||
min-height: 200px;
|
||||
}
|
||||
|
||||
/* Fullscreen button (Combodo custom) */
|
||||
.ibo-vendors-ckeditor--toolbar-fullscreen-button {
|
||||
display: none;
|
||||
|
||||
109
css/backoffice/vendors/_selectize.scss
vendored
109
css/backoffice/vendors/_selectize.scss
vendored
@@ -21,82 +21,87 @@ $ibo-vendors-selectize--item--ignore-partial--background-color: $ibo-color-grey-
|
||||
|
||||
$ibo-vendors-selectize--input-error--border: 1px solid $ibo-color-red-600 !default;
|
||||
|
||||
.selectize-dropdown-content {
|
||||
max-height: unset; /* Overloaded as it will be handled by the _input-select.scss partial */
|
||||
}
|
||||
.selectize-input input{
|
||||
color: $ibo-vendors-selectize-input--color;
|
||||
.selectize-control.single .selectize-input {
|
||||
box-shadow: unset;
|
||||
background-color: unset;
|
||||
background-image: unset;
|
||||
background-repeat: unset;
|
||||
}
|
||||
|
||||
.selectize-input,
|
||||
.selectize-control.single .selectize-input.input-active {
|
||||
background: unset;
|
||||
cursor: text;
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.selectize-control.plugin-combodo_add_button{
|
||||
display: flex;
|
||||
.selectize-control.single .selectize-input.dropdown-active:after {
|
||||
margin-top: unset;
|
||||
border-width: unset;
|
||||
border-color: unset;
|
||||
}
|
||||
.selectize-control.single .selectize-input:after {
|
||||
content: unset;
|
||||
}
|
||||
.selectize-input::after {
|
||||
content: unset;
|
||||
}
|
||||
|
||||
.selectize-add-option {
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
position: absolute;
|
||||
right: $ibo-vendors-selectize-control--plugin-add-button--add-option--right;
|
||||
|
||||
height: $ibo-vendors-selectize-control--plugin-add-button--add-option--height;
|
||||
width: $ibo-vendors-selectize-control--plugin-add-button--add-option--width;
|
||||
z-index: 1;
|
||||
|
||||
color: $ibo-vendors-selectize-control--plugin-add-button--add-option--color;
|
||||
@extend %ibo-font-size-100;
|
||||
.selectize-input>* {
|
||||
display: inline-flex;
|
||||
}
|
||||
|
||||
.selectize-control.single .selectize-input, .selectize-dropdown.single {
|
||||
border-color: $ibo-color-grey-500;
|
||||
}
|
||||
|
||||
.selectize-dropdown {
|
||||
.selected,
|
||||
.active,
|
||||
.active:not(.selected){
|
||||
background: #f5fafd;
|
||||
color: #495c68;
|
||||
}
|
||||
|
||||
[data-selectable],
|
||||
.optgroup-header {
|
||||
padding: 5px 8px;
|
||||
}
|
||||
|
||||
.option {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Simple options renderer
|
||||
|
||||
.simple-option-renderer--container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.simple-option-renderer--container--icon {
|
||||
width: 25px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.simple-option-renderer--container--label {
|
||||
margin-left: 3px;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.selectize-input{
|
||||
.attribute-set-item{
|
||||
>* {
|
||||
// Bulk modification: add / remove / partial items states
|
||||
.selectize-input {
|
||||
.attribute-set-item {
|
||||
> * {
|
||||
display: inline;
|
||||
}
|
||||
&.item-add::before,&.item-remove::before{
|
||||
&.item-add::before,&.item-remove::before {
|
||||
@extend %fa-solid-base;
|
||||
margin-right: $ibo-vendors-selectize--item--icon--margin-right;
|
||||
}
|
||||
&.item-add{
|
||||
&.item-add {
|
||||
background-color: $ibo-vendors-selectize--item--add--background-color !important;
|
||||
&::before{
|
||||
&::before {
|
||||
color: $ibo-vendors-selectize--item--add--icon--color;
|
||||
content: '\f067';
|
||||
}
|
||||
}
|
||||
&.item-remove{
|
||||
&.item-remove {
|
||||
background-color: $ibo-vendors-selectize--item--remove--background-color !important;
|
||||
&::before{
|
||||
&::before {
|
||||
color: $ibo-vendors-selectize--item--remove--icon--color;
|
||||
content: '\f1f8';
|
||||
}
|
||||
}
|
||||
&.item-ignore-partial{
|
||||
&.item-ignore-partial {
|
||||
background-color: $ibo-vendors-selectize--item--ignore-partial--background-color !important;
|
||||
}
|
||||
}
|
||||
&.selectize-input-error{
|
||||
&.selectize-input-error {
|
||||
border: $ibo-vendors-selectize--input-error--border;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
76
css/backoffice/vendors/_toastify.scss
vendored
Normal file
76
css/backoffice/vendors/_toastify.scss
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* @copyright Copyright (C) 2010-2024 Combodo SARL
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/* SCSS variables */
|
||||
|
||||
$ibo-vendors-toastify--right--right: $ibo-spacing-500 !default;
|
||||
$ibo-vendors-toastify--left--left: $ibo-spacing-500 !default;
|
||||
$ibo-vendors-toastify--top--top: -150px !default;
|
||||
$ibo-vendors-toastify--bottom--bottom: -150px !default;
|
||||
|
||||
$ibo-vendors-toastify--close--background: transparent !default;
|
||||
$ibo-vendors-toastify--close--padding: 0 !default;
|
||||
$ibo-vendors-toastify--close--margin-left: $ibo-spacing-300 !default;
|
||||
|
||||
.toastify.on {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.toast-close {
|
||||
background: $ibo-vendors-toastify--close--background;
|
||||
border: 0;
|
||||
color: inherit;
|
||||
cursor: pointer;
|
||||
font-family: inherit;
|
||||
padding: $ibo-vendors-toastify--close--padding;
|
||||
margin-left: $ibo-vendors-toastify--close--margin-left;
|
||||
}
|
||||
|
||||
.toastify-right {
|
||||
right: $ibo-vendors-toastify--right--right;
|
||||
}
|
||||
|
||||
.toastify-left {
|
||||
left: $ibo-vendors-toastify--left--left;
|
||||
}
|
||||
|
||||
.toastify-top {
|
||||
top: $ibo-vendors-toastify--top--top;
|
||||
}
|
||||
|
||||
.toastify-bottom {
|
||||
bottom: $ibo-vendors-toastify--bottom--bottom;
|
||||
}
|
||||
|
||||
.toastify-rounded {
|
||||
border-radius: 25px;
|
||||
}
|
||||
|
||||
.toastify-avatar {
|
||||
width: 1.5em;
|
||||
height: 1.5em;
|
||||
margin: -7px 5px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
.toastify-center {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
left: 0;
|
||||
right: 0;
|
||||
max-width: fit-content;
|
||||
max-width: -moz-fit-content;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 360px) {
|
||||
.toastify-right, .toastify-left {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
left: 0;
|
||||
right: 0;
|
||||
max-width: fit-content;
|
||||
}
|
||||
}
|
||||
|
||||
4
css/c3.min.css
vendored
4
css/c3.min.css
vendored
@@ -1 +1,5 @@
|
||||
/*
|
||||
* @deprecated 3.2.0 N°5621 Moved to NPM
|
||||
*/
|
||||
|
||||
.c3 svg{font:10px sans-serif;-webkit-tap-highlight-color:transparent}.c3 line,.c3 path{fill:none;stroke:#000}.c3 text{-webkit-user-select:none;-moz-user-select:none;user-select:none}.c3-bars path,.c3-event-rect,.c3-legend-item-tile,.c3-xgrid-focus,.c3-ygrid{shape-rendering:crispEdges}.c3-chart-arc path{stroke:#fff}.c3-chart-arc text{fill:#fff;font-size:13px}.c3-grid line{stroke:#aaa}.c3-grid text{fill:#aaa}.c3-xgrid,.c3-ygrid{stroke-dasharray:3 3}.c3-text.c3-empty{fill:gray;font-size:2em}.c3-line{stroke-width:1px}.c3-circle._expanded_{stroke-width:1px;stroke:#fff}.c3-selected-circle{fill:#fff;stroke-width:2px}.c3-bar{stroke-width:0}.c3-bar._expanded_{fill-opacity:.75}.c3-target.c3-focused{opacity:1}.c3-target.c3-focused path.c3-line,.c3-target.c3-focused path.c3-step{stroke-width:2px}.c3-target.c3-defocused{opacity:.3!important}.c3-region{fill:#4682b4;fill-opacity:.1}.c3-brush .extent{fill-opacity:.1}.c3-legend-item{font-size:12px}.c3-legend-item-hidden{opacity:.15}.c3-legend-background{opacity:.75;fill:#fff;stroke:#d3d3d3;stroke-width:1}.c3-title{font:14px sans-serif}.c3-tooltip-container{z-index:10}.c3-tooltip{border-collapse:collapse;border-spacing:0;background-color:#fff;empty-cells:show;-webkit-box-shadow:7px 7px 12px -9px #777;-moz-box-shadow:7px 7px 12px -9px #777;box-shadow:7px 7px 12px -9px #777;opacity:.9}.c3-tooltip tr{border:1px solid #CCC}.c3-tooltip th{background-color:#aaa;font-size:14px;padding:2px 5px;text-align:left;color:#FFF}.c3-tooltip td{font-size:13px;padding:3px 6px;background-color:#fff;border-left:1px dotted #999}.c3-tooltip td>span{display:inline-block;width:10px;height:10px;margin-right:6px}.c3-tooltip td.value{text-align:right}.c3-area{stroke-width:0;opacity:.2}.c3-chart-arcs-title{dominant-baseline:middle;font-size:1.3em}.c3-chart-arcs .c3-chart-arcs-background{fill:#e0e0e0;stroke:none}.c3-chart-arcs .c3-chart-arcs-gauge-unit{fill:#000;font-size:16px}.c3-chart-arcs .c3-chart-arcs-gauge-max,.c3-chart-arcs .c3-chart-arcs-gauge-min{fill:#777}.c3-chart-arc .c3-gauge-value{fill:#000}
|
||||
@@ -3,18 +3,32 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
|
||||
/* These rules should be the same as those in css/backoffice/vendors/ckeditor.css */
|
||||
body{
|
||||
margin: 5px 10px;
|
||||
.ibo-mention-item{
|
||||
line-height: 1.6rem;
|
||||
}
|
||||
.cke_editable{
|
||||
line-height: 1.4;
|
||||
|
||||
[data-role="object-mention"]{
|
||||
color: #0782C1;
|
||||
}
|
||||
figure{
|
||||
border: solid 1px #ccc;
|
||||
border-radius: 2px;
|
||||
}
|
||||
p{
|
||||
margin-top: 0.25em;
|
||||
margin-bottom: 0.25em;
|
||||
[data-role="object-mention"]:hover{
|
||||
color: #2b6bb0;
|
||||
}
|
||||
|
||||
.ck.ck-editor.cke-maximized{
|
||||
position: fixed;
|
||||
left: 0px;
|
||||
top:0px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
z-index: 999;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.ck.ck-editor.cke-maximized .ck.ck-editor__main{
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.ck.ck-editor.cke-maximized .ck-editor__editable_inline:not(.ck-comment__input *){
|
||||
height: 100%;
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
/**
|
||||
* Widgets Factory.
|
||||
*
|
||||
* @package FormSDK
|
||||
* @since 3.2.0
|
||||
*/
|
||||
|
||||
/* debug purpose */
|
||||
.form-type-pictograms{
|
||||
display: inline-block;
|
||||
float: right;
|
||||
margin-left: 5px;
|
||||
color: grey;
|
||||
cursor: pointer;
|
||||
padding: 0px 5px;
|
||||
border-radius: 8px;
|
||||
font-size: 0.9rem;
|
||||
}
|
||||
.form-type-pictograms i{
|
||||
width: 15px;
|
||||
}
|
||||
.complete .form-type-pictograms .pattern:after{
|
||||
content: '\f00c';
|
||||
font-family: "Font Awesome 6 Free";
|
||||
font-weight: 900;
|
||||
background-color: #20b220;
|
||||
border-radius: 50%;
|
||||
font-size: 7px;
|
||||
color: white;
|
||||
position: relative;
|
||||
top: -10px;
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
/* form label */
|
||||
.form-label.required:after{
|
||||
content: '*';
|
||||
color: #e63535;
|
||||
margin-left: 3px;
|
||||
}
|
||||
|
||||
.cke_focus .cke_contents{
|
||||
border: 1px #86b7fe solid;
|
||||
outline: 0;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 0 0 0.25rem rgba(13,110,253,.25);
|
||||
}
|
||||
|
||||
.form_interval_horizontal{
|
||||
display: flex;
|
||||
}
|
||||
.form_interval_horizontal > div{
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.form-compound-fieldset{
|
||||
padding: 8px;
|
||||
border-radius: 10px;
|
||||
border: 1px dashed lightgrey;
|
||||
}
|
||||
|
||||
.form-layout-row{
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
}
|
||||
.form-layout-column{
|
||||
margin: 10px;
|
||||
}
|
||||
.form-layout-column:first-child{
|
||||
margin-left: 0px;
|
||||
}
|
||||
.form-layout-column:last-child{
|
||||
margin-right: 0px;
|
||||
}
|
||||
|
||||
@@ -1,88 +0,0 @@
|
||||
.layout-grow{
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.custom-container{
|
||||
position: relative;
|
||||
border-radius: 10px;
|
||||
padding: 40px 20px 0px;
|
||||
}
|
||||
|
||||
.custom-container:before{
|
||||
content: 'Custom Layout CSS';
|
||||
font-weight: 500;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: -10px;
|
||||
transform: translateX(-50%);
|
||||
/*border: 1px solid #9c21af;*/
|
||||
background-color: white;
|
||||
padding: 5px 15px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.container-flower{
|
||||
background-color: #f3deff;
|
||||
background-size: 500px;
|
||||
background-repeat: no-repeat;
|
||||
background-position-x: right;
|
||||
background-position-y: bottom;
|
||||
background: linear-gradient( to right bottom, rgb(248 242 251) 50%, rgb(241 187 255) );
|
||||
padding-bottom: 200px;
|
||||
}
|
||||
.container-flower fieldset{
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
.container-flower:after{
|
||||
content: '';
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
background-image: url('../../sources/FormImplementation/Resources/6662396.png');
|
||||
background-size: 300px;
|
||||
position: absolute;
|
||||
bottom: 0px;
|
||||
right: 0px;
|
||||
border-radius: 10px;
|
||||
}
|
||||
|
||||
.container-flower .col-form-label{
|
||||
color: #8d63b7;
|
||||
}
|
||||
.container-flower .form-compound-fieldset{
|
||||
border: 1px solid #8d63b7;
|
||||
}
|
||||
|
||||
.container-color{
|
||||
position: relative;
|
||||
border-radius: 10px;
|
||||
background-color: #faf7ff;
|
||||
}
|
||||
|
||||
.container-color .form-compound-fieldset{
|
||||
background-color: #ebe4f6;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.container-color2{
|
||||
position: relative;
|
||||
border-radius: 10px;
|
||||
background-color: #f7f9ff;
|
||||
}
|
||||
|
||||
.container-color2 .form-compound-fieldset{
|
||||
background-color: #e8edf9;
|
||||
border: none;
|
||||
}
|
||||
|
||||
.error-label{
|
||||
color: #d32f2f;
|
||||
}
|
||||
|
||||
.container-color2 .form-compound-fieldset fieldset{
|
||||
border-bottom: 1px dashed #a3adc5;
|
||||
}
|
||||
|
||||
.container-color2 .form-compound-fieldset fieldset:last-child{
|
||||
border-bottom: none;
|
||||
}
|
||||
@@ -16,11 +16,11 @@
|
||||
|
||||
/* Shortened version style */
|
||||
.ui-timepicker-div.ui-timepicker-oneLine { padding-right: 2px; }
|
||||
.ui-timepicker-div.ui-timepicker-oneLine .ui_tpicker_time,
|
||||
.ui-timepicker-div.ui-timepicker-oneLine .ui_tpicker_time,
|
||||
.ui-timepicker-div.ui-timepicker-oneLine dt { display: none; }
|
||||
.ui-timepicker-div.ui-timepicker-oneLine .ui_tpicker_time_label { display: block; padding-top: 2px; }
|
||||
.ui-timepicker-div.ui-timepicker-oneLine dl { text-align: right; }
|
||||
.ui-timepicker-div.ui-timepicker-oneLine dl dd,
|
||||
.ui-timepicker-div.ui-timepicker-oneLine dl dd,
|
||||
.ui-timepicker-div.ui-timepicker-oneLine dl dd > div { display:inline-block; margin:0; }
|
||||
.ui-timepicker-div.ui-timepicker-oneLine dl dd.ui_tpicker_minute:before,
|
||||
.ui-timepicker-div.ui-timepicker-oneLine dl dd.ui_tpicker_second:before { content:':'; display:inline-block; }
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
/**
|
||||
* @deprecated 3.2.0 N°5621 Moved to NPM
|
||||
*/
|
||||
|
||||
/*!
|
||||
* jQuery contextMenu - Plugin for simple contextMenu handling
|
||||
*
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
/*
|
||||
Tabs - additional IE specific bug fixes
|
||||
|
||||
Recommended usage (Conditional Comments):
|
||||
<!--[if lte IE 7]>
|
||||
<link rel="stylesheet" href="tabs_ie.css" type="text/css" media="projection, screen" />
|
||||
<![endif]-->
|
||||
|
||||
*/
|
||||
.tabs-nav { /* auto clear */
|
||||
display: inline-block;
|
||||
}
|
||||
.tabs-nav .tabs-disabled a {
|
||||
filter: alpha(opacity=40);
|
||||
}
|
||||
@@ -1,3 +1,7 @@
|
||||
/*
|
||||
* @deprecated 3.2.0 N°5621 Moved to NPM
|
||||
*/
|
||||
|
||||
/* Magnific Popup CSS */
|
||||
.mfp-bg {
|
||||
top: 0;
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -58,6 +58,9 @@ $progress-bar-error-bg-color: #F56565 !default;
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Animations */
|
||||
@keyframes progress_bar_color_ongoing {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
* @license http://opensource.org/licenses/AGPL-3.0
|
||||
*/
|
||||
Dict::Add('IT IT', 'Italian', 'Italiano', array(
|
||||
'CAS:Error:UserNotAllowed' => 'User not allowed~~',
|
||||
'CAS:Login:SignIn' => 'Sign in with CAS~~',
|
||||
'CAS:Login:SignInTooltip' => 'Click here to authenticate yourself with the CAS server~~',
|
||||
'CAS:Error:UserNotAllowed' => 'Utente non autorizzato',
|
||||
'CAS:Login:SignIn' => 'Accedi con CAS',
|
||||
'CAS:Login:SignInTooltip' => 'Clicca qui per autenticarti con il server CAS',
|
||||
));
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user